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