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 }