1 /* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include "js_textdecoder.h" 17 #include <algorithm> 18 #include <codecvt> 19 20 #include <locale> 21 #include <map> 22 #include <string> 23 #include <vector> 24 25 #include "ohos/init_data.h" 26 #include "securec.h" 27 #include "unicode/unistr.h" 28 #include "util_helper.h" 29 #include "tools/log.h" 30 31 namespace OHOS::Util { 32 using namespace Commonlibrary::Platform; 33 TextDecoder(const std::string & buff,std::vector<int> optionVec)34 TextDecoder::TextDecoder(const std::string &buff, std::vector<int> optionVec) 35 : label_(0), encStr_(buff), tranTool_(nullptr, nullptr) 36 { 37 label_ |= optionVec[0] ? static_cast<int32_t>(ConverterFlags::FATAL_FLG) : 0; 38 label_ |= optionVec[1] ? static_cast<int32_t>(ConverterFlags::IGNORE_BOM_FLG) : 0; 39 #if !defined(__ARKUI_CROSS__) 40 SetHwIcuDirectory(); 41 #endif 42 bool fatal = (label_ & static_cast<int32_t>(ConverterFlags::FATAL_FLG)) == 43 static_cast<int32_t>(ConverterFlags::FATAL_FLG); 44 UErrorCode codeflag = U_ZERO_ERROR; 45 UConverter *conv = CreateConverter(encStr_, codeflag); 46 if (U_FAILURE(codeflag)) { 47 HILOG_ERROR("ucnv_open failed !"); 48 return; 49 } 50 if (fatal) { 51 codeflag = U_ZERO_ERROR; 52 ucnv_setToUCallBack(conv, UCNV_TO_U_CALLBACK_STOP, nullptr, nullptr, nullptr, &codeflag); 53 } 54 TransformToolPointer tempTranTool(conv, ConverterClose); 55 tranTool_ = std::move(tempTranTool); 56 } 57 Decode(napi_env env,napi_value src,bool iflag)58 napi_value TextDecoder::Decode(napi_env env, napi_value src, bool iflag) 59 { 60 uint8_t flags = 0; 61 flags |= (iflag ? 0 : static_cast<uint8_t>(ConverterFlags::FLUSH_FLG)); 62 UBool flush = ((flags & static_cast<uint8_t>(ConverterFlags::FLUSH_FLG))) == 63 static_cast<uint8_t>(ConverterFlags::FLUSH_FLG); 64 napi_typedarray_type type; 65 size_t length = 0; 66 void *data = nullptr; 67 size_t byteOffset = 0; 68 napi_value arrayBuffer = nullptr; 69 NAPI_CALL(env, napi_get_typedarray_info(env, src, &type, &length, &data, &arrayBuffer, &byteOffset)); 70 const char *source = ReplaceNull(data, length); 71 size_t limit = GetMinByteSize() * length; 72 size_t len = limit * sizeof(UChar); 73 UChar *arr = nullptr; 74 if (limit > 0) { 75 arr = new (std::nothrow) UChar[limit + 1]; 76 if (arr == nullptr) { 77 HILOG_ERROR("decode arr is nullptr"); 78 return nullptr; 79 } 80 if (memset_s(arr, len + sizeof(UChar), 0, len + sizeof(UChar)) != EOK) { 81 HILOG_ERROR("decode arr memset_s failed"); 82 FreedMemory(arr); 83 return nullptr; 84 } 85 } else { 86 HILOG_DEBUG("limit is error"); 87 return nullptr; 88 } 89 UChar *target = arr; 90 size_t tarStartPos = reinterpret_cast<uintptr_t>(arr); 91 UErrorCode codeFlag = U_ZERO_ERROR; 92 ucnv_toUnicode(GetConverterPtr(), &target, target + len, &source, source + length, nullptr, flush, &codeFlag); 93 if (codeFlag != U_ZERO_ERROR) { 94 return ThrowError(env, "TextDecoder decoding error."); 95 } 96 size_t resultLength = 0; 97 bool omitInitialBom = false; 98 DecodeArr decArr(target, tarStartPos, limit); 99 SetBomFlag(arr, codeFlag, decArr, resultLength, omitInitialBom); 100 UChar *arrDat = arr; 101 if (omitInitialBom && resultLength > 0) { 102 arrDat = &arr[2]; // 2: Obtains the 2 value of the array. 103 } 104 std::string tepStr = ConvertToString(arrDat, length); 105 napi_value resultStr = nullptr; 106 NAPI_CALL(env, napi_create_string_utf8(env, tepStr.c_str(), tepStr.size(), &resultStr)); 107 FreedMemory(arr); 108 if (flush) { 109 label_ &= static_cast<int32_t>(ConverterFlags::BOM_SEEN_FLG); 110 Reset(); 111 } 112 return resultStr; 113 } 114 DecodeToString(napi_env env,napi_value src,bool iflag)115 napi_value TextDecoder::DecodeToString(napi_env env, napi_value src, bool iflag) 116 { 117 uint8_t flags = 0; 118 flags |= (iflag ? 0 : static_cast<uint8_t>(ConverterFlags::FLUSH_FLG)); 119 UBool flush = (flags & static_cast<uint8_t>(ConverterFlags::FLUSH_FLG)) == 120 static_cast<uint8_t>(ConverterFlags::FLUSH_FLG); 121 napi_typedarray_type type; 122 size_t length = 0; 123 void *data = nullptr; 124 size_t byteOffset = 0; 125 napi_value arrayBuffer = nullptr; 126 napi_get_typedarray_info(env, src, &type, &length, &data, &arrayBuffer, &byteOffset); 127 const char *source = static_cast<char *>(data); 128 size_t limit = GetMinByteSize() * length; 129 size_t len = limit * sizeof(UChar); 130 UChar *arr = nullptr; 131 if (limit > 0) { 132 arr = new (std::nothrow) UChar[limit + 1]{0}; 133 if (arr == nullptr) { 134 HILOG_DEBUG("arr is nullptr"); 135 return nullptr; 136 } 137 } else { 138 HILOG_DEBUG("limit is error"); 139 return nullptr; 140 } 141 UChar *target = arr; 142 UErrorCode codeFlag = U_ZERO_ERROR; 143 ucnv_toUnicode(GetConverterPtr(), &target, target + len, &source, source + length, nullptr, flush, &codeFlag); 144 if (codeFlag != U_ZERO_ERROR) { 145 FreedMemory(arr); 146 napi_throw_error(env, "401", 147 "Parameter error. Please check if the decode data matches the encoding format."); 148 return nullptr; 149 } 150 size_t resultLen = target - arr; 151 bool omitInitialBom = false; 152 SetIgnoreBOM(arr, resultLen, omitInitialBom); 153 UChar *arrDat = arr; 154 if (omitInitialBom) { 155 arrDat = &arr[1]; 156 resultLen--; 157 } 158 napi_value resultStr = nullptr; 159 napi_create_string_utf16(env, reinterpret_cast<char16_t *>(arrDat), resultLen, &resultStr); 160 FreedMemory(arr); 161 if (flush) { 162 label_ &= ~static_cast<int32_t>(ConverterFlags::BOM_SEEN_FLG); 163 Reset(); 164 } 165 return resultStr; 166 } 167 GetEncoding(napi_env env) const168 napi_value TextDecoder::GetEncoding(napi_env env) const 169 { 170 size_t length = encStr_.length(); 171 napi_value result = nullptr; 172 NAPI_CALL(env, napi_create_string_utf8(env, encStr_.c_str(), length, &result)); 173 return result; 174 } 175 GetFatal(napi_env env) const176 napi_value TextDecoder::GetFatal(napi_env env) const 177 { 178 int32_t temp = label_ & static_cast<int32_t>(ConverterFlags::FATAL_FLG); 179 bool comRst = false; 180 if (temp == static_cast<int32_t>(ConverterFlags::FATAL_FLG)) { 181 comRst = true; 182 } else { 183 comRst = false; 184 } 185 napi_value result = nullptr; 186 NAPI_CALL(env, napi_get_boolean(env, comRst, &result)); 187 return result; 188 } 189 GetIgnoreBOM(napi_env env) const190 napi_value TextDecoder::GetIgnoreBOM(napi_env env) const 191 { 192 int32_t temp = label_ & static_cast<int32_t>(ConverterFlags::IGNORE_BOM_FLG); 193 bool comRst = false; 194 if (temp == static_cast<int32_t>(ConverterFlags::IGNORE_BOM_FLG)) { 195 comRst = true; 196 } else { 197 comRst = false; 198 } 199 napi_value result; 200 NAPI_CALL(env, napi_get_boolean(env, comRst, &result)); 201 return result; 202 } 203 GetMinByteSize() const204 size_t TextDecoder::GetMinByteSize() const 205 { 206 if (tranTool_ == nullptr) { 207 return 0; 208 } 209 size_t res = static_cast<size_t>(ucnv_getMinCharSize(tranTool_.get())); 210 return res; 211 } 212 Reset() const213 void TextDecoder::Reset() const 214 { 215 if (tranTool_ == nullptr) { 216 return; 217 } 218 ucnv_reset(tranTool_.get()); 219 } 220 FreedMemory(UChar * & pData)221 void TextDecoder::FreedMemory(UChar *&pData) 222 { 223 if (pData != nullptr) { 224 delete[] pData; 225 pData = nullptr; 226 } 227 } 228 SetBomFlag(const UChar * arr,const UErrorCode codeFlag,const DecodeArr decArr,size_t & rstLen,bool & bomFlag)229 void TextDecoder::SetBomFlag(const UChar *arr, const UErrorCode codeFlag, const DecodeArr decArr, 230 size_t &rstLen, bool &bomFlag) 231 { 232 if (arr == nullptr) { 233 return; 234 } 235 if (U_SUCCESS(codeFlag)) { 236 if (decArr.limitLen > 0) { 237 rstLen = reinterpret_cast<uintptr_t>(decArr.target) - decArr.tarStartPos; 238 if (rstLen > 0 && IsUnicode() && !IsIgnoreBom() && !IsBomFlag()) { 239 bomFlag = (arr[0] == 0xFEFF) ? true : false; 240 label_ |= static_cast<int32_t>(ConverterFlags::BOM_SEEN_FLG); 241 } 242 } 243 } 244 } 245 SetIgnoreBOM(const UChar * arr,size_t resultLen,bool & bomFlag)246 void TextDecoder::SetIgnoreBOM(const UChar *arr, size_t resultLen, bool &bomFlag) 247 { 248 switch (ucnv_getType(GetConverterPtr())) { 249 case UCNV_UTF8: 250 case UCNV_UTF16_BigEndian: 251 case UCNV_UTF16_LittleEndian: 252 label_ |= static_cast<int32_t>(ConverterFlags::UNICODE_FLG); 253 break; 254 default: 255 break; 256 } 257 if (resultLen > 0 && IsUnicode() && IsIgnoreBom()) { 258 bomFlag = (arr[0] == 0xFEFF) ? true : false; 259 } 260 label_ |= static_cast<int32_t>(ConverterFlags::BOM_SEEN_FLG); 261 } 262 ThrowError(napi_env env,const char * errMessage)263 napi_value TextDecoder::ThrowError(napi_env env, const char* errMessage) 264 { 265 napi_value utilError = nullptr; 266 napi_value code = nullptr; 267 uint32_t errCode = 10200019; 268 napi_create_uint32(env, errCode, &code); 269 napi_value name = nullptr; 270 std::string errName = "BusinessError"; 271 napi_value msg = nullptr; 272 napi_create_string_utf8(env, errMessage, NAPI_AUTO_LENGTH, &msg); 273 napi_create_string_utf8(env, errName.c_str(), NAPI_AUTO_LENGTH, &name); 274 napi_create_error(env, nullptr, msg, &utilError); 275 napi_set_named_property(env, utilError, "code", code); 276 napi_set_named_property(env, utilError, "name", name); 277 napi_throw(env, utilError); 278 napi_value res = nullptr; 279 NAPI_CALL(env, napi_get_undefined(env, &res)); 280 return res; 281 } 282 ReplaceNull(void * data,size_t length) const283 const char* TextDecoder::ReplaceNull(void *data, size_t length) const 284 { 285 char *str = static_cast<char*>(data); 286 if (encStr_ == "utf-8") { 287 for (size_t i = 0; i < length; ++i) { 288 if (str[i] == '\0') { 289 str[i] = ' '; 290 } 291 } 292 } 293 return const_cast<const char*>(str); 294 } 295 } 296