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 "utils/log.h" 29 namespace OHOS::Util { TextDecoder(const std::string & buff,std::vector<int> optionVec)30 TextDecoder::TextDecoder(const std::string &buff, std::vector<int> optionVec) 31 : label_(0), encStr_(buff), tranTool_(nullptr, nullptr) 32 { 33 uint32_t i32Flag = 0; 34 if (optionVec.size() == 2) { // 2:Meaning of optionVec size 2 35 if (optionVec[0] >= 0 && optionVec[1] >= 0) { 36 i32Flag |= optionVec[0] ? static_cast<uint32_t>(ConverterFlags::FATAL_FLG) : 0; 37 i32Flag |= optionVec[1] ? static_cast<uint32_t>(ConverterFlags::IGNORE_BOM_FLG) : 0; 38 } else if (optionVec[0] >= 0 && optionVec[1] < 0) { 39 i32Flag |= optionVec[0] ? static_cast<uint32_t>(ConverterFlags::FATAL_FLG) : 0; 40 } else if (optionVec[0] < 0 && optionVec[1] >= 0) { 41 i32Flag |= optionVec[1] ? static_cast<uint32_t>(ConverterFlags::IGNORE_BOM_FLG) : 0; 42 } 43 } 44 label_ = i32Flag; 45 SetHwIcuDirectory(); 46 bool fatal = (i32Flag & static_cast<uint32_t>(ConverterFlags::FATAL_FLG)) == 47 static_cast<uint32_t>(ConverterFlags::FATAL_FLG); 48 UErrorCode codeflag = U_ZERO_ERROR; 49 UConverter *conv = ucnv_open(encStr_.c_str(), &codeflag); 50 if (U_FAILURE(codeflag)) { 51 HILOG_ERROR("ucnv_open failed !"); 52 return; 53 } 54 if (fatal) { 55 codeflag = U_ZERO_ERROR; 56 ucnv_setToUCallBack(conv, UCNV_TO_U_CALLBACK_STOP, nullptr, nullptr, nullptr, &codeflag); 57 } 58 TransformToolPointer tempTranTool(conv, ConverterClose); 59 tranTool_ = std::move(tempTranTool); 60 } 61 62 Decode(napi_env env,napi_value src,bool iflag)63 napi_value TextDecoder::Decode(napi_env env, napi_value src, bool iflag) 64 { 65 uint8_t flags = 0; 66 flags |= (iflag ? 0 : static_cast<uint8_t>(ConverterFlags::FLUSH_FLG)); 67 UBool flush = ((flags & static_cast<uint8_t>(ConverterFlags::FLUSH_FLG))) == 68 static_cast<uint8_t>(ConverterFlags::FLUSH_FLG); 69 napi_typedarray_type type; 70 size_t length = 0; 71 void *data1 = nullptr; 72 size_t byteOffset = 0; 73 napi_value arrayBuffer = nullptr; 74 NAPI_CALL(env, napi_get_typedarray_info(env, src, &type, &length, &data1, &arrayBuffer, &byteOffset)); 75 const char *source = static_cast<char*>(data1); 76 UErrorCode codeFlag = U_ZERO_ERROR; 77 size_t limit = GetMinByteSize() * length; 78 size_t len = limit * sizeof(UChar); 79 UChar *arr = nullptr; 80 if (limit > 0) { 81 arr = new UChar[limit + 1]; 82 if (memset_s(arr, len + sizeof(UChar), 0, len + sizeof(UChar)) != EOK) { 83 HILOG_ERROR("decode arr memset_s failed"); 84 FreedMemory(arr); 85 return nullptr; 86 } 87 } else { 88 HILOG_ERROR("limit is error"); 89 return nullptr; 90 } 91 UChar *target = arr; 92 size_t tarStartPos = reinterpret_cast<uintptr_t>(arr); 93 ucnv_toUnicode(GetConverterPtr(), &target, target + len, &source, source + length, nullptr, flush, &codeFlag); 94 size_t resultLength = 0; 95 bool omitInitialBom = false; 96 DecodeArr decArr(target, tarStartPos, limit); 97 SetBomFlag(arr, codeFlag, decArr, resultLength, omitInitialBom); 98 UChar *arrDat = arr; 99 if (omitInitialBom && resultLength > 0) { 100 arrDat = &arr[2]; // 2: Obtains the 2 value of the array. 101 } 102 std::u16string tempStr16(arrDat); 103 std::string tepStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.to_bytes(tempStr16); 104 napi_value resultStr = nullptr; 105 NAPI_CALL(env, napi_create_string_utf8(env, tepStr.c_str(), tepStr.size(), &resultStr)); 106 FreedMemory(arr); 107 if (flush) { 108 label_ &= static_cast<uint32_t>(ConverterFlags::BOM_SEEN_FLG); 109 Reset(); 110 } 111 return resultStr; 112 } 113 GetEncoding(napi_env env) const114 napi_value TextDecoder::GetEncoding(napi_env env) const 115 { 116 size_t length = strlen(encStr_.c_str()); 117 napi_value result = nullptr; 118 NAPI_CALL(env, napi_create_string_utf8(env, encStr_.c_str(), length, &result)); 119 return result; 120 } 121 GetFatal(napi_env env) const122 napi_value TextDecoder::GetFatal(napi_env env) const 123 { 124 uint32_t temp = label_ & static_cast<uint32_t>(ConverterFlags::FATAL_FLG); 125 bool comRst = false; 126 if (temp == static_cast<uint32_t>(ConverterFlags::FATAL_FLG)) { 127 comRst = true; 128 } else { 129 comRst = false; 130 } 131 napi_value result = nullptr; 132 NAPI_CALL(env, napi_get_boolean(env, comRst, &result)); 133 return result; 134 } 135 GetIgnoreBOM(napi_env env) const136 napi_value TextDecoder::GetIgnoreBOM(napi_env env) const 137 { 138 uint32_t temp = label_ & static_cast<uint32_t>(ConverterFlags::IGNORE_BOM_FLG); 139 bool comRst = false; 140 if (temp == static_cast<uint32_t>(ConverterFlags::IGNORE_BOM_FLG)) { 141 comRst = true; 142 } else { 143 comRst = false; 144 } 145 napi_value result; 146 NAPI_CALL(env, napi_get_boolean(env, comRst, &result)); 147 return result; 148 } 149 GetMinByteSize() const150 size_t TextDecoder::GetMinByteSize() const 151 { 152 if (tranTool_ == nullptr) { 153 return 0; 154 } 155 size_t res = static_cast<size_t>(ucnv_getMinCharSize(tranTool_.get())); 156 return res; 157 } 158 Reset() const159 void TextDecoder::Reset() const 160 { 161 if (tranTool_ == nullptr) { 162 return; 163 } 164 ucnv_reset(tranTool_.get()); 165 } 166 FreedMemory(UChar * pData)167 void TextDecoder::FreedMemory(UChar *pData) 168 { 169 if (pData != nullptr) { 170 delete[] pData; 171 pData = nullptr; 172 } 173 } 174 SetBomFlag(const UChar * arr,const UErrorCode codeFlag,const DecodeArr decArr,size_t & rstLen,bool & bomFlag)175 void TextDecoder::SetBomFlag(const UChar *arr, const UErrorCode codeFlag, const DecodeArr decArr, 176 size_t &rstLen, bool &bomFlag) 177 { 178 if (arr == nullptr) { 179 return; 180 } 181 if (U_SUCCESS(codeFlag)) { 182 if (decArr.limitLen > 0) { 183 rstLen = reinterpret_cast<uintptr_t>(decArr.target) - decArr.tarStartPos; 184 if (rstLen > 0 && IsUnicode() && !IsIgnoreBom() && !IsBomFlag()) { 185 bomFlag = (arr[0] == 0xFEFF) ? true : false; 186 label_ |= static_cast<uint32_t>(ConverterFlags::BOM_SEEN_FLG); 187 } 188 } 189 } 190 } 191 } 192