• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "ecmascript/js_api/js_api_buffer.h"
17 #include <cstring>
18 #include <cstdint>
19 #include <cstring>
20 #include <string_view>
21 
22 #include "ecmascript/base/typed_array_helper-inl.h"
23 #include "ecmascript/base/typed_array_helper.h"
24 #include "ecmascript/byte_array.h"
25 #include "ecmascript/ecma_string-inl.h"
26 #include "ecmascript/ecma_string.h"
27 #include "ecmascript/ecma_vm.h"
28 #include "ecmascript/js_array.h"
29 #include "ecmascript/js_arraybuffer.h"
30 #include "ecmascript/js_dataview.h"
31 #include "ecmascript/js_handle.h"
32 #include "ecmascript/js_hclass.h"
33 #include "ecmascript/js_object.h"
34 #include "ecmascript/js_tagged_number.h"
35 #include "ecmascript/js_tagged_value.h"
36 #include "ecmascript/js_typed_array.h"
37 #include "ecmascript/object_factory.h"
38 #include "jsnapi_expo.h"
39 #include "macros.h"
40 
41 namespace panda::ecmascript {
42 using ContainerError = containers::ContainerError;
43 using string = std::string;
44 using string_view = std::string_view;
45 using ErrorFlag = containers::ErrorFlag;
46 using ElementSize = base::ElementSize;
47 using EncodingType = JSAPIFastBuffer::EncodingType;
48 using TypedArrayHelper = base::TypedArrayHelper;
49 using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
50 using u16string = std::u16string;
51 
52 namespace {
53 const std::map<string, EncodingType> ENCODING_MAP = {
54     {"hex", EncodingType::HEX},         {"base64url", EncodingType::BASE64URL}, {"base64", EncodingType::BASE64},
55     {"ascii", EncodingType::ASCII},     {"latin1", EncodingType::LATIN1},       {"binary", EncodingType::BINARY},
56     {"ucs2", EncodingType::UTF16LE},    {"ucs-2", EncodingType::UTF16LE},       {"utf-16le", EncodingType::UTF16LE},
57     {"utf16le", EncodingType::UTF16LE}, {"utf-8", EncodingType::UTF8},          {"utf8", EncodingType::UTF8},
58 };
59 }  // namespace
60 
61 const uint8_t BASE64_TABLE[256] = {
62     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
63     -1, -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
64     -1, -1, -1, -1, -1, -1, -1, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
65     22, 23, 24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
66     45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
67     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
68     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
69     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
70     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
71 
RangeChecker(uint32_t rangeLeft,uint32_t rangeRight,uint32_t l,uint32_t r)72 inline bool RangeChecker(uint32_t rangeLeft, uint32_t rangeRight, uint32_t l, uint32_t r)
73 {
74     return l <= r && l <= rangeRight && r >= rangeLeft;
75 }
76 
IsBase64Char(unsigned char c)77 bool IsBase64Char(unsigned char c)
78 {
79     return (isalnum(c) || (c == '+') || (c == '/') || (c == '-') || (c == '_'));
80 }
81 
GetEncodingType(string encode)82 EncodingType JSAPIFastBuffer::GetEncodingType(string encode)
83 {
84     if (ENCODING_MAP.find(encode) != ENCODING_MAP.end()) {
85         return ENCODING_MAP.at(encode);
86     }
87     return EncodingType::INVALID;
88 }
89 
GetEncodingType(JSThread * thread,const JSHandle<JSTaggedValue> & encode)90 EncodingType JSAPIFastBuffer::GetEncodingType(JSThread *thread, const JSHandle<JSTaggedValue> &encode)
91 {
92     auto strAccessor = EcmaStringAccessor(JSHandle<EcmaString>(encode));
93     auto str = strAccessor.ToStdString(thread);
94     return GetEncodingType(str);
95 }
96 
GetUInt8ArrayFromBufferObject(JSThread * thread,JSTaggedValue buffer)97 JSTypedArray *GetUInt8ArrayFromBufferObject(JSThread *thread, JSTaggedValue buffer)
98 {
99     if (buffer.IsJSUint8Array()) {
100         return JSTypedArray::Cast(buffer.GetTaggedObject());
101     }
102     ASSERT(buffer.IsJSAPIBuffer());
103     return JSTypedArray::Cast(
104         JSAPIFastBuffer::Cast(buffer.GetTaggedObject())->GetFastBufferData(thread).GetTaggedObject());
105 }
106 
GetUInt8ArrayFromBufferObject(JSThread * thread,JSHandle<JSTaggedValue> buffer)107 JSTypedArray *GetUInt8ArrayFromBufferObject(JSThread *thread, JSHandle<JSTaggedValue> buffer)
108 {
109     return GetUInt8ArrayFromBufferObject(thread, buffer.GetTaggedValue());
110 }
111 
GetUnderlyingData(JSThread * thread,JSTypedArray * array,uint32_t offset)112 uint8_t *GetUnderlyingData(JSThread *thread, JSTypedArray *array, uint32_t offset)
113 {
114     if (array->GetByteLength() <= offset) {
115         return nullptr;
116     }
117     JSTaggedValue arrayBuffer = array->GetViewedArrayBufferOrByteArray(thread);
118     if (BuiltinsArrayBuffer::IsDetachedBuffer(thread, arrayBuffer)) {
119         return nullptr;
120     }
121     auto res =
122         reinterpret_cast<uint8_t *>(builtins::BuiltinsArrayBuffer::GetDataPointFromBuffer(thread, arrayBuffer, offset));
123     return res;
124 }
125 
GetUnderlyingData(JSThread * thread,JSTaggedValue obj,uint32_t offset=0)126 uint8_t *GetUnderlyingData(JSThread *thread, JSTaggedValue obj, uint32_t offset = 0)
127 {
128     if (obj.IsJSAPIBuffer()) {
129         JSAPIFastBuffer *buffer = JSAPIFastBuffer::Cast(obj.GetTaggedObject());
130         if (buffer->GetLength() <= offset) {
131             return nullptr;
132         }
133         offset += buffer->GetOffset();
134     }
135     JSTypedArray *array = GetUInt8ArrayFromBufferObject(thread, obj);
136     return GetUnderlyingData(thread, array, offset);
137 }
138 
GetValueInt32(JSHandle<JSTaggedValue> valueHandle)139 int32_t GetValueInt32(JSHandle<JSTaggedValue> valueHandle)
140 {
141     JSTaggedValue value = valueHandle.GetTaggedValue();
142     if (UNLIKELY(value.IsDouble())) {
143         return static_cast<int32_t>(
144             ecmascript::base::NumberHelper::DoubleToInt(value.GetDouble(), ecmascript::base::INT32_BITS));
145     }
146     return value.GetInt();
147 }
148 
GetValueUInt32(JSHandle<JSTaggedValue> valueHandle)149 uint32_t GetValueUInt32(JSHandle<JSTaggedValue> valueHandle)
150 {
151     return static_cast<uint32_t>(GetValueInt32(valueHandle));
152 }
153 
FromStringUtf8(JSThread * thread,const JSHandle<JSTaggedValue> & str)154 string FromStringUtf8(JSThread *thread, const JSHandle<JSTaggedValue> &str)
155 {
156     auto strAccessor = EcmaStringAccessor(JSHandle<EcmaString>(str));
157     auto res = strAccessor.ToStdString(thread);
158     return res;
159 }
160 
FromStringUtf16(JSThread * thread,const JSHandle<JSTaggedValue> & str,string & stringDecoded)161 string_view FromStringUtf16(JSThread *thread, const JSHandle<JSTaggedValue> &str, string &stringDecoded)
162 {
163     auto strAccessor = EcmaStringAccessor(JSHandle<EcmaString>(str));
164     auto u16string = StringConverter::Utf8ToUtf16BE(strAccessor.ToStdString(thread));
165     stringDecoded = StringConverter::Utf16StrToStr(u16string);
166     return string_view(stringDecoded);
167 }
168 
FromStringASCII(JSThread * thread,const JSHandle<JSTaggedValue> & str,string & stringDecoded)169 string_view FromStringASCII(JSThread *thread, const JSHandle<JSTaggedValue> &str, string &stringDecoded)
170 {
171     auto strAccessor = EcmaStringAccessor(JSHandle<EcmaString>(str));
172     uint32_t length = strAccessor.GetLength();
173     stringDecoded.reserve(length);
174     stringDecoded.resize(length);
175     strAccessor.WriteToOneByte(thread, reinterpret_cast<uint8_t *>(stringDecoded.data()), length);
176     return string_view(stringDecoded);
177 }
178 
FromStringBase64(JSThread * thread,const JSHandle<JSTaggedValue> & str,string & stringDecoded)179 string_view FromStringBase64(JSThread *thread, const JSHandle<JSTaggedValue> &str, string &stringDecoded)
180 {
181     auto strAccessor = EcmaStringAccessor(JSHandle<EcmaString>(str));
182     CVector<uint8_t> buf;
183     Span<const uint8_t> sp = strAccessor.ToUtf8Span(thread, buf);
184     StringConverter::Base64Decode(string_view(reinterpret_cast<const char *>(sp.data()), sp.size()), stringDecoded);
185     return std::string_view(stringDecoded);
186 }
187 
ConvertEcmaStringToStdString(JSThread * thread,const JSHandle<JSTaggedValue> & str)188 std::string ConvertEcmaStringToStdString(JSThread *thread, const JSHandle<JSTaggedValue> &str)
189 {
190     ASSERT(str->IsString());
191     auto strAccessor = EcmaStringAccessor(JSHandle<EcmaString>(str));
192     return strAccessor.ToStdString(thread);
193 }
194 
NewUint8Array(JSThread * thread,uint32_t length)195 JSHandle<JSTypedArray> JSAPIFastBuffer::NewUint8Array(JSThread *thread, uint32_t length)
196 {
197     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
198     JSHandle<JSTaggedValue> handleTagValFunc = env->GetUint8ArrayFunction();
199     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
200     JSHandle<JSObject> obj =
201         factory->NewJSObjectByConstructor(JSHandle<JSFunction>(handleTagValFunc), handleTagValFunc);
202     DataViewType arrayType = DataViewType::UINT8;
203     JSTypedArray::Cast(*obj)->SetTypedArrayName(thread, thread->GlobalConstants()->GetUint8ArrayString());
204     TypedArrayHelper::AllocateTypedArrayBuffer(thread, obj, length, arrayType);
205     return JSHandle<JSTypedArray>(obj);
206 }
207 
Copy(JSThread * thread,const JSHandle<JSTaggedValue> & dst,const JSHandle<JSTaggedValue> & src,uint32_t tStart,uint32_t sStart,uint32_t sEnd)208 JSTaggedValue JSAPIFastBuffer::Copy(JSThread *thread, const JSHandle<JSTaggedValue> &dst,
209                                     const JSHandle<JSTaggedValue> &src, uint32_t tStart, uint32_t sStart, uint32_t sEnd)
210 {
211     ASSERT(tStart >= 0 && sStart >= 0 && sStart <= sEnd);
212     uint32_t copyLength = sEnd - sStart;
213     JSTypedArray *dstArray = GetUInt8ArrayFromBufferObject(thread, dst);
214     uint32_t dstLength = dst->IsJSAPIBuffer() ? JSHandle<JSAPIFastBuffer>(dst)->GetLength() : dstArray->GetByteLength();
215     if (dstLength <= tStart) {
216         return JSTaggedValue(0);
217     }
218     copyLength = std::min(copyLength, dstLength - tStart);
219     uint8_t *srcData = GetUnderlyingData(thread, src.GetTaggedValue(), sStart);
220     uint8_t *dstData = GetUnderlyingData(thread, dst.GetTaggedValue(), tStart);
221     if (srcData == nullptr || dstData == nullptr) {
222         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::ARRAY_BUFFER_IS_NULL_OR_DETACHED,
223                                                             "The underlying ArrayBuffer is null or detached.");
224         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
225     }
226     WriteBytes(thread, srcData, copyLength, dstData);
227     return JSTaggedValue(copyLength);
228 }
229 
CreateBufferFromArrayLike(JSThread * thread,const JSHandle<JSAPIFastBuffer> & buffer,const JSHandle<JSTaggedValue> & obj)230 JSTaggedValue JSAPIFastBuffer::CreateBufferFromArrayLike(JSThread *thread, const JSHandle<JSAPIFastBuffer> &buffer,
231                                                          const JSHandle<JSTaggedValue> &obj)
232 {
233     if (!obj->IsECMAObject()) {
234         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR,
235                                                             "CreateBufferFromArrayLike must accept object.");
236         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
237     }
238     JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
239     JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, obj, lengthKeyHandle).GetValue();
240     JSTaggedNumber number = JSTaggedValue::ToLength(thread, value);
241     if (number.GetNumber() > JSObject::MAX_ELEMENT_INDEX) {
242         JSTaggedValue error =
243             ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "len is bigger than 2^32 - 1.");
244         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
245     }
246     uint32_t len = number.ToUint32();
247     auto fastBufferData = NewUint8Array(thread, len);
248     buffer->SetFastBufferData(thread, fastBufferData);
249     buffer->SetLength(len);
250     for (uint32_t i = 0; i < len; i++) {
251         JSTaggedValue next = JSTaggedValue::GetProperty(thread, obj, i).GetValue().GetTaggedValue();
252         if (!next.IsInt()) {
253             JSTaggedValue error =
254                 ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, "value in arraylike must be a integer.");
255             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
256         }
257         buffer->SetValueByIndex(thread, i, JSTaggedValue(static_cast<uint8_t>(next.GetInt())), JSType::JS_UINT8_ARRAY);
258     }
259     return buffer.GetTaggedValue();
260 }
261 
FromArrayBuffer(JSThread * thread,const JSHandle<JSAPIFastBuffer> & buffer,const JSHandle<JSTaggedValue> & src,uint32_t byteOffset,uint32_t length)262 JSTaggedValue JSAPIFastBuffer::FromArrayBuffer(JSThread *thread, const JSHandle<JSAPIFastBuffer> &buffer,
263                                                const JSHandle<JSTaggedValue> &src, uint32_t byteOffset, uint32_t length)
264 {
265     if (BuiltinsArrayBuffer::IsDetachedBuffer(thread, src.GetTaggedValue())) {
266         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::ARRAY_BUFFER_IS_NULL_OR_DETACHED,
267                                                             "The underlying ArrayBuffer is null or detached.");
268         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
269     }
270     auto srcBuffer = JSHandle<JSArrayBuffer>(src);
271     uint32_t srcLength = srcBuffer->GetArrayBufferByteLength();
272     if (srcLength <= byteOffset) {
273         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR,
274                                                             "byteOffset must less than length.");
275         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
276     }
277     auto len = std::min(length, srcLength);
278     auto array = NewUint8Array(thread, len);
279     array->SetViewedArrayBufferOrByteArray(thread, srcBuffer);
280     array->SetByteLength(len);
281     array->SetArrayLength(len);
282     buffer->SetFastBufferData(thread, array);
283     buffer->SetLength(len);
284     buffer->SetOffset(byteOffset);
285     return buffer.GetTaggedValue();
286 }
287 
FromStringHex(JSThread * thread,const JSHandle<JSTaggedValue> & str,string & stringDecoded)288 string_view FromStringHex(JSThread *thread, const JSHandle<JSTaggedValue> &str, string &stringDecoded)
289 {
290     auto strAccessor = EcmaStringAccessor(JSHandle<EcmaString>(str));
291     auto hexStr = strAccessor.ToStdString(thread);
292     StringConverter::HexDecode(hexStr, stringDecoded);
293     return std::string_view(stringDecoded);
294 }
295 
IsOneByte(uint8_t u8Char)296 bool IsOneByte(uint8_t u8Char)
297 {
298     return (u8Char & 0x80) == 0;
299 }
300 
Utf8ToUtf16BEToData(const unsigned char * data,u16string & u16Str,string::size_type & index,uint8_t & c1)301 void StringConverter::Utf8ToUtf16BEToData(const unsigned char *data, u16string &u16Str, string::size_type &index,
302                                           uint8_t &c1)
303 {
304     uint8_t c2 = data[++index];  // The second byte
305     uint8_t c3 = data[++index];  // The third byte
306     uint8_t c4 = data[++index];  // The forth byte
307     // Calculate the UNICODE code point value (3 bits lower for the first byte, 6
308     // bits for the other) 3 : shift left 3 times of UTF8_VALID_BITS
309     uint32_t codePoint = ((c1 & LOWER_3_BITS_MASK) << (3 * UTF8_VALID_BITS)) |
310                          // 2 : shift left 2 times of UTF8_VALID_BITS
311                          ((c2 & LOWER_6_BITS_MASK) << (2 * UTF8_VALID_BITS)) |
312                          ((c3 & LOWER_6_BITS_MASK) << UTF8_VALID_BITS) | (c4 & LOWER_6_BITS_MASK);
313     // In UTF-16, U+10000 to U+10FFFF represent surrogate pairs with two 16-bit
314     // units
315     if (codePoint >= UTF16_SPECIAL_VALUE) {
316         codePoint -= UTF16_SPECIAL_VALUE;
317         // 10 : a half of 20 , shift right 10 bits
318         u16Str.push_back(static_cast<char16_t>((codePoint >> 10) | HIGH_AGENT_MASK));
319         u16Str.push_back(static_cast<char16_t>((codePoint & LOWER_10_BITS_MASK) | LOW_AGENT_MASK));
320     } else {  // In UTF-16, U+0000 to U+D7FF and U+E000 to U+FFFF are Unicode code
321         // point values
322         // assume it does not exist (if any, not encoded)
323         u16Str.push_back(static_cast<char16_t>(codePoint));
324     }
325 }
326 
Utf8ToUtf16BE(const string & u8Str,bool * ok)327 u16string StringConverter::Utf8ToUtf16BE(const string &u8Str, bool *ok)
328 {
329     u16string u16Str = u"";
330     u16Str.reserve(u8Str.size());
331     string::size_type len = u8Str.length();
332     const unsigned char *data = reinterpret_cast<const unsigned char *>(u8Str.data());
333     bool isOk = true;
334     for (string::size_type i = 0; i < len; ++i) {
335         uint8_t c1 = data[i];  // The first byte
336         if (IsOneByte(c1)) {   // only 1 byte represents the UNICODE code point
337             u16Str.push_back(static_cast<char16_t>(c1));
338             continue;
339         }
340         switch (c1 & HIGER_4_BITS_MASK) {
341             case FOUR_BYTES_STYLE: {  // 4 byte characters, from 0x10000 to 0x10FFFF
342                 Utf8ToUtf16BEToData(data, u16Str, i, c1);
343                 break;
344             }
345             case THREE_BYTES_STYLE: {    // 3 byte characters, from 0x800 to 0xFFFF
346                 uint8_t c2 = data[++i];  // The second byte
347                 uint8_t c3 = data[++i];  // The third byte
348                 // Calculates the UNICODE code point value
349                 // (4 bits lower for the first byte, 6 bits lower for the other)
350                 // 2 : shift left 2 times of UTF8_VALID_BITS
351                 uint32_t codePoint = ((c1 & LOWER_4_BITS_MASK) << (2 * UTF8_VALID_BITS)) |
352                                      ((c2 & LOWER_6_BITS_MASK) << UTF8_VALID_BITS) | (c3 & LOWER_6_BITS_MASK);
353                 u16Str.push_back(static_cast<char16_t>(codePoint));
354                 break;
355             }
356             case TWO_BYTES_STYLE1:  // 2 byte characters, from 0x80 to 0x7FF
357             case TWO_BYTES_STYLE2: {
358                 uint8_t c2 = data[++i];  // The second byte
359                 // Calculates the UNICODE code point value
360                 // (5 bits lower for the first byte, 6 bits lower for the other)
361                 uint32_t codePoint = ((c1 & LOWER_5_BITS_MASK) << UTF8_VALID_BITS) | (c2 & LOWER_6_BITS_MASK);
362                 u16Str.push_back(static_cast<char16_t>(codePoint));
363                 break;
364             }
365             default: {
366                 isOk = false;
367                 break;
368             }
369         }
370     }
371     if (ok != nullptr) {
372         *ok = isOk;
373     }
374     return u16Str;
375 }
376 
Utf16BEToLE(const u16string & wstr)377 u16string StringConverter::Utf16BEToLE(const u16string &wstr)
378 {
379     u16string str16 = u"";
380     const char16_t *data = wstr.data();
381     for (unsigned int i = 0; i < wstr.length(); i++) {
382         char16_t wc = data[i];
383         char16_t high = (wc >> 8) & 0x00FF;
384         char16_t low = wc & 0x00FF;
385         char16_t c16 = (low << 8) | high;
386         str16.push_back(c16);
387     }
388     return str16;
389 }
390 
Utf16BEToANSI(const u16string & wstr)391 string StringConverter::Utf16BEToANSI(const u16string &wstr)
392 {
393     string ret = "";
394     for (u16string::const_iterator it = wstr.begin(); it != wstr.end(); ++it) {
395         char16_t wc = (*it);
396         // get the lower bit from the UNICODE code point
397         char c = static_cast<char>(wc & LOWER_8_BITS_MASK);
398         ret.push_back(c);
399     }
400     return ret;
401 }
402 
Utf8ToUtf16BEToANSI(const string & str)403 string StringConverter::Utf8ToUtf16BEToANSI(const string &str)
404 {
405     u16string u16Str = Utf8ToUtf16BE(str);
406     string ret = Utf16BEToANSI(u16Str);
407     return ret;
408 }
409 
GetString(JSThread * thread,const JSHandle<JSTaggedValue> & str,EncodingType encodingType)410 string JSAPIFastBuffer::GetString(JSThread *thread, const JSHandle<JSTaggedValue> &str, EncodingType encodingType)
411 {
412     string_view data;
413     string strDecoded;
414     switch (encodingType) {
415         case UTF8:
416             strDecoded = FromStringUtf8(thread, str);
417             data = strDecoded;
418             break;
419         case ASCII:
420         case LATIN1:
421         case BINARY:
422             data = FromStringASCII(thread, str, strDecoded);
423             break;
424         case UTF16LE:
425             data = FromStringUtf16(thread, str, strDecoded);
426             break;
427         case BASE64:
428         case BASE64URL:
429             data = FromStringBase64(thread, str, strDecoded);
430             break;
431         case HEX:
432             data = FromStringHex(thread, str, strDecoded);
433             break;
434         default:
435             return "";
436     }
437     return strDecoded;
438 }
439 
GetString(JSThread * thread,const JSHandle<JSTaggedValue> & str,JSHandle<JSTaggedValue> encoding)440 string JSAPIFastBuffer::GetString(JSThread *thread, const JSHandle<JSTaggedValue> &str,
441                                   JSHandle<JSTaggedValue> encoding)
442 {
443     EncodingType encodingType = UTF8;
444     encodingType = GetEncodingType(ConvertEcmaStringToStdString(thread, encoding));
445     return GetString(thread, str, encodingType);
446 }
447 
FromString(JSThread * thread,const JSHandle<JSAPIFastBuffer> & buffer,const JSHandle<JSTaggedValue> & str,const JSHandle<JSTaggedValue> & encoding)448 JSTaggedValue JSAPIFastBuffer::FromString(JSThread *thread, const JSHandle<JSAPIFastBuffer> &buffer,
449                                           const JSHandle<JSTaggedValue> &str, const JSHandle<JSTaggedValue> &encoding)
450 {
451     if (encoding->IsUndefined() || encoding->IsNull()) {
452         return FromString(thread, buffer, str);
453     }
454     EncodingType encodingType = GetEncodingType(thread, encoding);
455     return FromString(thread, buffer, str, encodingType);
456 }
457 
FromString(JSThread * thread,const JSHandle<JSAPIFastBuffer> & buffer,const JSHandle<JSTaggedValue> & str,EncodingType encoding)458 JSTaggedValue JSAPIFastBuffer::FromString(JSThread *thread, const JSHandle<JSAPIFastBuffer> &buffer,
459                                           const JSHandle<JSTaggedValue> &str, EncodingType encoding)
460 {
461     string_view data;
462     string strDecoded;
463     switch (encoding) {
464         case UTF8:
465             strDecoded = FromStringUtf8(thread, str);
466             data = strDecoded;
467             break;
468         case ASCII:
469         case LATIN1:
470         case BINARY:
471             data = FromStringASCII(thread, str, strDecoded);
472             break;
473         case UTF16LE:
474             data = FromStringUtf16(thread, str, strDecoded);
475             break;
476         case BASE64:
477         case BASE64URL:
478             data = FromStringBase64(thread, str, strDecoded);
479             break;
480         case HEX:
481             data = FromStringHex(thread, str, strDecoded);
482             break;
483         default:
484             THROW_RANGE_ERROR_AND_RETURN(thread, "Not supported encodingType", JSTaggedValue::Exception());
485     }
486     // using data to new buffer
487     uint32_t length = data.length();
488     JSHandle<JSTypedArray> array = NewUint8Array(thread, length);
489     buffer->SetFastBufferData(thread, array);
490     buffer->SetLength(length);
491     if (length != 0) {
492         auto *dst = GetUnderlyingData(thread, buffer.GetTaggedValue());
493         if (dst == nullptr) {
494             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::ARRAY_BUFFER_IS_NULL_OR_DETACHED,
495                                                                 "The underlying ArrayBuffer is null or detached.");
496             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
497         }
498         WriteBytes(thread, reinterpret_cast<const uint8_t *>(data.data()), length, reinterpret_cast<uint8_t *>(dst));
499     }
500     return buffer.GetTaggedValue();
501 }
502 
ToString(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,EncodingType encodingType,uint32_t start,uint32_t end)503 JSTaggedValue JSAPIFastBuffer::ToString(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer, EncodingType encodingType,
504                                         uint32_t start, uint32_t end)
505 {
506     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
507     if (!RangeChecker(0, buffer->GetLength(), start, end)) {
508         std::ostringstream oss;
509         oss << "Buffer ToString parameter are out of range";
510         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
511         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
512     }
513     auto arrayBuffer = GetArrayBuffer(thread, buffer);
514     if (BuiltinsArrayBuffer::IsDetachedBuffer(thread, arrayBuffer)) {
515         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::ARRAY_BUFFER_IS_NULL_OR_DETACHED,
516                                                             "The underlying ArrayBuffer is null or detached.");
517         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
518     }
519     uint8_t *data = reinterpret_cast<uint8_t *>(
520         builtins::BuiltinsArrayBuffer::GetDataPointFromBuffer(thread, arrayBuffer, buffer->GetOffset() + start));
521     uint32_t len = end - start;
522     string strDecoded;
523     switch (encodingType) {
524         case UTF8:
525             return factory->NewFromUtf8WithoutStringTable(string_view(reinterpret_cast<const char *>(data), len))
526                 .GetTaggedValue();
527         case ASCII:
528             return factory->NewFromASCII(string_view(reinterpret_cast<const char *>(data), len)).GetTaggedValue();
529         case UTF16LE:
530             // 2 : uint16_t is double of uint8_t
531             return factory->NewFromUtf16(reinterpret_cast<uint16_t *>(data), len / 2).GetTaggedValue();
532         case LATIN1:
533         case BINARY:
534             StringConverter::Latin1Encode(reinterpret_cast<unsigned char *>(data), len, strDecoded);
535             break;
536         case BASE64:
537         case BASE64URL:
538             StringConverter::Base64Encode(reinterpret_cast<unsigned char *>(data), len, strDecoded,
539                                           encodingType == BASE64URL);
540             break;
541         case HEX:
542             StringConverter::HexEncode(reinterpret_cast<unsigned char *>(data), len, strDecoded);
543             break;
544         default:
545             THROW_RANGE_ERROR_AND_RETURN(thread, "Not supported encodingType", JSTaggedValue::Exception());
546     }
547     return factory->NewFromUtf8(strDecoded).GetTaggedValue();
548 }
549 
WriteString(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,JSHandle<JSTaggedValue> & value,uint32_t offset,uint32_t maxLen,EncodingType encoding)550 JSTaggedValue JSAPIFastBuffer::WriteString(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer,
551                                            JSHandle<JSTaggedValue> &value, uint32_t offset, uint32_t maxLen,
552                                            EncodingType encoding)
553 {
554     ASSERT(value->IsString());
555     uint32_t bufLength = buffer->GetLength();
556     if (offset > bufLength) {
557         return JSTaggedValue(0);
558     }
559     maxLen = std::min(maxLen, bufLength - offset);
560     string_view data;
561     string strDecoded;  // data = string_view(strDecoded)
562     switch (encoding) {
563         case UTF8:
564             strDecoded = FromStringUtf8(thread, value);
565             data = strDecoded;
566             break;
567         case ASCII:
568         case LATIN1:
569         case BINARY:
570             data = FromStringASCII(thread, value, strDecoded);
571             break;
572         case UTF16LE:
573             strDecoded = FromStringUtf16(thread, value, strDecoded);
574             data = strDecoded;
575             break;
576         case BASE64:
577         case BASE64URL:
578             data = FromStringBase64(thread, value, strDecoded);
579             break;
580         case HEX:
581             data = FromStringHex(thread, value, strDecoded);
582             break;
583         default:
584             THROW_RANGE_ERROR_AND_RETURN(thread, "Not supported encodingType", JSTaggedValue::Exception());
585     }
586     uint32_t strLength = data.length();
587     if (strLength == 0) {
588         return JSTaggedValue(0);
589     }
590     maxLen = std::min(maxLen, strLength);
591     auto *dst = GetUnderlyingData(thread, buffer.GetTaggedValue(), offset);
592     if (dst == nullptr) {
593         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::ARRAY_BUFFER_IS_NULL_OR_DETACHED,
594                                                             "The underlying ArrayBuffer is null or detached.");
595         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
596     }
597     WriteBytes(thread, reinterpret_cast<const uint8_t *>(data.data()), maxLen, reinterpret_cast<uint8_t *>(dst));
598     return JSTaggedValue(maxLen);
599 }
600 
AllocateFastBuffer(JSThread * thread,const JSHandle<JSAPIFastBuffer> & buffer,uint32_t byteLength,uint32_t byteOffset)601 JSTaggedValue JSAPIFastBuffer::AllocateFastBuffer(JSThread *thread, const JSHandle<JSAPIFastBuffer> &buffer,
602                                                   uint32_t byteLength, uint32_t byteOffset)
603 {
604     JSHandle<JSTypedArray> handleUint8Array = JSAPIFastBuffer::NewUint8Array(thread, byteLength);
605     buffer->SetFastBufferData(thread, handleUint8Array);
606     buffer->SetLength(byteLength);
607     buffer->SetOffset(byteOffset);
608     return buffer.GetTaggedValue();
609 }
610 
AllocateFromBufferObject(JSThread * thread,const JSHandle<JSAPIFastBuffer> & buffer,const JSHandle<JSTaggedValue> & src,uint32_t byteLength,uint32_t byteOffset)611 JSTaggedValue JSAPIFastBuffer::AllocateFromBufferObject(JSThread *thread, const JSHandle<JSAPIFastBuffer> &buffer,
612                                                         const JSHandle<JSTaggedValue> &src, uint32_t byteLength,
613                                                         uint32_t byteOffset)
614 {
615     auto handleUint8Array = JSTaggedValue(GetUInt8ArrayFromBufferObject(thread, src));
616     buffer->SetFastBufferData(thread, handleUint8Array);
617     buffer->SetLength(byteLength);
618     buffer->SetOffset(byteOffset);
619     return buffer.GetTaggedValue();
620 }
621 
GetArrayBuffer(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer)622 JSTaggedValue JSAPIFastBuffer::GetArrayBuffer(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer)
623 {
624     // if buffer size smaller than Buffer.poolSize, it may return the pool arraybuffer.
625     auto array =
626         JSHandle<JSTypedArray>(thread, JSTypedArray::Cast(buffer->GetFastBufferData(thread).GetTaggedObject()));
627     return JSTypedArray::GetOffHeapBuffer(thread, array);
628 }
629 
630 // return a JSArray copied from buffer.Uint8Array
FromBufferToArray(JSThread * thread,JSHandle<JSTaggedValue> & value)631 JSTaggedValue JSAPIFastBuffer::FromBufferToArray(JSThread *thread, JSHandle<JSTaggedValue> &value)
632 {
633     auto buffer = JSHandle<JSAPIFastBuffer>(value);
634     int32_t length = static_cast<int32_t>(buffer->GetLength());
635     JSHandle<JSTaggedValue> array = JSArray::ArrayCreate(thread, JSTaggedNumber(length));
636     JSHandle<JSTypedArray> typedArray =
637         JSHandle<JSTypedArray>(thread, JSTypedArray::Cast(buffer->GetFastBufferData(thread).GetTaggedObject()));
638     for (int i = 0; i < length; i++) {
639         JSTaggedValue bufferValue = GetValueByIndex(thread, typedArray.GetTaggedValue(), i, JSType::JS_UINT8_ARRAY);
640         JSArray::FastSetPropertyByValue(thread, array, i, JSHandle<JSTaggedValue>(thread, bufferValue));
641     }
642     return array.GetTaggedValue();
643 }
644 
Entries(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer)645 JSTaggedValue JSAPIFastBuffer::Entries(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer)
646 {
647     auto array =
648         JSHandle<JSTypedArray>(thread, JSTypedArray::Cast(buffer->GetFastBufferData(thread).GetTaggedObject()));
649     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
650     JSHandle<JSArrayIterator> iter(
651         factory->NewJSArrayIterator(JSHandle<JSObject>(thread, array.GetTaggedValue()), IterationKind::KEY_AND_VALUE));
652     return iter.GetTaggedValue();
653 }
654 
Keys(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer)655 JSTaggedValue JSAPIFastBuffer::Keys(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer)
656 {
657     auto array =
658         JSHandle<JSTypedArray>(thread, JSTypedArray::Cast(buffer->GetFastBufferData(thread).GetTaggedObject()));
659     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
660     JSHandle<JSArrayIterator> iter(
661         factory->NewJSArrayIterator(JSHandle<JSObject>(thread, array.GetTaggedValue()), IterationKind::KEY));
662     return iter.GetTaggedValue();
663 }
664 
Values(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer)665 JSTaggedValue JSAPIFastBuffer::Values(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer)
666 {
667     auto array =
668         JSHandle<JSTypedArray>(thread, JSTypedArray::Cast(buffer->GetFastBufferData(thread).GetTaggedObject()));
669     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
670     JSHandle<JSArrayIterator> iter(
671         factory->NewJSArrayIterator(JSHandle<JSObject>(thread, array.GetTaggedValue()), IterationKind::VALUE));
672     return iter.GetTaggedValue();
673 }
674 
Utf16StrToStr(std::u16string & value)675 std::string StringConverter::Utf16StrToStr(std::u16string &value)
676 {
677     string str = "";
678     const char16_t *data = reinterpret_cast<const char16_t *>(value.data());
679     for (unsigned int i = 0; i < value.length(); i++) {
680         char16_t c = data[i];
681         char high = static_cast<char>((c >> 8) & 0x00FF);
682         char low = static_cast<char>(c & 0x00FF);
683         str.push_back(low);
684         str.push_back(high);
685     }
686     return str;
687 }
688 
FillString(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,JSHandle<JSTaggedValue> & valueHandle,EncodingType encoding,uint32_t start,uint32_t end)689 JSTaggedValue JSAPIFastBuffer::FillString(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer,
690                                           JSHandle<JSTaggedValue> &valueHandle, EncodingType encoding, uint32_t start,
691                                           uint32_t end)
692 {
693     string str = GetString(thread, valueHandle, encoding);
694     if (str.length() == 0) {
695         str.push_back(0);
696     }
697     return WriteStringLoop(thread, buffer, str, start, end);
698 }
699 
Fill(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,JSHandle<JSTaggedValue> & valueHandle,EncodingType encoding,uint32_t start,uint32_t end)700 JSTaggedValue JSAPIFastBuffer::Fill(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer,
701                                     JSHandle<JSTaggedValue> &valueHandle, EncodingType encoding, uint32_t start,
702                                     uint32_t end)
703 {
704     if (valueHandle->IsUndefined() || valueHandle->IsNull()) {
705         valueHandle = JSHandle<JSTaggedValue>(thread, JSTaggedValue(0));
706     }
707     if (valueHandle->IsNumber()) {
708         if (!valueHandle->IsInt()) {
709             std::ostringstream oss;
710             oss << "Buffer fill number shoule be a integer";
711             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, oss.str().c_str());
712             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Undefined());
713         }
714         // only use low 8 bits of value
715         uint8_t value = static_cast<uint8_t>(valueHandle->GetInt());
716         uint32_t length = end - start;
717         uint8_t *data = GetUnderlyingData(thread, buffer.GetTaggedValue(), start);
718         if (data == nullptr) {
719             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::ARRAY_BUFFER_IS_NULL_OR_DETACHED,
720                                                                 "The underlying ArrayBuffer is null or detached.");
721             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
722         }
723         if (memset_s(data, length, value, length) != EOK) {
724             JSTaggedValue error =
725                 ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, "Fill value memset failed.");
726             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
727         }
728     } else if (valueHandle->IsString()) {
729         FillString(thread, buffer, valueHandle, encoding, start, end);
730     } else if (valueHandle->IsJSAPIBuffer() || valueHandle->IsTypedArray()) {
731         WriteBufferObjectLoop(thread, buffer, valueHandle, start, end);
732     }
733     return buffer.GetTaggedValue();
734 }
735 
Compare(JSThread * thread,JSHandle<JSAPIFastBuffer> & a,JSHandle<JSTaggedValue> & bObj,uint32_t sStart,uint32_t sEnd,uint32_t tStart,uint32_t tEnd)736 JSTaggedValue JSAPIFastBuffer::Compare(JSThread *thread, JSHandle<JSAPIFastBuffer> &a, JSHandle<JSTaggedValue> &bObj,
737                                        uint32_t sStart, uint32_t sEnd, uint32_t tStart, uint32_t tEnd)
738 {
739     JSTypedArray *typedArrayA = GetUInt8ArrayFromBufferObject(thread, a.GetTaggedValue());
740     JSTypedArray *typedArrayB = GetUInt8ArrayFromBufferObject(thread, bObj);
741     uint32_t aCmpLength = sEnd - sStart;
742     uint32_t bCmpLength = tEnd - tStart;
743     if (typedArrayA->GetByteLength() < aCmpLength || typedArrayB->GetByteLength() < bCmpLength) {
744         std::ostringstream oss;
745         oss << "Buffer Compare parameters are out of range.";
746         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
747         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
748     }
749     uint8_t *aPointer = GetUnderlyingData(thread, a.GetTaggedValue(), sStart);
750     uint8_t *bPointer = GetUnderlyingData(thread, bObj.GetTaggedValue(), tStart);
751     if (aPointer == nullptr || bPointer == nullptr) {
752         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::ARRAY_BUFFER_IS_NULL_OR_DETACHED,
753                                                             "Buffer Compare memory ptr is nullptr.");
754         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
755     }
756     uint32_t length = std::min(aCmpLength, bCmpLength);
757     int32_t ret = memcmp(aPointer, bPointer, length);
758     if (ret == 0) {
759         if (aCmpLength != bCmpLength) {
760             return aCmpLength < bCmpLength ? JSTaggedValue(-1) : JSTaggedValue(1);
761         }
762         return JSTaggedValue(0);
763     }
764     return ret < 0 ? JSTaggedValue(-1) : JSTaggedValue(1);
765 }
766 
Includes(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,JSHandle<JSTaggedValue> valueHandle,uint32_t start,EncodingType encoding)767 JSTaggedValue JSAPIFastBuffer::Includes(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer,
768                                         JSHandle<JSTaggedValue> valueHandle, uint32_t start, EncodingType encoding)
769 {
770     JSTaggedValue res = IndexOf(thread, buffer, valueHandle, start, encoding, false);
771     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
772     return res.GetInt() == -1 ? JSTaggedValue::False() : JSTaggedValue::True();
773 }
774 
StringMatch(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,const uint8_t * str,uint32_t start,uint32_t strLength,bool isReverse)775 int32_t JSAPIFastBuffer::StringMatch(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer, const uint8_t *str,
776                                      uint32_t start, uint32_t strLength, bool isReverse)
777 {
778     if (buffer->GetLength() < strLength) {
779         return -1;
780     }
781     auto src = GetUnderlyingData(thread, buffer.GetTaggedValue());
782     if (src == nullptr) {
783         return -1;
784     }
785     uint32_t end = buffer->GetLength() - strLength;
786     // reverse is mean enumeration order
787     if (isReverse) {
788         for (int32_t i = std::min(end, start); i >= 0; --i) {
789             if (memcmp(str, src + i, strLength) == 0) {
790                 return i;
791             }
792         }
793     } else {
794         for (uint32_t i = start; i <= end; ++i) {
795             if (memcmp(str, src + i, strLength) == 0) {
796                 return i;
797             }
798         }
799     }
800     return -1;
801 }
802 
IndexOf(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,JSHandle<JSTaggedValue> valueHandle,uint32_t start,EncodingType encoding,bool isReverse)803 JSTaggedValue JSAPIFastBuffer::IndexOf(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer,
804                                        JSHandle<JSTaggedValue> valueHandle, uint32_t start, EncodingType encoding,
805                                        bool isReverse)
806 {
807     if (!valueHandle->IsNumber()) {
808         if (valueHandle->IsString()) {
809             string str = GetString(thread, valueHandle, encoding);
810             const uint8_t *data = reinterpret_cast<const uint8_t *>(str.data());
811             uint32_t len = str.length();
812             return len == 0 ? JSTaggedValue(0)
813                             : JSTaggedValue(StringMatch(thread, buffer, data, start, len, isReverse));
814         } else if (valueHandle->IsJSAPIBuffer() || valueHandle->IsJSUint8Array()) {
815             const uint8_t *data = GetUnderlyingData(thread, valueHandle.GetTaggedValue());
816             uint32_t len = valueHandle->IsJSAPIBuffer() ? JSHandle<JSAPIFastBuffer>(valueHandle)->GetLength()
817                                                         : JSHandle<JSTypedArray>(valueHandle)->GetByteLength();
818             if (len == 0) {
819                 return JSTaggedValue(0);
820             }
821             if (data == nullptr) {
822                 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::ARRAY_BUFFER_IS_NULL_OR_DETACHED,
823                                                                     "The underlying ArrayBuffer is null or detached.");
824                 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
825             }
826             return JSTaggedValue(StringMatch(thread, buffer, data, start, len, isReverse));
827         }
828         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, "IndexOf value invalid.");
829         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
830     }
831     if (!valueHandle->IsInt()) {
832         std::ostringstream oss;
833         oss << "Buffer includes value shoule be integer when value is number";
834         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, oss.str().c_str());
835         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
836     }
837     uint8_t value = static_cast<uint8_t>(valueHandle->GetInt());
838     uint32_t length = buffer->GetLength();
839     if (isReverse) {
840         for (int32_t i = std::min(length - 1, start); i >= 0; --i) {
841             if (value == ReadUInt8(thread, buffer, i, true).GetInt()) {
842                 return JSTaggedValue(i);
843             }
844         }
845     } else {
846         for (uint32_t i = start; i < length; ++i) {
847             if (value == ReadUInt8(thread, buffer, i, true).GetInt()) {
848                 return JSTaggedValue(i);
849             }
850         }
851     }
852     return JSTaggedValue(-1);  // value not found
853 }
854 
WriteBytes(JSThread * thread,const uint8_t * src,unsigned int size,uint8_t * dest)855 bool JSAPIFastBuffer::WriteBytes(JSThread *thread, const uint8_t *src, unsigned int size, uint8_t *dest)
856 {
857     if (src == nullptr || dest == nullptr) {
858         return false;
859     }
860     if (size == 0) {
861         return true;
862     }
863     if (memmove_s(dest, size, src, size) != EOK) {
864         std::ostringstream oss;
865         oss << "Buffer WriteBytes memmove_s failed";
866         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
867         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
868     }
869     return true;
870 }
871 
WriteDataLoop(const uint8_t * src,uint8_t * dest,uint32_t length,uint32_t start,uint32_t end)872 bool JSAPIFastBuffer::WriteDataLoop(const uint8_t *src, uint8_t *dest, uint32_t length, uint32_t start, uint32_t end)
873 {
874     if (end - start <= 0 || length == 0) {
875         return false;
876     }
877     dest += start;
878     end -= start;
879     uint32_t pos = 0;
880     uint32_t copySize = std::min(length, end);
881     if (memmove_s(dest, copySize, src, copySize) != EOK) {
882         return false;
883     }
884     pos += copySize;
885     while (pos < end) {
886         copySize = std::min(copySize, end - pos);
887         if (memmove_s(dest + pos, copySize, dest, copySize) != EOK) {
888             return false;
889         }
890         pos += copySize;
891         copySize <<= 1;
892     }
893     return true;
894 }
895 
WriteStringLoop(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,string_view data,uint32_t start,uint32_t end)896 JSTaggedValue JSAPIFastBuffer::WriteStringLoop(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer, string_view data,
897                                                uint32_t start, uint32_t end)
898 {
899     uint32_t length = data.length();
900     uint8_t *dst = GetUnderlyingData(thread, buffer.GetTaggedValue());
901     uint8_t *str = const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(data.data()));
902     if (str == nullptr || dst == nullptr) {
903         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::ARRAY_BUFFER_IS_NULL_OR_DETACHED,
904                                                             "The underlying ArrayBuffer is null or detached.");
905         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
906     }
907     if (!WriteDataLoop(str, dst, length, start, end)) {
908         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, "Write data Failed.");
909         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
910     }
911     return JSTaggedValue(length);
912 }
913 
WriteBufferObjectLoop(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,JSHandle<JSTaggedValue> & srcObj,uint32_t start,uint32_t end)914 JSTaggedValue JSAPIFastBuffer::WriteBufferObjectLoop(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer,
915                                                      JSHandle<JSTaggedValue> &srcObj, uint32_t start, uint32_t end)
916 {
917     if (end - start > buffer->GetLength()) {
918         return JSTaggedValue(0);
919     }
920     auto srcArray = GetUInt8ArrayFromBufferObject(thread, srcObj);
921     uint32_t length = srcArray->GetByteLength();
922     uint8_t *src = GetUnderlyingData(thread, srcObj.GetTaggedValue());
923     uint8_t *dst = GetUnderlyingData(thread, buffer.GetTaggedValue());
924     if (src == nullptr || dst == nullptr) {
925         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::ARRAY_BUFFER_IS_NULL_OR_DETACHED,
926                                                             "The underlying ArrayBuffer is null or detached.");
927         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
928     }
929     WriteDataLoop(src, dst, length, start, end);
930     return JSTaggedValue(length);
931 }
932 
WriteBytes(JSThread * thread,JSHandle<JSTaggedValue> srcData,JSHandle<JSTaggedValue> dstData,uint32_t sStart,uint32_t tStart,uint32_t size)933 bool JSAPIFastBuffer::WriteBytes(JSThread *thread, JSHandle<JSTaggedValue> srcData, JSHandle<JSTaggedValue> dstData,
934                                  uint32_t sStart, uint32_t tStart, uint32_t size)
935 {
936     ASSERT(srcData->IsByteArray() || srcData->IsArrayBuffer());
937     ASSERT(dstData->IsByteArray() || dstData->IsArrayBuffer());
938     auto src = reinterpret_cast<uint8_t *>(
939         builtins::BuiltinsArrayBuffer::GetDataPointFromBuffer(thread, srcData.GetTaggedValue(), sStart));
940     auto dst = reinterpret_cast<uint8_t *>(
941         builtins::BuiltinsArrayBuffer::GetDataPointFromBuffer(thread, dstData.GetTaggedValue(), tStart));
942     return WriteBytes(thread, src, size, dst);
943 }
944 
SetValueByIndex(JSThread * thread,const JSTaggedValue typedarray,uint32_t index,JSTaggedValue value,JSType valueType,bool littleEndian)945 JSTaggedValue JSAPIFastBuffer::SetValueByIndex(JSThread *thread, const JSTaggedValue typedarray, uint32_t index,
946                                                JSTaggedValue value, JSType valueType, bool littleEndian)
947 {
948     ASSERT(typedarray.IsJSUint8Array());
949     JSTypedArray *typedarrayObj = JSTypedArray::Cast(typedarray.GetTaggedObject());
950     if (UNLIKELY(value.IsECMAObject())) {
951         return JSTaggedValue::Hole();
952     }
953     JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray(thread);
954     DataViewType elementType = TypedArrayHelper::GetType(valueType);
955     auto valueHandle = JSHandle<JSTaggedValue>(thread, value);
956     return BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer, index, elementType, valueHandle, littleEndian);
957 }
958 
GetValueByIndex(JSThread * thread,const JSTaggedValue typedarray,uint32_t index,JSType jsType,bool littleEndian)959 JSTaggedValue JSAPIFastBuffer::GetValueByIndex(JSThread *thread, const JSTaggedValue typedarray, uint32_t index,
960                                                JSType jsType, bool littleEndian)
961 {
962     ASSERT(typedarray.IsTypedArray() || typedarray.IsSharedTypedArray());
963     // Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
964     JSTypedArray *typedarrayObj = JSTypedArray::Cast(typedarray.GetTaggedObject());
965     JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray(thread);
966     if (buffer.IsArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(thread, buffer)) {
967         return JSTaggedValue::Undefined();
968     }
969     DataViewType elementType = TypedArrayHelper::GetType(jsType);
970     return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, index, elementType, littleEndian);
971 }
972 
GetProperty(JSThread * thread,const JSHandle<JSAPIFastBuffer> & obj,const JSHandle<JSTaggedValue> & key)973 OperationResult JSAPIFastBuffer::GetProperty(JSThread *thread, const JSHandle<JSAPIFastBuffer> &obj,
974                                              const JSHandle<JSTaggedValue> &key)
975 {
976     uint32_t length = obj->GetLength();
977     int32_t index = key->GetInt();
978     if (index < 0 || static_cast<uint32_t>(index) >= length) {
979         std::ostringstream oss;
980         oss << "The value of \"index\" is out of range. It must be >= 0 and <= " << (length - 1)
981             << ". Received value is: " << index;
982         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
983         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error,
984                                          OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
985     }
986     return OperationResult(thread, ReadUInt8(thread, obj, index, true), PropertyMetaData(false));
987 }
988 
SetProperty(JSThread * thread,const JSHandle<JSAPIFastBuffer> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)989 bool JSAPIFastBuffer::SetProperty(JSThread *thread, const JSHandle<JSAPIFastBuffer> &obj,
990                                   const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value)
991 {
992     uint32_t length = obj->GetLength();
993     int32_t index = key->GetInt();
994     if (index < 0 || static_cast<uint32_t>(index) >= length) {
995         return false;
996     }
997     WriteUInt8(thread, obj, value, index, true);
998     return true;
999 }
1000 
Base64Encode(const unsigned char * src,uint32_t len,string & outStr,bool isUrl)1001 void StringConverter::Base64Encode(const unsigned char *src, uint32_t len, string &outStr, bool isUrl)
1002 {
1003     if (!len) {
1004         outStr = "";
1005         return;
1006     }
1007     char *out = nullptr;
1008     char *pos = nullptr;
1009     const unsigned char *pEnd = nullptr;
1010     const unsigned char *pStart = nullptr;
1011     size_t outLen = 4 * ((len + 2) / 3);  // 3-byte blocks to 4-byte
1012 
1013     outStr.resize(outLen);
1014     out = outStr.data();
1015 
1016     pEnd = src + len;
1017     pStart = src;
1018     pos = out;
1019     const char *table = isUrl ? "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
1020                               : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1021     // 3 : 3 bytes is just 24 bits which is 4 times of 6 bits
1022     while (pEnd - pStart >= 3) {
1023         // 2 : add two zeros in front of the first set of 6 bits to become a new 8 binary bits
1024         *pos = table[pStart[0] >> 2];
1025         // 4 : add two zeros in front of the following second set of 6 bits to become the new 8 binary bits
1026         *(pos + 1) = table[((pStart[0] & LOWER_2_BITS_MASK) << 4) | (pStart[1] >> 4)];  // 1 means the first encoded
1027         // 2 : 4 : 6 : add two zeros in front of the following third set of 6 bits to become the new 8 binary bits
1028         *(pos + 2) = table[((pStart[1] & LOWER_4_BITS_MASK) << 2) | (pStart[2] >> 6)];
1029         // 2 : 3 : add two zeros in front of the following forth set of 6 bits to become the new 8 binary bits
1030         *(pos + 3) = table[pStart[2] & LOWER_6_BITS_MASK];
1031         // 4 : the pointer of pos scrolls off 4 bytes to point the next 4 bytes of encoded chars
1032         pos += 4;
1033         // 3 : the pointer of pStart scrolls off 3 bytes to point the next 3 bytes of which will be encoded chars
1034         pStart += 3;
1035     }
1036     if (pEnd - pStart > 0) {
1037         // 2 : add two zeros in front of the first set of 6 bits to become a new 8 binary bits
1038         *pos = table[pStart[0] >> 2];
1039         if (pEnd - pStart == 1) {
1040             // 4 : paddle the last two bits of the last byte with two zeros in front of it and four zeros after it
1041             *(pos + 1) = table[(pStart[0] & LOWER_2_BITS_MASK) << 4];
1042             // 2 : fill in the missing bytes with '='
1043             *(pos + 2) = '=';
1044         } else {
1045             // 4 : add two zeros in front of the second set of 6 bits to become the new 8 binary bits
1046             *(pos + 1) = table[((pStart[0] & LOWER_2_BITS_MASK) << 4) | (pStart[1] >> 4)];
1047             // 2 : paddle the last four bits of the last byte with two zeros in front of it and two zeros after it
1048             *(pos + 2) = table[(pStart[1] & LOWER_4_BITS_MASK) << 2];
1049         }
1050         // 3 : fill in the missing bytes with '='
1051         *(pos + 3) = '=';
1052     }
1053 
1054     if (isUrl) {
1055         size_t poss = outStr.find_last_not_of('=');
1056         if (poss != std::string::npos) {
1057             outStr.erase(poss + 1);
1058         }
1059     }
1060 }
1061 
DecodeBase64CharSlow(const uint8_t * data,string & ret,size_t len,uint32_t & cursor,uint32_t & retIter)1062 void DecodeBase64CharSlow(const uint8_t *data, string &ret, size_t len, uint32_t &cursor, uint32_t &retIter)
1063 {
1064     auto &table = BASE64_TABLE;
1065     size_t count = 0;
1066     // 4 : four char to decode each time
1067     CVector<unsigned char> temp(4, 0);
1068     // 4 : try to map 4 index from base64 table
1069     while (cursor < len && count < 4) {
1070         unsigned char ch = table[data[cursor++]];
1071         if (ch > StringConverter::LOWER_6_BITS_MASK) {
1072             continue;
1073         }
1074         temp[count++] = ch;
1075     }
1076     if (count > JSAPIFastBuffer::OneByte) {
1077         ret[retIter] =
1078             // 2 : 4 : two bits(except two higer bits) of the second byte, combine them to a new byte
1079             ((temp[0] & StringConverter::LOWER_6_BITS_MASK) << 2) | ((temp[JSAPIFastBuffer::OneByte] & 0x30) >> 4);
1080         ++retIter;
1081     }
1082     if (count > JSAPIFastBuffer::TwoBytes) {
1083         // 4 : 2 : four bits(except two higer bits) of the third byte, combine them to a new byte
1084         ret[retIter] = ((temp[JSAPIFastBuffer::OneByte] & StringConverter::LOWER_4_BITS_MASK) << 4) |
1085                        // 2 : (except two higer bits)
1086                        ((temp[JSAPIFastBuffer::TwoBytes] & StringConverter::MIDDLE_4_BITS_MASK) >> 2);
1087         ++retIter;
1088     }
1089     if (count > JSAPIFastBuffer::ThreeBytes) {
1090         // 2 : 3 : 6 : combine them to a new byte
1091         ret[retIter] = ((temp[JSAPIFastBuffer::TwoBytes] & StringConverter::LOWER_2_BITS_MASK) << 6) |
1092                        (temp[JSAPIFastBuffer::ThreeBytes] & StringConverter::LOWER_6_BITS_MASK);
1093         ++retIter;
1094     }
1095 }
1096 
Base64Decode(string_view encodedStr,string & ret)1097 void StringConverter::Base64Decode(string_view encodedStr, string &ret)
1098 {
1099     size_t len = encodedStr.length();
1100     unsigned int cursor = 0;
1101     unsigned char charArray4[4] = {0};
1102     // why upperLength: len = ceil(decodedString.length / 3) * 4
1103     // upperLength = len / 4 * 3 = ceil(decodedString.length / 3) * 3 >=
1104     // decodedString.length
1105     uint32_t upperLength = (len + 3) / 4 * 3;
1106     ret.reserve(upperLength);
1107     ret.resize(upperLength);
1108     uint32_t maxLen = len / 4 * 4;
1109     uint32_t retIter = 0;
1110     auto &table = BASE64_TABLE;
1111     const uint8_t *data = reinterpret_cast<const uint8_t *>(encodedStr.data());
1112     while (cursor < maxLen) {
1113         // 0 : the first index map to base64 table
1114         charArray4[0] = static_cast<unsigned char>(table[data[cursor]]);
1115         // 1 : the second index map to base64 table
1116         charArray4[1] = static_cast<unsigned char>(table[data[cursor + 1]]);
1117         // 2 : the third index map to base64 table
1118         charArray4[2] = static_cast<unsigned char>(table[data[cursor + 2]]);
1119         // 3 : the fourth index map to base64 table
1120         charArray4[3] = static_cast<unsigned char>(table[data[cursor + 3]]);
1121         // 0 : 1 : 2 : 3 : check if invalid index exist
1122         if ((charArray4[0] | charArray4[1] | charArray4[2] | charArray4[3]) > LOWER_6_BITS_MASK) {
1123             DecodeBase64CharSlow(data, ret, len, cursor, retIter);
1124             continue;
1125         }
1126         // 1 : result first char
1127         // 2 : 4 : two bits(except two higer bits) of the second byte, combine them to a new byte
1128         ret[retIter] = ((charArray4[0] & LOWER_6_BITS_MASK) << 2) | ((charArray4[1] & 0x30) >> 4);
1129         // 1 : 2 : result second char
1130         // 4 : 2 : four bits(except two higer bits) of the third byte, combine them to a new byte
1131         ret[retIter + 1] = ((charArray4[1] & LOWER_4_BITS_MASK) << 4) | ((charArray4[2] & MIDDLE_4_BITS_MASK) >> 2);
1132         // 2 : 3 : result third char
1133         // 2 : 3 : 6 : combine them to a new byte
1134         ret[retIter + 2] = ((charArray4[2] & LOWER_2_BITS_MASK) << 6) | (charArray4[3] & LOWER_6_BITS_MASK);
1135         // 3 : every time 3 bytes
1136         retIter += 3;
1137         // 4 : every time 4 bytes
1138         cursor += 4;
1139     }
1140     if (cursor < len) {
1141         DecodeBase64CharSlow(data, ret, len, cursor, retIter);
1142     }
1143     ret.resize(retIter);
1144 }
1145 
1146 // encoding bytesflow(latin1) to utf8
Latin1Encode(const unsigned char * data,uint32_t len,std::string & ret)1147 void StringConverter::Latin1Encode(const unsigned char *data, uint32_t len, std::string &ret)
1148 {
1149     // 2 : reserve enough space to encode
1150     ret.reserve(len * 2);
1151     for (uint32_t i = 0; i < len; i++) {
1152         unsigned char c = data[i];
1153         if (c < 0x80) {
1154             ret.push_back(c);
1155         } else {
1156             ret.push_back(0xc0 | (c >> UTF8_VALID_BITS));
1157             ret.push_back(0x80 | (c & 0x3f));
1158         }
1159     }
1160 }
1161 
IsValidHex(const string & hex)1162 bool IsValidHex(const string &hex)
1163 {
1164     if (!hex.length()) {
1165         return false;
1166     }
1167     for (unsigned int i = 0; i < hex.size(); i++) {
1168         char c = hex.at(i);
1169         // 0 ~ 9, A ~ F, a ~ f
1170         if (!(c <= '9' && c >= '0') && !(c <= 'F' && c >= 'A') && !(c <= 'f' && c >= 'a')) {
1171             return false;
1172         }
1173     }
1174     return true;
1175 }
1176 
HexEncode(const unsigned char * hexStr,uint32_t len,string & ret)1177 void StringConverter::HexEncode(const unsigned char *hexStr, uint32_t len, string &ret)
1178 {
1179     // 2 : reserve enough length to encode
1180     ret.reserve(2 * len);
1181     for (uint32_t i = 0; i < len; i++) {
1182         uint8_t high = hexStr[i] >> 4;
1183         uint8_t low = hexStr[i] & 0x0f;
1184         // 9 : 10 : convert high to hex
1185         ret.push_back(high > 9 ? 'a' + (high % 10) : '0' + high);
1186         // 9 : 10 : convert low to hex
1187         ret.push_back(low > 9 ? 'a' + (low % 10) : '0' + low);
1188     }
1189 }
1190 
HexDecode(string_view hexStr,string & ret)1191 void StringConverter::HexDecode(string_view hexStr, string &ret)
1192 {
1193     unsigned int arrSize = hexStr.size();
1194     // 2 : 1 : means a half length of hex str's size
1195     ret.reserve(arrSize / 2);
1196 
1197     string hexStrTmp;
1198     int num = 0;
1199     // 2 : hex string to stoi
1200     hexStrTmp.resize(2);
1201     // 2 : means a half length of hex str's size
1202     for (unsigned int i = 0; i < arrSize / 2; i++) {
1203         // 2 : offset is i * 2
1204         hexStrTmp[0] = hexStr[i * 2];
1205         // 2 : offset is i * 2 + 1
1206         hexStrTmp[1] = hexStr[i * 2 + 1];
1207         if (!IsValidHex(hexStrTmp)) {
1208             break;
1209         }
1210         // 16 : the base is 16
1211         num = stoi(hexStrTmp, nullptr, 16);
1212         ret.push_back(static_cast<char>(num));
1213     }
1214 }
1215 
SplitUInt(JSHandle<JSTaggedValue> & value,uint64_t byteLength)1216 std::pair<JSTaggedValue, JSTaggedValue> SplitUInt(JSHandle<JSTaggedValue> &value, uint64_t byteLength)
1217 {
1218     ASSERT(value->IsNumber());
1219     uint64_t temp;
1220     if (value->IsDouble()) {
1221         temp = static_cast<uint64_t>(value->GetDouble());
1222     } else {
1223         temp = static_cast<uint64_t>(value->GetInt());
1224     }
1225     byteLength *= JSAPIFastBuffer::ONE_BYTE_BIT_LENGTH;
1226     uint64_t bitMask = static_cast<uint64_t>(static_cast<uint64_t>(1) << byteLength) - 1;
1227     auto l = JSTaggedValue(static_cast<uint32_t>(temp & bitMask));
1228     auto r = JSTaggedValue(static_cast<uint32_t>(temp >> byteLength));
1229     return std::make_pair(l, r);
1230 }
1231 
MergeUInt(JSTaggedValue low,JSTaggedValue high,uint64_t byteLengthLow)1232 JSTaggedValue MergeUInt(JSTaggedValue low, JSTaggedValue high, uint64_t byteLengthLow)
1233 {
1234     byteLengthLow *= JSAPIFastBuffer::ONE_BYTE_BIT_LENGTH;
1235     uint64_t lowValue = 0;
1236     uint64_t highValue = 0;
1237     lowValue |= static_cast<uint64_t>(low.GetNumber());
1238     highValue |= static_cast<uint64_t>(high.GetNumber());
1239     return JSTaggedValue(static_cast<double>((highValue << byteLengthLow) | lowValue));
1240 }
1241 
WriteBytesValue(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,JSHandle<JSTaggedValue> & value,uint32_t offset,ByteLength byteLength,bool littleEndian)1242 JSTaggedValue JSAPIFastBuffer::WriteBytesValue(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer,
1243                                                JSHandle<JSTaggedValue> &value, uint32_t offset, ByteLength byteLength,
1244                                                bool littleEndian)
1245 {
1246     if (UNLIKELY(byteLength > SixBytes)) {
1247         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR,
1248                                                             "WriteInt or WriteUInt only support 1 byte to 6 bytes");
1249         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1250     }
1251     switch (byteLength) {
1252         case OneByte:
1253             return WriteUInt8(thread, buffer, value, offset, littleEndian);
1254         case TwoBytes:
1255             return WriteUInt16(thread, buffer, value, offset, littleEndian);
1256         case FourBytes:
1257             return WriteUInt32(thread, buffer, value, offset, littleEndian);
1258         default:
1259             break;
1260     }
1261     if (byteLength > FourBytes) {
1262         std::pair<JSTaggedValue, JSTaggedValue> valuePair = SplitUInt(value, ThreeBytes);
1263         if (valuePair.first == JSTaggedValue::Undefined()) {
1264             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR,
1265                                                                 "WriteInt or WriteUInt only support Integer Type");
1266             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1267         }
1268         JSHandle<JSTaggedValue> lowValue = JSHandle<JSTaggedValue>(thread, valuePair.first);
1269         JSHandle<JSTaggedValue> highValue = JSHandle<JSTaggedValue>(thread, valuePair.second);
1270         ByteLength highBytes = static_cast<ByteLength>(byteLength - ThreeBytes);
1271         if (littleEndian) {
1272             auto nextIndex = WriteBytesValue(thread, buffer, lowValue, offset, ThreeBytes, littleEndian);
1273             return WriteBytesValue(thread, buffer, highValue, nextIndex.GetInt(), highBytes, littleEndian);
1274         }
1275         auto nextIndex = WriteBytesValue(thread, buffer, highValue, offset, highBytes, littleEndian);
1276         return WriteBytesValue(thread, buffer, lowValue, nextIndex.GetInt(), ThreeBytes, littleEndian);
1277     }
1278     std::pair<JSTaggedValue, JSTaggedValue> valuePair = SplitUInt(value, TwoBytes);
1279     if (valuePair.first == JSTaggedValue::Undefined()) {
1280         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR,
1281                                                             "WriteInt or WriteUInt only support Integer Type");
1282         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1283     }
1284     JSHandle<JSTaggedValue> lowValue = JSHandle<JSTaggedValue>(thread, valuePair.first);
1285     JSHandle<JSTaggedValue> highValue = JSHandle<JSTaggedValue>(thread, valuePair.second);
1286     ByteLength highBytes = static_cast<ByteLength>(byteLength - TwoBytes);
1287     if (littleEndian) {
1288         auto nextIndex = WriteBytesValue(thread, buffer, lowValue, offset, TwoBytes, littleEndian);
1289         return WriteBytesValue(thread, buffer, highValue, nextIndex.GetInt(), highBytes, littleEndian);
1290     }
1291     auto nextIndex = WriteBytesValue(thread, buffer, highValue, offset, highBytes, littleEndian);
1292     return WriteBytesValue(thread, buffer, lowValue, nextIndex.GetInt(), TwoBytes, littleEndian);
1293 }
1294 
ReadBytes(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,uint32_t offset,ByteLength byteLength,bool littleEndian)1295 JSTaggedValue JSAPIFastBuffer::ReadBytes(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer, uint32_t offset,
1296                                          ByteLength byteLength, bool littleEndian)
1297 {
1298     if (UNLIKELY(byteLength > SixBytes || byteLength < OneByte)) {
1299         std::ostringstream oss;
1300         oss << "ReadInt or ReadUInt only support 1 byte to 6 bytes";
1301         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
1302         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1303     }
1304     switch (byteLength) {
1305         case OneByte:
1306             return ReadUInt8(thread, buffer, offset, littleEndian);
1307         case TwoBytes:
1308             return ReadUInt16(thread, buffer, offset, littleEndian);
1309         case FourBytes:
1310             return ReadUInt32(thread, buffer, offset, littleEndian);
1311         default:
1312             break;
1313     }
1314     if (byteLength > FourBytes) {
1315         auto valueLow = ReadBytes(thread, buffer, offset, ThreeBytes, littleEndian);
1316         ByteLength highBytes = static_cast<ByteLength>(byteLength - ThreeBytes);
1317         auto valueHigh = ReadBytes(thread, buffer, offset + ThreeBytes, highBytes, littleEndian);
1318         if (littleEndian) {
1319             return MergeUInt(valueLow, valueHigh, ThreeBytes);
1320         }
1321         return MergeUInt(valueHigh, valueLow, highBytes);
1322     }
1323     auto valueLow = ReadBytes(thread, buffer, offset, TwoBytes, littleEndian);
1324     ByteLength highBytes = static_cast<ByteLength>(byteLength - TwoBytes);
1325     auto valueHigh = ReadBytes(thread, buffer, offset + TwoBytes, highBytes, littleEndian);
1326     if (littleEndian) {
1327         return MergeUInt(valueLow, valueHigh, TwoBytes);
1328     }
1329     return MergeUInt(valueHigh, valueLow, highBytes);
1330 }
1331 
ReadInt(JSThread * thread,JSHandle<JSAPIFastBuffer> & buffer,uint32_t offset,ByteLength byteLength,bool littleEndian)1332 JSTaggedValue JSAPIFastBuffer::ReadInt(JSThread *thread, JSHandle<JSAPIFastBuffer> &buffer, uint32_t offset,
1333                                        ByteLength byteLength, bool littleEndian)
1334 {
1335     auto ret = ReadBytes(thread, buffer, offset, byteLength, littleEndian);
1336     int64_t value = ret.GetNumber();
1337     // 1 : calculate bit mask
1338     int64_t negetiveMask = (1LL << (byteLength * JSAPIFastBuffer::ONE_BYTE_BIT_LENGTH - 1));
1339 
1340     if (value & negetiveMask) {
1341         int64_t bitMask = negetiveMask | (negetiveMask - 1);
1342         bitMask &= -value;
1343         // -1 : to negetive
1344         return JSTaggedValue(JSTaggedNumber(JSTaggedValue(bitMask)) * JSTaggedNumber(-1));
1345     }
1346     return JSTaggedValue(value);
1347 }
1348 
WriteBigUInt64(JSThread * thread,const JSHandle<JSAPIFastBuffer> & buffer,const JSHandle<JSTaggedValue> & value,uint32_t offset,bool littleEndian)1349 JSTaggedValue JSAPIFastBuffer::WriteBigUInt64(JSThread *thread, const JSHandle<JSAPIFastBuffer> &buffer,
1350                                               const JSHandle<JSTaggedValue> &value, uint32_t offset, bool littleEndian)
1351 {
1352     JSType type = JSType::JS_BIGUINT64_ARRAY;
1353     auto byteSize = base::TypedArrayHelper::GetElementSize(type);
1354     JSHandle<JSTypedArray> typedArray =
1355         JSHandle<JSTypedArray>(thread, JSTypedArray::Cast(buffer->GetFastBufferData(thread).GetTaggedObject()));
1356     uint64_t valueNum;
1357     bool isLossLess;
1358     ASSERT(value->IsBigInt() || value->IsNumber() || value->IsBoolean());
1359     BigInt::BigIntToUint64(thread, value, &valueNum, &isLossLess);
1360     uint64_t left = 0;
1361     uint64_t right = UINT64_MAX;
1362     if (valueNum > right || valueNum < left) {
1363         std::ostringstream oss;
1364         oss << std::fixed << "The value of \"value\" is out of range. It must be >= " << left << " and <= " << right
1365             << ". Received value is: " << valueNum;
1366         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
1367         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1368     }
1369     if (offset < 0 || offset + NumberSize::BIGUINT64 > buffer->GetLength()) {
1370         std::ostringstream oss;
1371         oss << std::fixed << "The value of \"offset\" is out of range. It must be >= " << 0
1372             << " and <= " << buffer->GetLength() - NumberSize::BIGUINT64 << ". Received value is: " << offset;
1373         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
1374         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1375     }
1376     JSAPIFastBuffer::SetValueByIndex(thread, typedArray.GetTaggedValue(), offset, value.GetTaggedValue(), type,
1377                                      littleEndian);
1378     return JSTaggedValue(offset + byteSize);
1379 }
1380 
ReadBigUInt64(JSThread * thread,const JSHandle<JSAPIFastBuffer> & buffer,uint32_t offset,bool littleEndian)1381 JSTaggedValue JSAPIFastBuffer::ReadBigUInt64(JSThread *thread, const JSHandle<JSAPIFastBuffer> &buffer, uint32_t offset,
1382                                              bool littleEndian)
1383 {
1384     JSType type = JSType::JS_BIGUINT64_ARRAY;
1385     JSHandle<JSTypedArray> typedArray =
1386         JSHandle<JSTypedArray>(thread, JSTypedArray ::Cast(buffer->GetFastBufferData(thread).GetTaggedObject()));
1387     if (offset < 0 || offset + NumberSize::BIGUINT64 > buffer->GetLength()) {
1388         std::ostringstream oss;
1389         oss << std::fixed << "The value of \"offset\" is out of range. It must be >= " << 0
1390             << " and <= " << buffer->GetLength() - NumberSize::BIGUINT64 << ". Received value is: " << offset;
1391         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
1392         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1393     }
1394     return JSAPIFastBuffer::GetValueByIndex(thread, typedArray.GetTaggedValue(), offset, type, littleEndian);
1395 }
1396 
WriteBigInt64(JSThread * thread,const JSHandle<JSAPIFastBuffer> & buffer,const JSHandle<JSTaggedValue> & value,uint32_t offset,bool littleEndian)1397 JSTaggedValue JSAPIFastBuffer::WriteBigInt64(JSThread *thread, const JSHandle<JSAPIFastBuffer> &buffer,
1398                                              const JSHandle<JSTaggedValue> &value, uint32_t offset, bool littleEndian)
1399 {
1400     JSType type = JSType::JS_BIGINT64_ARRAY;
1401     auto byteSize = base::TypedArrayHelper::GetElementSize(type);
1402     JSHandle<JSTypedArray> typedArray =
1403         JSHandle<JSTypedArray>(thread, JSTypedArray ::Cast(buffer->GetFastBufferData(thread).GetTaggedObject()));
1404     int64_t valueNum;
1405     bool isLossLess;
1406     ASSERT(value->IsBigInt() || value->IsNumber() || value->IsBoolean());
1407     BigInt::BigIntToInt64(thread, value, &valueNum, &isLossLess);
1408     int64_t left = INT64_MIN;
1409     int64_t right = INT64_MAX;
1410     if (valueNum > right || valueNum < left) {
1411         std::ostringstream oss;
1412         oss << std::fixed << "The value of \"value\" is out of range. It must be >= " << left << " and <= " << right
1413             << ". Received value is: " << valueNum;
1414         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
1415         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1416     }
1417     if (offset < 0 || offset + NumberSize::BIGUINT64 > buffer->GetLength()) {
1418         std::ostringstream oss;
1419         oss << std::fixed << "The value of \"offset\" is out of range. It must be >= " << 0
1420             << " and <= " << buffer->GetLength() - NumberSize::BIGUINT64 << ". Received value is: " << offset;
1421         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
1422         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1423     }
1424     JSAPIFastBuffer::SetValueByIndex(thread, typedArray.GetTaggedValue(), offset, value.GetTaggedValue(), type,
1425                                      littleEndian);
1426     return JSTaggedValue(offset + byteSize);
1427 }
1428 
ReadBigInt64(JSThread * thread,const JSHandle<JSAPIFastBuffer> & buffer,uint32_t offset,bool littleEndian)1429 JSTaggedValue JSAPIFastBuffer::ReadBigInt64(JSThread *thread, const JSHandle<JSAPIFastBuffer> &buffer, uint32_t offset,
1430                                             bool littleEndian)
1431 {
1432     JSType type = JSType::JS_BIGINT64_ARRAY;
1433     JSHandle<JSTypedArray> typedArray =
1434         JSHandle<JSTypedArray>(thread, JSTypedArray ::Cast(buffer->GetFastBufferData(thread).GetTaggedObject()));
1435     if (offset < 0 || offset + NumberSize::BIGINT64 > buffer->GetLength()) {
1436         std::ostringstream oss;
1437         oss << std::fixed << "The value of \"offset\" is out of range. It must be >= " << 0
1438             << " and <= " << buffer->GetLength() - NumberSize::BIGINT64 << ". Received value is: " << offset;
1439         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
1440         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1441     }
1442     return JSAPIFastBuffer ::GetValueByIndex(thread, typedArray.GetTaggedValue(), offset, type, littleEndian);
1443 }
1444 }  // namespace panda::ecmascript
1445