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 18 #include "ohos/init_data.h" 19 #include "securec.h" 20 #include "util_helper.h" 21 22 namespace OHOS::Util { 23 using namespace Commonlibrary::Platform; 24 TextDecoder(const std::string & buff,int32_t flags)25 TextDecoder::TextDecoder(const std::string &buff, int32_t flags) 26 : encStr_(buff), tranTool_(nullptr, nullptr) 27 { 28 label_ |= flags; 29 #if !defined(__ARKUI_CROSS__) 30 SetHwIcuDirectory(); 31 #endif 32 bool fatal = (flags & static_cast<int32_t>(ConverterFlags::FATAL_FLG)) == 33 static_cast<int32_t>(ConverterFlags::FATAL_FLG); 34 UErrorCode codeflag = U_ZERO_ERROR; 35 UConverter *conv = CreateConverter(encStr_, codeflag); 36 if (U_FAILURE(codeflag)) { 37 HILOG_ERROR("TextDecoder:: ucnv_open failed !"); 38 return; 39 } 40 if (fatal) { 41 codeflag = U_ZERO_ERROR; 42 ucnv_setToUCallBack(conv, UCNV_TO_U_CALLBACK_STOP, nullptr, nullptr, nullptr, &codeflag); 43 } 44 TransformToolPointer tempTranTool(conv, ConverterClose); 45 tranTool_ = std::move(tempTranTool); 46 } 47 48 //static CanBeCompressed(const uint16_t * utf16Data,uint32_t utf16Len)49 bool TextDecoder::CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len) 50 { 51 uint32_t index = 0; 52 for (; index + 4 <= utf16Len; index += 4) { // 4: process the data in chunks of 4 elements to improve speed 53 // Check if all four characters in the current block are ASCII characters 54 if (!IsASCIICharacter(utf16Data[index]) || 55 !IsASCIICharacter(utf16Data[index + 1]) || // 1: the second element of the block 56 !IsASCIICharacter(utf16Data[index + 2]) || // 2: the third element of the block 57 !IsASCIICharacter(utf16Data[index + 3])) { // 3: the fourth element of the block 58 return false; 59 } 60 } 61 // Check remaining characters if they are ASCII 62 for (; index < utf16Len; ++index) { 63 if (!IsASCIICharacter(utf16Data[index])) { 64 return false; 65 } 66 } 67 return true; 68 } 69 ConvertToChar(UChar * uchar,size_t length,char * tempCharArray)70 std::pair<char *, bool> TextDecoder::ConvertToChar(UChar *uchar, size_t length, char *tempCharArray) 71 { 72 uint16_t *uint16Data = reinterpret_cast<uint16_t *>(uchar); 73 if (CanBeCompressed(uint16Data, length)) { 74 if (length <= 0) { 75 HILOG_ERROR("TextDecoder:: length is error"); 76 return std::make_pair(nullptr, false); 77 } 78 char *strUtf8; 79 if (length <= TEMP_CHAR_LENGTH) { 80 strUtf8 = tempCharArray; 81 } else { 82 strUtf8 = new (std::nothrow) char[length]; 83 if (strUtf8 == nullptr) { 84 HILOG_ERROR("TextDecoder:: memory allocation failed, strUtf8 is nullptr"); 85 return std::make_pair(nullptr, false); 86 } 87 } 88 for (size_t i = 0; i < length; ++i) { 89 strUtf8[i] = static_cast<char>(uchar[i]); 90 } 91 return std::make_pair(strUtf8, true); 92 } 93 return std::make_pair(nullptr, false); 94 } 95 Decode(napi_env env,napi_value src,bool iflag)96 napi_value TextDecoder::Decode(napi_env env, napi_value src, bool iflag) 97 { 98 uint8_t flags = 0; 99 flags |= (iflag ? 0 : static_cast<uint8_t>(ConverterFlags::FLUSH_FLG)); 100 UBool flush = ((flags & static_cast<uint8_t>(ConverterFlags::FLUSH_FLG))) == 101 static_cast<uint8_t>(ConverterFlags::FLUSH_FLG); 102 napi_typedarray_type type; 103 size_t length = 0; 104 void *data = nullptr; 105 size_t byteOffset = 0; 106 napi_value arrayBuffer = nullptr; 107 NAPI_CALL(env, napi_get_typedarray_info(env, src, &type, &length, &data, &arrayBuffer, &byteOffset)); 108 const char *source = ReplaceNull(data, length); 109 size_t limit = GetMinByteSize() * length; 110 size_t len = limit * sizeof(UChar); 111 UChar *arr = nullptr; 112 if (limit > 0) { 113 arr = new (std::nothrow) UChar[limit + 1]; 114 if (arr == nullptr) { 115 HILOG_ERROR("TextDecoder:: memory allocation failed, decode arr is nullptr"); 116 return nullptr; 117 } 118 if (memset_s(arr, len + sizeof(UChar), 0, len + sizeof(UChar)) != EOK) { 119 HILOG_ERROR("TextDecoder:: decode arr memset_s failed"); 120 FreedMemory(arr); 121 return nullptr; 122 } 123 } else { 124 HILOG_DEBUG("TextDecoder:: limit is error"); 125 return nullptr; 126 } 127 UChar *target = arr; 128 size_t tarStartPos = reinterpret_cast<uintptr_t>(arr); 129 UErrorCode codeFlag = U_ZERO_ERROR; 130 ucnv_toUnicode(GetConverterPtr(), &target, target + len, &source, source + length, nullptr, flush, &codeFlag); 131 if (codeFlag != U_ZERO_ERROR) { 132 return ThrowError(env, "TextDecoder decoding error."); 133 } 134 size_t resultLength = 0; 135 bool omitInitialBom = false; 136 DecodeArr decArr(target, tarStartPos, limit); 137 SetBomFlag(arr, codeFlag, decArr, resultLength, omitInitialBom); 138 UChar *arrDat = arr; 139 if (omitInitialBom && resultLength > 0) { 140 arrDat = &arr[2]; // 2: Obtains the 2 value of the array. 141 } 142 std::string tepStr = ConvertToString(arrDat, length); 143 napi_value resultStr = nullptr; 144 NAPI_CALL(env, napi_create_string_utf8(env, tepStr.c_str(), tepStr.size(), &resultStr)); 145 FreedMemory(arr); 146 if (flush) { 147 label_ &= static_cast<int32_t>(ConverterFlags::BOM_SEEN_FLG); 148 Reset(); 149 } 150 return resultStr; 151 } 152 GetResultStr(napi_env env,UChar * arrDat,size_t length)153 napi_value TextDecoder::GetResultStr(napi_env env, UChar *arrDat, 154 size_t length) 155 { 156 napi_value resultStr = nullptr; 157 if (length <= TEMP_CHAR_LENGTH) { 158 char tempCharArray[TEMP_CHAR_LENGTH]; 159 std::pair<char *, bool> tempPair = ConvertToChar(arrDat, length, tempCharArray); 160 if (tempPair.second == true) { 161 char *utf8Str = tempPair.first; 162 napi_create_string_utf8(env, utf8Str, length, &resultStr); 163 } else { 164 napi_create_string_utf16(env, reinterpret_cast<char16_t *>(arrDat), length, &resultStr); 165 } 166 } else { 167 std::pair<char *, bool> tempPair = ConvertToChar(arrDat, length, nullptr); 168 if (tempPair.second == true) { 169 char *utf8Str = tempPair.first; 170 napi_create_string_utf8(env, utf8Str, length, &resultStr); 171 NAPI_ASSERT(env, utf8Str != nullptr, "Data allocation failed"); 172 delete[] utf8Str; 173 } else { 174 napi_create_string_utf16(env, reinterpret_cast<char16_t *>(arrDat), length, &resultStr); 175 } 176 } 177 return resultStr; 178 } 179 DecodeToString(napi_env env,napi_value src,bool iflag)180 napi_value TextDecoder::DecodeToString(napi_env env, 181 napi_value src, bool iflag) 182 { 183 uint8_t flags = 0; 184 flags |= (iflag ? 0 : static_cast<uint8_t>(ConverterFlags::FLUSH_FLG)); 185 UBool flush = (flags & static_cast<uint8_t>(ConverterFlags::FLUSH_FLG)) == 186 static_cast<uint8_t>(ConverterFlags::FLUSH_FLG); 187 napi_typedarray_type type; 188 size_t length = 0; 189 void *data = nullptr; 190 size_t byteOffset = 0; 191 napi_value arrayBuffer = nullptr; 192 napi_get_typedarray_info(env, src, &type, &length, &data, &arrayBuffer, &byteOffset); 193 const char *source = static_cast<char *>(data); 194 size_t limit = GetMinByteSize() * length; 195 size_t len = limit * sizeof(UChar); 196 UChar *arr = nullptr; 197 if (limit > 0) { 198 arr = new (std::nothrow) UChar[limit + 1]{0}; 199 if (arr == nullptr) { 200 HILOG_ERROR("TextDecoder:: memory allocation failed, arr is nullptr"); 201 return nullptr; 202 } 203 } else { 204 HILOG_DEBUG("TextDecoder:: limit is error"); 205 return nullptr; 206 } 207 UChar *target = arr; 208 UErrorCode codeFlag = U_ZERO_ERROR; 209 ucnv_toUnicode(GetConverterPtr(), &target, target + len, &source, source + length, nullptr, flush, &codeFlag); 210 if (codeFlag != U_ZERO_ERROR) { 211 FreedMemory(arr); 212 napi_throw_error(env, "401", 213 "Parameter error. Please check if the decode data matches the encoding format."); 214 return nullptr; 215 } 216 size_t resultLen = target - arr; 217 bool omitInitialBom = false; 218 SetIgnoreBOM(arr, resultLen, omitInitialBom); 219 UChar *arrDat = arr; 220 if (omitInitialBom) { 221 arrDat = &arr[1]; 222 resultLen--; 223 } 224 napi_value resultStr = GetResultStr(env, arrDat, resultLen); 225 FreedMemory(arr); 226 if (flush) { 227 label_ &= ~static_cast<int32_t>(ConverterFlags::BOM_SEEN_FLG); 228 Reset(); 229 } 230 return resultStr; 231 } 232 GetMinByteSize() const233 size_t TextDecoder::GetMinByteSize() const 234 { 235 if (tranTool_ == nullptr) { 236 return 0; 237 } 238 size_t res = static_cast<size_t>(ucnv_getMinCharSize(tranTool_.get())); 239 return res; 240 } 241 Reset() const242 void TextDecoder::Reset() const 243 { 244 if (tranTool_ == nullptr) { 245 return; 246 } 247 ucnv_reset(tranTool_.get()); 248 } 249 FreedMemory(UChar * & pData)250 void TextDecoder::FreedMemory(UChar *&pData) 251 { 252 if (pData != nullptr) { 253 delete[] pData; 254 pData = nullptr; 255 } 256 } 257 SetBomFlag(const UChar * arr,const UErrorCode codeFlag,const DecodeArr decArr,size_t & rstLen,bool & bomFlag)258 void TextDecoder::SetBomFlag(const UChar *arr, const UErrorCode codeFlag, const DecodeArr decArr, 259 size_t &rstLen, bool &bomFlag) 260 { 261 if (arr == nullptr) { 262 return; 263 } 264 if (U_SUCCESS(codeFlag)) { 265 if (decArr.limitLen > 0) { 266 rstLen = reinterpret_cast<uintptr_t>(decArr.target) - decArr.tarStartPos; 267 if (rstLen > 0 && IsUnicode() && !IsIgnoreBom() && !IsBomFlag()) { 268 bomFlag = (arr[0] == 0xFEFF) ? true : false; 269 label_ |= static_cast<int32_t>(ConverterFlags::BOM_SEEN_FLG); 270 } 271 } 272 } 273 } 274 SetIgnoreBOM(const UChar * arr,size_t resultLen,bool & bomFlag)275 void TextDecoder::SetIgnoreBOM(const UChar *arr, size_t resultLen, bool &bomFlag) 276 { 277 switch (ucnv_getType(GetConverterPtr())) { 278 case UCNV_UTF8: 279 case UCNV_UTF16_BigEndian: 280 case UCNV_UTF16_LittleEndian: 281 label_ |= static_cast<int32_t>(ConverterFlags::UNICODE_FLG); 282 break; 283 default: 284 break; 285 } 286 if (resultLen > 0 && IsUnicode() && IsIgnoreBom()) { 287 bomFlag = (arr[0] == 0xFEFF) ? true : false; 288 } 289 label_ |= static_cast<int32_t>(ConverterFlags::BOM_SEEN_FLG); 290 } 291 ThrowError(napi_env env,const char * errMessage)292 napi_value TextDecoder::ThrowError(napi_env env, const char* errMessage) 293 { 294 napi_value utilError = nullptr; 295 napi_value code = nullptr; 296 uint32_t errCode = 10200019; 297 napi_create_uint32(env, errCode, &code); 298 napi_value name = nullptr; 299 std::string errName = "BusinessError"; 300 napi_value msg = nullptr; 301 napi_create_string_utf8(env, errMessage, NAPI_AUTO_LENGTH, &msg); 302 napi_create_string_utf8(env, errName.c_str(), NAPI_AUTO_LENGTH, &name); 303 napi_create_error(env, nullptr, msg, &utilError); 304 napi_set_named_property(env, utilError, "code", code); 305 napi_set_named_property(env, utilError, "name", name); 306 napi_throw(env, utilError); 307 napi_value res = nullptr; 308 NAPI_CALL(env, napi_get_undefined(env, &res)); 309 return res; 310 } 311 ReplaceNull(void * data,size_t length) const312 const char* TextDecoder::ReplaceNull(void *data, size_t length) const 313 { 314 char *str = static_cast<char*>(data); 315 if (encStr_ == "utf-8") { 316 for (size_t i = 0; i < length; ++i) { 317 if (str[i] == '\0') { 318 str[i] = ' '; 319 } 320 } 321 } 322 return const_cast<const char*>(str); 323 } 324 } 325