/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ECMASCRIPT_STUBS_RUNTIME_OPTIMIZED_STUBS_INL_H #define ECMASCRIPT_STUBS_RUNTIME_OPTIMIZED_STUBS_INL_H #include "ecmascript/stubs/runtime_stubs.h" #include "ecmascript/ecma_string-inl.h" namespace panda::ecmascript { template uint16_t RuntimeStubs::GetCodeUnit(Span &sp, int32_t index, int32_t length) { if ((index < 0) || (index >= length)) { return 0; } return sp[index]; } template JSTaggedValue RuntimeStubs::DecodePercentEncoding(JSThread *thread, int32_t &n, int32_t &k, const JSHandle &str, uint8_t &bb, std::vector &oct, Span &sp, int32_t strLen) { CString errorMsg; int32_t j = 1; while (j < n) { k++; uint16_t codeUnit = GetCodeUnit(sp, k, strLen); // b. If the code unit at index k within string is not "%", throw a URIError exception. // c. If the code units at index (k +1) and (k + 2) within string do not represent hexadecimal // digits, throw a URIError exception. if (!(codeUnit == '%')) { errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); } uint16_t frontChart = GetCodeUnit(sp, k + 1, strLen); uint16_t behindChart = GetCodeUnit(sp, k + 2, strLen); // 2: means plus 2 if (!(base::utf_helper::IsHexDigits(frontChart) && base::utf_helper::IsHexDigits(behindChart))) { errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); } bb = GetValueFromTwoHex(frontChart, behindChart); // e. If the two most significant bits in B are not 10, throw a URIError exception. if (!((bb & base::utf_helper::BIT_MASK_2) == base::utf_helper::BIT_MASK_1)) { errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); } k += 2; // 2: means plus 2 oct.push_back(bb); j++; } return JSTaggedValue::True(); } JSTaggedValue RuntimeStubs::UTF16EncodeCodePoint(JSThread *thread, const std::vector &oct, const JSHandle &str, std::u16string &sStr) { if (!base::utf_helper::IsValidUTF8(oct)) { CString errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); } uint32_t vv = base::StringHelper::Utf8ToU32String(oct); if (vv < base::utf_helper::DECODE_SECOND_FACTOR) { sStr = base::StringHelper::Utf16ToU16String(reinterpret_cast(&vv), 1); } else { uint16_t lv = (((vv - base::utf_helper::DECODE_SECOND_FACTOR) & base::utf_helper::BIT16_MASK) + base::utf_helper::DECODE_TRAIL_LOW); // NOLINT uint16_t hv = ((((vv - base::utf_helper::DECODE_SECOND_FACTOR) >> 10U) & base::utf_helper::BIT16_MASK) + base::utf_helper::DECODE_LEAD_LOW); // 10: means shift left by 10 digits sStr = base::StringHelper::Append(base::StringHelper::Utf16ToU16String(&hv, 1), base::StringHelper::Utf16ToU16String(&lv, 1)); } return JSTaggedValue::True(); } template JSTaggedValue RuntimeStubs::DecodePercentEncoding(JSThread *thread, const JSHandle &str, int32_t &k, int32_t strLen, std::u16string &sStr, Span &sp) { [[maybe_unused]] uint32_t start = static_cast(k); CString errorMsg; // ii. If k + 2 is greater than or equal to strLen, throw a URIError exception. // iii. If the code units at index (k+1) and (k + 2) within string do not represent hexadecimal digits, // throw a URIError exception. if ((k + 2) >= strLen) { // 2: means plus 2 errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); } uint16_t frontChar = GetCodeUnit(sp, k + 1, strLen); uint16_t behindChar = GetCodeUnit(sp, k + 2, strLen); // 2: means plus 2 if (!(base::utf_helper::IsHexDigits(frontChar) && base::utf_helper::IsHexDigits(behindChar))) { errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); } uint8_t bb = GetValueFromTwoHex(frontChar, behindChar); k += 2; // 2: means plus 2 if ((bb & base::utf_helper::BIT_MASK_1) == 0) { sStr = base::StringHelper::Utf8ToU16String(&bb, 1); } else { // vii. Else the most significant bit in B is 1, // 1. Let n be the smallest nonnegative integer such that (B << n) & 0x80 is equal to 0. // 3. Let Octets be an array of 8-bit integers of size n. // 4. Put B into Octets at index 0. // 6. Let j be 1. // 7. Repeat, while j < n // a. Increase k by 1. // d. Let B be the 8-bit value represented by the two hexadecimal digits at // index (k + 1) and (k + 2). // f. Increase k by 2. // g. Put B into Octets at index j. // h. Increase j by 1. // 9. If V < 0x10000, then // a. Let C be the code unit V. // b. If C is not in reservedSet, then // i. Let S be the String containing only the code unit C. // c. Else C is in reservedSet, // i. Let S be the substring of string from index start to index k inclusive. // 10. Else V ≥ 0x10000, // a. Let L be (((V – 0x10000) & 0x3FF) + 0xDC00). // b. Let H be ((((V – 0x10000) >> 10) & 0x3FF) + 0xD800). // c. Let S be the String containing the two code units H and L. int32_t n = 0; while ((((static_cast(bb) << static_cast(n)) & base::utf_helper::BIT_MASK_1) != 0)) { n++; if (n > 4) { // 4 : 4 means less than 4 break; } } // 2. If n equals 1 or n is greater than 4, throw a URIError exception. if ((n == 1) || (n > 4)) { errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); } std::vector oct = {bb}; // 5. If k + (3 × (n – 1)) is greater than or equal to strLen, throw a URIError exception. if (k + (3 * (n - 1)) >= strLen) { // 3: means multiply by 3 errorMsg = "DecodeURI: invalid character: " + ConvertToString(str.GetTaggedValue()); THROW_URI_ERROR_AND_RETURN(thread, errorMsg.c_str(), JSTaggedValue::Exception()); } DecodePercentEncoding(thread, n, k, str, bb, oct, sp, strLen); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); UTF16EncodeCodePoint(thread, oct, str, sStr); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } return JSTaggedValue::True(); } template JSTaggedValue RuntimeStubs::RuntimeDecodeURIComponent(JSThread *thread, const JSHandle &string, const T *data) { // 1. Let strLen be the number of code units in string. CString errorMsg; auto stringAcc = EcmaStringAccessor(string); int32_t strLen = static_cast(stringAcc.GetLength()); // 2. Let R be the empty String. ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); std::u16string resStr; std::vector tmpVec; tmpVec.resize(strLen); if (LIKELY(strLen != 0)) { if (memcpy_s(tmpVec.data(), sizeof(T) * strLen, data, sizeof(T) * strLen) != EOK) { LOG_FULL(FATAL) << "memcpy_s failed"; UNREACHABLE(); } } Span sp(tmpVec.data(), strLen); // 3. Let k be 0. // 4. Repeat int32_t k = 0; while (true) { if (k == strLen) { // a. If k equals strLen, return R. auto *uint16tData = reinterpret_cast(resStr.data()); uint32_t resSize = resStr.size(); return factory->NewFromUtf16Literal(uint16tData, resSize).GetTaggedValue(); } // b. Let C be the code unit at index k within string. // c. If C is not "%", then // i. Let S be the String containing only the code unit C. // d. Else C is "%", // i. Let start be k. // iv. Let B be the 8-bit value represented by the two hexadecimal digits at index (k + 1) and (k + 2). // v. Increase k by 2. // vi. If the most significant bit in B is 0, then // 1. Let C be the code unit with code unit value B. // 2. If C is not in reservedSet, then // a. Let S be the String containing only the code unit C. // 3. Else C is in reservedSet, // a. Let S be the substring of string from index start to index k inclusive. uint16_t cc = GetCodeUnit(sp, k, strLen); std::u16string sStr; if (cc != '%') { if (cc == 0 && strLen == 1) { JSHandle tmpEcmaString = factory->NewFromUtf16Literal(&cc, 1); return tmpEcmaString.GetTaggedValue(); } sStr = base::StringHelper::Utf16ToU16String(&cc, 1); } else { DecodePercentEncoding(thread, string, k, strLen, sStr, sp); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } resStr += sStr; k++; } } uint8_t RuntimeStubs::GetValueFromTwoHex(uint8_t front, uint8_t behind) { std::string hexString("0123456789ABCDEF"); size_t idxf = base::StringHelper::FindFromU8ToUpper(hexString, &front); size_t idxb = base::StringHelper::FindFromU8ToUpper(hexString, &behind); uint8_t res = ((idxf << 4U) | idxb) & base::utf_helper::BIT_MASK_FF; // NOLINT 4: means shift left by 4 digits return res; } } // namespace panda::ecmascript #endif // ECMASCRIPT_STUBS_RUNTIME_OPTIMIZED_STUBS_INL_H