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