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