1/* 2 * Copyright (c) 2024 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#ifndef ECMASCRIPT_STUBS_RUNTIME_OPTIMIZED_STUBS_INL_H 17#define ECMASCRIPT_STUBS_RUNTIME_OPTIMIZED_STUBS_INL_H 18 19#include "ecmascript/stubs/runtime_stubs.h" 20#include "ecmascript/ecma_string-inl.h" 21 22namespace panda::ecmascript { 23template <typename T> 24uint16_t RuntimeStubs::GetCodeUnit(Span<T> &sp, int32_t index, int32_t length) 25{ 26 if ((index < 0) || (index >= length)) { 27 return 0; 28 } 29 return sp[index]; 30} 31 32template <typename T> 33JSTaggedValue RuntimeStubs::DecodePercentEncoding(JSThread *thread, int32_t &n, int32_t &k, 34 const JSHandle<EcmaString> &str, uint8_t &bb, 35 std::vector<uint8_t> &oct, Span<T> &sp, int32_t strLen) 36{ 37 CString errorMsg; 38 int32_t j = 1; 39 while (j < n) { 40 k++; 41 uint16_t codeUnit = GetCodeUnit<T>(sp, k, strLen); 42 // b. If the code unit at index k within string is not "%", throw a URIError exception. 43 // c. If the code units at index (k +1) and (k + 2) within string do not represent hexadecimal 44 // digits, throw a URIError exception. 45 if (!(codeUnit == '%')) { 46 errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); 47 THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); 48 } 49 50 uint16_t frontChart = GetCodeUnit<T>(sp, k + 1, strLen); 51 uint16_t behindChart = GetCodeUnit<T>(sp, k + 2, strLen); // 2: means plus 2 52 if (!(base::utf_helper::IsHexDigits(frontChart) && base::utf_helper::IsHexDigits(behindChart))) { 53 errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); 54 THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); 55 } 56 bb = GetValueFromTwoHex(frontChart, behindChart); 57 // e. If the two most significant bits in B are not 10, throw a URIError exception. 58 if (!((bb & base::utf_helper::BIT_MASK_2) == base::utf_helper::BIT_MASK_1)) { 59 errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); 60 THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); 61 } 62 k += 2; // 2: means plus 2 63 oct.push_back(bb); 64 j++; 65 } 66 return JSTaggedValue::True(); 67} 68 69JSTaggedValue RuntimeStubs::UTF16EncodeCodePoint(JSThread *thread, const std::vector<uint8_t> &oct, 70 const JSHandle<EcmaString> &str, std::u16string &sStr) 71{ 72 if (!base::utf_helper::IsValidUTF8(oct)) { 73 CString errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); 74 THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); 75 } 76 uint32_t vv = base::StringHelper::Utf8ToU32String(oct); 77 if (vv < base::utf_helper::DECODE_SECOND_FACTOR) { 78 sStr = base::StringHelper::Utf16ToU16String(reinterpret_cast<uint16_t *>(&vv), 1); 79 } else { 80 uint16_t lv = (((vv - base::utf_helper::DECODE_SECOND_FACTOR) & base::utf_helper::BIT16_MASK) + 81 base::utf_helper::DECODE_TRAIL_LOW); 82 // NOLINT 83 uint16_t hv = ((((vv - base::utf_helper::DECODE_SECOND_FACTOR) >> 10U) & base::utf_helper::BIT16_MASK) + 84 base::utf_helper::DECODE_LEAD_LOW); // 10: means shift left by 10 digits 85 sStr = base::StringHelper::Append(base::StringHelper::Utf16ToU16String(&hv, 1), 86 base::StringHelper::Utf16ToU16String(&lv, 1)); 87 } 88 return JSTaggedValue::True(); 89} 90 91template <typename T> 92JSTaggedValue RuntimeStubs::DecodePercentEncoding(JSThread *thread, const JSHandle<EcmaString> &str, int32_t &k, 93 int32_t strLen, std::u16string &sStr, Span<T> &sp) 94{ 95 [[maybe_unused]] uint32_t start = static_cast<uint32_t>(k); 96 CString errorMsg; 97 // ii. If k + 2 is greater than or equal to strLen, throw a URIError exception. 98 // iii. If the code units at index (k+1) and (k + 2) within string do not represent hexadecimal digits, 99 // throw a URIError exception. 100 if ((k + 2) >= strLen) { // 2: means plus 2 101 errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); 102 THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); 103 } 104 uint16_t frontChar = GetCodeUnit<T>(sp, k + 1, strLen); 105 uint16_t behindChar = GetCodeUnit<T>(sp, k + 2, strLen); // 2: means plus 2 106 if (!(base::utf_helper::IsHexDigits(frontChar) && base::utf_helper::IsHexDigits(behindChar))) { 107 errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); 108 THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); 109 } 110 uint8_t bb = GetValueFromTwoHex(frontChar, behindChar); 111 k += 2; // 2: means plus 2 112 if ((bb & base::utf_helper::BIT_MASK_1) == 0) { 113 sStr = base::StringHelper::Utf8ToU16String(&bb, 1); 114 } else { 115 // vii. Else the most significant bit in B is 1, 116 // 1. Let n be the smallest nonnegative integer such that (B << n) & 0x80 is equal to 0. 117 // 3. Let Octets be an array of 8-bit integers of size n. 118 // 4. Put B into Octets at index 0. 119 // 6. Let j be 1. 120 // 7. Repeat, while j < n 121 // a. Increase k by 1. 122 // d. Let B be the 8-bit value represented by the two hexadecimal digits at 123 // index (k + 1) and (k + 2). 124 // f. Increase k by 2. 125 // g. Put B into Octets at index j. 126 // h. Increase j by 1. 127 // 9. If V < 0x10000, then 128 // a. Let C be the code unit V. 129 // b. If C is not in reservedSet, then 130 // i. Let S be the String containing only the code unit C. 131 // c. Else C is in reservedSet, 132 // i. Let S be the substring of string from index start to index k inclusive. 133 // 10. Else V ≥ 0x10000, 134 // a. Let L be (((V – 0x10000) & 0x3FF) + 0xDC00). 135 // b. Let H be ((((V – 0x10000) >> 10) & 0x3FF) + 0xD800). 136 // c. Let S be the String containing the two code units H and L. 137 int32_t n = 0; 138 while ((((static_cast<uint32_t>(bb) << static_cast<uint32_t>(n)) & base::utf_helper::BIT_MASK_1) != 0)) { 139 n++; 140 if (n > 4) { // 4 : 4 means less than 4 141 break; 142 } 143 } 144 // 2. If n equals 1 or n is greater than 4, throw a URIError exception. 145 if ((n == 1) || (n > 4)) { 146 errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); 147 THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); 148 } 149 150 std::vector<uint8_t> oct = {bb}; 151 152 // 5. If k + (3 × (n – 1)) is greater than or equal to strLen, throw a URIError exception. 153 if (k + (3 * (n - 1)) >= strLen) { // 3: means multiply by 3 154 errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); 155 THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); 156 } 157 DecodePercentEncoding<T>(thread, n, k, str, bb, oct, sp, strLen); 158 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 159 UTF16EncodeCodePoint(thread, oct, str, sStr); 160 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 161 } 162 return JSTaggedValue::True(); 163} 164 165template <typename T> 166JSTaggedValue RuntimeStubs::RuntimeDecodeURIComponent(JSThread *thread, const JSHandle<EcmaString> &string, 167 const T *data) 168{ 169 // 1. Let strLen be the number of code units in string. 170 CString errorMsg; 171 auto stringAcc = EcmaStringAccessor(string); 172 int32_t strLen = static_cast<int32_t>(stringAcc.GetLength()); 173 // 2. Let R be the empty String. 174 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 175 std::u16string resStr; 176 std::vector<T> tmpVec; 177 tmpVec.resize(strLen); 178 if (LIKELY(strLen != 0)) { 179 if (memcpy_s(tmpVec.data(), sizeof(T) * strLen, data, sizeof(T) * strLen) != EOK) { 180 LOG_FULL(FATAL) << "memcpy_s failed"; 181 UNREACHABLE(); 182 } 183 } 184 Span<T> sp(tmpVec.data(), strLen); 185 // 3. Let k be 0. 186 // 4. Repeat 187 int32_t k = 0; 188 while (true) { 189 if (k == strLen) { 190 // a. If k equals strLen, return R. 191 auto *uint16tData = reinterpret_cast<uint16_t *>(resStr.data()); 192 uint32_t resSize = resStr.size(); 193 return factory->NewFromUtf16Literal(uint16tData, resSize).GetTaggedValue(); 194 } 195 196 // b. Let C be the code unit at index k within string. 197 // c. If C is not "%", then 198 // i. Let S be the String containing only the code unit C. 199 // d. Else C is "%", 200 // i. Let start be k. 201 // iv. Let B be the 8-bit value represented by the two hexadecimal digits at index (k + 1) and (k + 2). 202 // v. Increase k by 2. 203 // vi. If the most significant bit in B is 0, then 204 // 1. Let C be the code unit with code unit value B. 205 // 2. If C is not in reservedSet, then 206 // a. Let S be the String containing only the code unit C. 207 // 3. Else C is in reservedSet, 208 // a. Let S be the substring of string from index start to index k inclusive. 209 uint16_t cc = GetCodeUnit<T>(sp, k, strLen); 210 std::u16string sStr; 211 if (cc != '%') { 212 if (cc == 0 && strLen == 1) { 213 JSHandle<EcmaString> tmpEcmaString = factory->NewFromUtf16Literal(&cc, 1); 214 return tmpEcmaString.GetTaggedValue(); 215 } 216 sStr = base::StringHelper::Utf16ToU16String(&cc, 1); 217 } else { 218 DecodePercentEncoding<T>(thread, string, k, strLen, sStr, sp); 219 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 220 } 221 resStr += sStr; 222 k++; 223 } 224} 225 226uint8_t RuntimeStubs::GetValueFromTwoHex(uint8_t front, uint8_t behind) 227{ 228 std::string hexString("0123456789ABCDEF"); 229 size_t idxf = base::StringHelper::FindFromU8ToUpper(hexString, &front); 230 size_t idxb = base::StringHelper::FindFromU8ToUpper(hexString, &behind); 231 232 uint8_t res = ((idxf << 4U) | idxb) & base::utf_helper::BIT_MASK_FF; // NOLINT 4: means shift left by 4 digits 233 return res; 234} 235} // namespace panda::ecmascript 236#endif // ECMASCRIPT_STUBS_RUNTIME_OPTIMIZED_STUBS_INL_H