1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ark_interop_napi.h"
17 #include "ark_interop_external.h"
18 #include "ark_interop_internal.h"
19 #include "ark_interop_macro.h"
20 #include "ark_interop_log.h"
21
ARKTS_CreateBigInt(ARKTS_Env env,int64_t value)22 ARKTS_Value ARKTS_CreateBigInt(ARKTS_Env env, int64_t value)
23 {
24 ARKTS_ASSERT_P(env, "env is null");
25
26 auto vm = P_CAST(env, panda::EcmaVM*);
27 auto result = panda::BigIntRef::New(vm, value);
28 return BIT_CAST(result, ARKTS_Value);
29 }
30
ReverseBytes(uint8_t dst[],size_t size)31 static bool ReverseBytes(uint8_t dst[], size_t size)
32 {
33 auto powOf2 = (size & 1) == 0;
34 if (!powOf2) {
35 return false;
36 }
37 auto half = size >> 1;
38 for (size_t i = 0;i < half; ++i) {
39 auto temp = dst[i];
40 dst[i] = dst[size - i - 1];
41 dst[size - i - 1] = temp;
42 }
43 return true;
44 }
45
46 constexpr int WORD_BYTES = sizeof(uint64_t) / sizeof(uint8_t);
47 constexpr int BYTE_BITS = 8;
48
ARKTS_CreateBigIntWithBytes(ARKTS_Env env,bool isNegative,int64_t size,const uint8_t bytes[])49 ARKTS_Value ARKTS_CreateBigIntWithBytes(ARKTS_Env env, bool isNegative, int64_t size, const uint8_t bytes[])
50 {
51 ARKTS_ASSERT_P(env, "env is null");
52 ARKTS_ASSERT_P(size != 0 && size <= int64_t(0xFFFF'FFFF) * WORD_BYTES, "size is invalid");
53 ARKTS_ASSERT_P(bytes, "bytes is null");
54
55 auto vm = P_CAST(env, panda::EcmaVM*);
56
57 auto firstBytes = size % WORD_BYTES;
58 auto wholeU64Cnt = size / WORD_BYTES;
59 auto totalCnt = firstBytes ? wholeU64Cnt + 1 : wholeU64Cnt;
60
61 std::vector<uint64_t> u64v;
62 u64v.resize(totalCnt);
63
64 int64_t wordStart = 0;
65 int64_t wordEnd = firstBytes ? firstBytes : WORD_BYTES;
66 for (int64_t index = totalCnt - 1;index >= 0; --index) {
67 uint64_t value = 0;
68 for (auto i = wordStart;i < wordEnd; ++i) {
69 value = (value << BYTE_BITS) | bytes[i];
70 }
71 u64v[index] = value;
72
73 wordStart = wordEnd;
74 wordEnd += WORD_BYTES;
75 }
76
77 auto result = panda::BigIntRef::CreateBigWords(vm, isNegative, totalCnt, u64v.data());
78 return BIT_CAST(result, ARKTS_Value);
79 }
80
ARKTS_IsBigInt(ARKTS_Env env,ARKTS_Value value)81 bool ARKTS_IsBigInt(ARKTS_Env env, ARKTS_Value value)
82 {
83 auto tag = BIT_CAST(value, panda::JSValueRef);
84 if (!tag.IsHeapObject()) {
85 return false;
86 }
87 tag = *P_CAST(value, panda::JSValueRef*);
88 auto vm = P_CAST(env, panda::EcmaVM*);
89 return tag.IsBigInt(vm);
90 }
91
ARKTS_BigIntGetByteSize(ARKTS_Env env,ARKTS_Value value)92 int64_t ARKTS_BigIntGetByteSize(ARKTS_Env env, ARKTS_Value value)
93 {
94 ARKTS_ASSERT_I(ARKTS_IsBigInt(env, value), "value is not bigint");
95 auto vm = P_CAST(env, panda::EcmaVM*);
96
97 auto bigint = P_CAST(value, panda::BigIntRef*);
98 return bigint->GetWordsArraySize(vm) * WORD_BYTES;
99 }
100
ARKTS_BigIntReadBytes(ARKTS_Env env,ARKTS_Value value,bool * isNegative,int64_t byteCount,uint8_t bytes[])101 void ARKTS_BigIntReadBytes(ARKTS_Env env, ARKTS_Value value, bool* isNegative, int64_t byteCount, uint8_t bytes[])
102 {
103 ARKTS_ASSERT_V(bytes, "bytes is null");
104 ARKTS_ASSERT_V(ARKTS_IsBigInt(env, value), "value is not bigint");
105 auto vm = P_CAST(env, panda::EcmaVM*);
106
107 auto bigint = BIT_CAST(value, panda::Local<panda::BigIntRef>);
108 auto u64cnt = bigint->GetWordsArraySize(vm);
109 ARKTS_ASSERT_V(byteCount >= u64cnt * WORD_BYTES, "byteCount not enough");
110 bigint->GetWordsArray(vm, isNegative, u64cnt, reinterpret_cast<uint64_t*>(bytes));
111 ARKTS_ASSERT_V(ReverseBytes(bytes, byteCount), "ReverseBytes failed");
112 }