1/*
2 * Copyright (c) 2022 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 "js_base64.h"
17#include <cstring>
18#include <sys/types.h>
19#include "securec.h"
20#include "napi/native_api.h"
21#include "napi/native_node_api.h"
22#include "tools/log.h"
23
24namespace OHOS::Util {
25    namespace {
26        static const size_t TRAGET_TWO = 2;
27        static const size_t TRAGET_THREE = 3;
28        static const size_t TRAGET_FOUR = 4;
29        static const size_t TRAGET_SIX = 6;
30        static const size_t TRAGET_EIGHT = 8;
31        static const size_t TRAGET_SIXTYFIVE = 65;
32        const char BASE[] = {
33            65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
34            83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105,
35            106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
36            121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 61
37        };
38
39        const char BASEURL[] = {
40            65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
41            83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105,
42            106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
43            121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95
44        };
45    }
46
47    /* base64 encode */
48    napi_value Base64::EncodeSync(napi_env env, napi_value src, Type valueType)
49    {
50        napi_typedarray_type type;
51        size_t length = 0;
52        void *resultData = nullptr;
53        napi_get_typedarray_info(env, src, &type, &length, &resultData, nullptr, nullptr);
54        if (type != napi_uint8_array || length == 0) {
55            napi_throw_error(env, "401",
56                "Parameter error. The type of Parameter must be Uint8Array and the length greater than zero.");
57            return nullptr;
58        }
59        inputEncode_ = static_cast<const unsigned char*>(resultData);
60        unsigned char *rets = EncodeAchieve(inputEncode_, length, valueType);
61        if (rets == nullptr) {
62            napi_throw_error(env, "-1", "encode input is null");
63            return nullptr;
64        }
65        void *data = nullptr;
66        napi_value arrayBuffer = nullptr;
67        size_t bufferSize = outputLen;
68        napi_create_arraybuffer(env, bufferSize, &data, &arrayBuffer);
69        if (memcpy_s(data, bufferSize, reinterpret_cast<const void*>(rets), bufferSize) != EOK) {
70            FreeMemory(rets);
71            HILOG_ERROR("copy ret to arraybuffer error");
72            return nullptr;
73        }
74        napi_value result = nullptr;
75        napi_create_typedarray(env, napi_uint8_array, bufferSize, arrayBuffer, 0, &result);
76        FreeMemory(rets);
77        return result;
78    }
79
80    /* base64 encodeToString */
81    napi_value Base64::EncodeToStringSync(napi_env env, napi_value src, Type valueType)
82    {
83        napi_typedarray_type type;
84        size_t length = 0;
85        void *resultData = nullptr;
86        napi_get_typedarray_info(env, src, &type, &length, &resultData, nullptr, nullptr);
87        if (type != napi_uint8_array || length == 0) {
88            napi_throw_error(env, "401",
89                "Parameter error. The type of Parameter must be Uint8Array and the length greater than zero.");
90            return nullptr;
91        }
92        inputEncode_ = static_cast<const unsigned char*>(resultData);
93        unsigned char *ret = EncodeAchieve(inputEncode_, length, valueType);
94        if (ret == nullptr) {
95            FreeMemory(ret);
96            napi_throw_error(env, "-1", "encodeToString input is null");
97            return nullptr;
98        }
99        const char *encString = reinterpret_cast<const char*>(ret);
100        napi_value resultStr = nullptr;
101        napi_create_string_utf8(env, encString, strlen(encString), &resultStr);
102        FreeMemory(ret);
103        return resultStr;
104    }
105
106    unsigned char *Base64::EncodeAchieve(const unsigned char *input, size_t inputLen, Type valueType)
107    {
108        unsigned char *ret = nullptr;
109        outputLen = (inputLen / TRAGET_THREE) * TRAGET_FOUR;
110        if ((inputLen % TRAGET_THREE) > 0) {
111            outputLen += TRAGET_FOUR;
112        }
113        if (outputLen > 0) {
114            ret = new (std::nothrow) unsigned char[outputLen + 1];
115            if (ret == nullptr) {
116                HILOG_ERROR("Base64:: ret is nullptr");
117                return nullptr;
118            }
119            if (memset_s(ret, outputLen + 1, '\0', outputLen + 1) != EOK) {
120                HILOG_ERROR("encode ret memset_s failed");
121                FreeMemory(ret);
122                return nullptr;
123            }
124        } else {
125            HILOG_ERROR("outputLen is error");
126            return nullptr;
127        }
128        if (ret == nullptr) {
129            return ret;
130        }
131
132        bool flag = false;
133        if (valueType == Type::BASIC_URL_SAFE || valueType == Type::MIME_URL_SAFE) {
134            flag = true;
135        }
136        const char *searchArray = flag ? BASEURL : BASE;
137        unsigned char *result = EncodeAchieveInner(input, ret, searchArray, inputLen, valueType);
138        return result;
139    }
140
141    unsigned char *Base64::EncodeAchieveInner(const unsigned char *input, unsigned char *ret,
142                                              const char *searchArray, size_t inputLen, Type valueType)
143    {
144        size_t inp = 0;
145        size_t temp = 0;
146        size_t bitWise = 0;
147        size_t index = 0;
148        while (inp < inputLen) {
149            temp = 0;
150            bitWise = 0;
151            while (temp < TRAGET_THREE) {
152                if (inp >= inputLen) {
153                    break;
154                }
155                bitWise = ((bitWise << TRAGET_EIGHT) | (input[inp] & XFF_FLG));
156                inp++;
157                temp++;
158            }
159            bitWise = (bitWise << ((TRAGET_THREE - temp) * TRAGET_EIGHT));
160            for (size_t i = 0; i < TRAGET_FOUR; i++) {
161                if (temp < i && (valueType == Type::BASIC_URL_SAFE || valueType == Type::MIME_URL_SAFE)) {
162                    outputLen -= (temp == 1) ? TRAGET_TWO : 1;
163                    break;
164                } else if (temp < i && valueType != Type::BASIC_URL_SAFE && valueType != Type::MIME_URL_SAFE) {
165                    ret[index++] = searchArray[BIT_FLG];
166                } else {
167                    ret[index++] = searchArray[(bitWise >> ((TRAGET_THREE - i) * TRAGET_SIX)) & SIXTEEN_FLG];
168                }
169            }
170        }
171        ret[index] = 0;
172        return ret;
173    }
174
175    /* base64 decode */
176    napi_value Base64::DecodeSync(napi_env env, napi_value src, Type valueType)
177    {
178        bool resDecode = DecodeSyncInner(env, src, valueType);
179        if (!resDecode || pret == nullptr) {
180            return nullptr;
181        }
182        void *data = nullptr;
183        napi_value arrayBuffer = nullptr;
184        size_t bufferSize = decodeOutLen;
185        napi_create_arraybuffer(env, bufferSize, &data, &arrayBuffer);
186        if (memcpy_s(data, bufferSize, reinterpret_cast<const void*>(pret), bufferSize) != EOK) {
187            FreeMemory(pret);
188            HILOG_ERROR("copy retDecode to arraybuffer error");
189            return nullptr;
190        }
191        napi_value result = nullptr;
192        napi_create_typedarray(env, napi_uint8_array, bufferSize, arrayBuffer, 0, &result);
193        FreeMemory(pret);
194        return result;
195    }
196
197    bool Base64::DecodeSyncInner(napi_env env, napi_value src, Type valueType)
198    {
199        napi_valuetype valuetype = napi_undefined;
200        napi_typeof(env, src, &valuetype);
201        napi_typedarray_type type;
202        size_t length = 0;
203        void *resultData = nullptr;
204        char *inputString = nullptr;
205        if (valuetype != napi_valuetype::napi_string) {
206            napi_get_typedarray_info(env, src, &type, &length, &resultData, nullptr, nullptr);
207        }
208        if (valuetype == napi_valuetype::napi_string) {
209            size_t prolen = 0;
210            napi_get_value_string_utf8(env, src, nullptr, 0, &prolen);
211            if (prolen > 0) {
212                inputString = new (std::nothrow) char[prolen + 1];
213                if (inputString == nullptr) {
214                    HILOG_ERROR("inputString is nullptr");
215                    return false;
216                }
217                if (memset_s(inputString, prolen + 1, '\0', prolen + 1) != EOK) {
218                    FreeMemory(inputString);
219                    napi_throw_error(env, "-1", "decode inputString memset_s failed");
220                    return false;
221                }
222            } else {
223                napi_throw_error(env, "-2", "prolen is error !");
224                return false;
225            }
226            if (inputString != nullptr) {
227                napi_get_value_string_utf8(env, src, inputString, prolen + 1, &prolen);
228                pret = DecodeAchieve(env, inputString, prolen, valueType);
229            }
230        } else if (type == napi_typedarray_type::napi_uint8_array && length > 0) {
231            inputDecode_ = static_cast<const char*>(resultData);
232            pret = DecodeAchieve(env, inputDecode_, length, valueType);
233        } else {
234            std::string errMsg =
235                "Parameter error. The type of Parameter must be Uint8Array or string and the length greater than 0.";
236            napi_throw_error(env, "401", errMsg.c_str());
237            return false;
238        }
239        FreeMemory(inputString);
240        return true;
241    }
242
243    unsigned char *Base64::DecodeAchieve(napi_env env, const char *input, size_t inputLen, Type valueType)
244    {
245        retLen = (inputLen / TRAGET_FOUR) * TRAGET_THREE;
246        decodeOutLen = retLen;
247        size_t equalCount = 0;
248
249        if (*(input + inputLen - 1) == '=') {
250            equalCount++;
251        }
252        if (*(input + inputLen - TRAGET_TWO) == '=') {
253            equalCount++;
254        }
255        retLen = DecodeOut(equalCount, retLen);
256        if (retLen > 0) {
257            retDecode = new (std::nothrow) unsigned char[retLen + 1];
258            if (retDecode == nullptr) {
259                HILOG_ERROR("retDecode is nullptr");
260                return nullptr;
261            }
262            if (memset_s(retDecode, retLen + 1, '\0', retLen + 1) != EOK) {
263                FreeMemory(retDecode);
264                napi_throw_error(env, "-1", "decode retDecode memset_s failed");
265                return nullptr;
266            }
267        } else {
268            napi_throw_error(env, "-2", "retLen is error !");
269            return nullptr;
270        }
271        if (retDecode == nullptr) {
272            return retDecode;
273        }
274        if (valueType == Type::BASIC_URL_SAFE || valueType == Type::MIME_URL_SAFE) {
275            size_t remainder = inputLen % TRAGET_FOUR;
276            if (remainder == TRAGET_TWO) {
277                decodeOutLen += 1;
278            } else if (remainder == TRAGET_THREE) {
279                decodeOutLen += TRAGET_TWO;
280            }
281        }
282        unsigned char *result = nullptr;
283        result = DecodeAchieveInner(env, input, inputLen, equalCount, valueType);
284        if (result == nullptr) {
285            FreeMemory(retDecode);
286        }
287        return result;
288    }
289
290    unsigned char *Base64::DecodeAchieveInner(napi_env env, const char *input,
291                                              size_t inputLen, size_t equalCount, Type valueType)
292    {
293        size_t index = 0;
294        size_t inp = 0;
295        size_t temp = 0;
296        size_t bitWise = 0;
297        while (inp < (inputLen - equalCount)) {
298            temp = 0;
299            bitWise = 0;
300            while (temp < TRAGET_FOUR) {
301                if (inp >= (inputLen - equalCount)) {
302                    break;
303                }
304                int findsData = Finds(env, input[inp], valueType);
305                if (findsData == -1) {
306                    return nullptr;
307                }
308                bitWise = (bitWise << TRAGET_SIX) | static_cast<size_t>(findsData);
309                inp++;
310                temp++;
311            }
312            bitWise = bitWise << ((TRAGET_FOUR - temp) * TRAGET_SIX);
313            for (size_t i = 0; i < TRAGET_THREE; i++) {
314                if (i == temp) {
315                    break;
316                }
317                retDecode[index++] = static_cast<char>((bitWise >> ((TRAGET_TWO - i) * TRAGET_EIGHT)) & XFF_FLG);
318            }
319        }
320        retDecode[index] = 0;
321        return retDecode;
322    }
323
324    size_t Base64::DecodeOut(size_t equalCount, size_t retLen)
325    {
326        size_t temp = retLen;
327        switch (equalCount) {
328            case 0:
329                temp += TRAGET_FOUR;
330                break;
331            case 1:
332                temp += TRAGET_FOUR;
333                decodeOutLen -= 1;
334                break;
335            case TRAGET_TWO:
336                temp += TRAGET_THREE;
337                decodeOutLen -= TRAGET_TWO;
338                break;
339            default:
340                temp += TRAGET_TWO;
341                break;
342        }
343        return temp;
344    }
345
346    /* Decoding lookup function */
347    int Base64::Finds(napi_env env, char ch, Type valueType)
348    {
349        bool flag = false;
350        if (valueType == Type::BASIC_URL_SAFE || valueType == Type::MIME_URL_SAFE) {
351            flag = true;
352        }
353        int tableLen = flag ? TRAGET_SIXTYFIVE - 1 : TRAGET_SIXTYFIVE;
354        const char *searchArray = flag ? BASEURL : BASE;
355        for (int i = 0; i < tableLen; i++) {
356            if (searchArray[i] == ch) {
357                return i;
358            }
359        }
360        napi_throw_error(env, "-1", "The input string contains unsupported characters");
361        return -1;
362    }
363
364    napi_value Base64::Encode(napi_env env, napi_value src, Type valueType)
365    {
366        napi_typedarray_type type;
367        size_t length = 0;
368        void *resultData = nullptr;
369        napi_get_typedarray_info(env, src, &type, &length, &resultData, nullptr, nullptr);
370        if (type != napi_uint8_array || length == 0) {
371            napi_throw_error(env, "401",
372                "Parameter error. The type of Parameter must be Uint8Array and the length greater than zero.");
373            return nullptr;
374        }
375        unsigned char *inputEncode = nullptr;
376        inputEncode = static_cast<unsigned char*>(resultData);
377        CreateEncodePromise(env, inputEncode, length, valueType);
378        return stdEncodeInfo_->promise;
379    }
380
381    napi_value Base64::EncodeToString(napi_env env, napi_value src, Type valueType)
382    {
383        napi_typedarray_type type;
384        size_t length = 0;
385        void *resultData = nullptr;
386        napi_get_typedarray_info(env, src, &type, &length, &resultData, nullptr, nullptr);
387        if (type != napi_uint8_array || length == 0) {
388            napi_throw_error(env, "401",
389                "Parameter error. The type of Parameter must be Uint8Array and the length greater than zero.");
390            return nullptr;
391        }
392        unsigned char *inputEncode = nullptr;
393        inputEncode = static_cast<unsigned char*>(resultData);
394        CreateEncodeToStringPromise(env, inputEncode, length, valueType);
395        return stdEncodeInfo_->promise;
396    }
397
398    void Base64::CreateEncodePromise(napi_env env, unsigned char *inputDecode, size_t length, Type valueType)
399    {
400        napi_value resourceName = nullptr;
401        stdEncodeInfo_ = new (std::nothrow) EncodeInfo();
402        if (stdEncodeInfo_ == nullptr) {
403            HILOG_ERROR("stdEncodeInfo_ is nullptr");
404            return;
405        }
406        stdEncodeInfo_->sinputEncode = inputDecode;
407        stdEncodeInfo_->slength = length;
408        stdEncodeInfo_->env = env;
409        stdEncodeInfo_->valueType = valueType;
410        napi_create_promise(env, &stdEncodeInfo_->deferred, &stdEncodeInfo_->promise);
411        napi_create_string_utf8(env, "ReadStdEncode", NAPI_AUTO_LENGTH, &resourceName);
412        napi_create_async_work(env, nullptr, resourceName, ReadStdEncode, EndStdEncode,
413                               reinterpret_cast<void*>(stdEncodeInfo_), &stdEncodeInfo_->worker);
414        napi_queue_async_work_with_qos(env, stdEncodeInfo_->worker, napi_qos_user_initiated);
415    }
416
417    void Base64::CreateEncodeToStringPromise(napi_env env, unsigned char *inputDecode, size_t length, Type valueType)
418    {
419        napi_value resourceName = nullptr;
420        stdEncodeInfo_ = new EncodeInfo();
421        stdEncodeInfo_->sinputEncode = inputDecode;
422        stdEncodeInfo_->slength = length;
423        stdEncodeInfo_->valueType = valueType;
424        napi_create_promise(env, &stdEncodeInfo_->deferred, &stdEncodeInfo_->promise);
425        napi_create_string_utf8(env, "ReadStdEncodeToString", NAPI_AUTO_LENGTH, &resourceName);
426        napi_create_async_work(env, nullptr, resourceName, ReadStdEncodeToString, EndStdEncodeToString,
427                               reinterpret_cast<void*>(stdEncodeInfo_), &stdEncodeInfo_->worker);
428        napi_queue_async_work_with_qos(env, stdEncodeInfo_->worker, napi_qos_user_initiated);
429    }
430
431    unsigned char *EncodeAchieves(napi_env env, EncodeInfo *encodeInfo)
432    {
433        const unsigned char *input = encodeInfo->sinputEncode;
434        size_t inputLen = encodeInfo->slength;
435        unsigned char *ret = nullptr;
436
437        size_t outputLen = 0;
438        outputLen = (inputLen / TRAGET_THREE) * TRAGET_FOUR;
439        if ((inputLen % TRAGET_THREE) > 0) {
440            outputLen += TRAGET_FOUR;
441        }
442        encodeInfo->soutputLen = outputLen;
443        if (outputLen > 0) {
444            ret = new unsigned char[outputLen + 1];
445            if (memset_s(ret, outputLen + 1, '\0', outputLen + 1) != EOK) {
446                FreeMemory(ret);
447                napi_throw_error(encodeInfo->env, "-1", "ret path memset_s failed");
448                return nullptr;
449            }
450        } else {
451            napi_throw_error(encodeInfo->env, "-2", "outputLen is error !");
452            return nullptr;
453        }
454        if (ret == nullptr) {
455            return ret;
456        }
457
458        bool flag = false;
459        if (encodeInfo->valueType == Type::BASIC_URL_SAFE || encodeInfo->valueType == Type::MIME_URL_SAFE) {
460            flag = true;
461        }
462        const char *searchArray = flag ? BASEURL : BASE;
463        unsigned char *result = nullptr;
464        result = EncodeAchievesInner(ret, encodeInfo, searchArray, inputLen, input);
465        return result;
466    }
467
468    unsigned char *EncodeAchievesInner(unsigned char *ret, EncodeInfo *encodeInfo,
469                                       const char *searchArray, size_t inputLen, const unsigned char *input)
470    {
471        size_t inp = 0;
472        size_t temp = 0;
473        size_t bitWise = 0;
474        size_t index = 0;
475        while (inp < inputLen) {
476            temp = 0;
477            bitWise = 0;
478            while (temp < TRAGET_THREE) {
479                if (inp >= inputLen) {
480                    break;
481                }
482                bitWise = ((bitWise << TRAGET_EIGHT) | (input[inp] & XFF_FLG));
483                inp++;
484                temp++;
485            }
486            bitWise = (bitWise << ((TRAGET_THREE - temp) * TRAGET_EIGHT));
487            for (size_t i = 0; i < TRAGET_FOUR; i++) {
488                if (temp < i &&
489                    (encodeInfo->valueType == Type::BASIC_URL_SAFE || encodeInfo->valueType == Type::MIME_URL_SAFE)) {
490                    encodeInfo->soutputLen -= (temp == 1) ? TRAGET_TWO : 1;
491                    break;
492                } else if (temp < i &&
493                    (encodeInfo->valueType != Type::BASIC_URL_SAFE && encodeInfo->valueType != Type::MIME_URL_SAFE)) {
494                    ret[index++] = searchArray[BIT_FLG];
495                } else {
496                    ret[index++] = searchArray[(bitWise >> ((TRAGET_THREE - i) * TRAGET_SIX)) & SIXTEEN_FLG];
497                }
498            }
499        }
500        ret[index] = 0;
501        return ret;
502    }
503
504    void Base64::ReadStdEncode(napi_env env, void *data)
505    {
506        auto stdEncodeInfo = reinterpret_cast<EncodeInfo*>(data);
507        unsigned char *rets = EncodeAchieves(env, stdEncodeInfo);
508        stdEncodeInfo->sinputEncoding = rets;
509    }
510
511    void Base64::EndStdEncode(napi_env env, napi_status status, void *buffer)
512    {
513        auto stdEncodeInfo = reinterpret_cast<EncodeInfo*>(buffer);
514        void *data = nullptr;
515        napi_handle_scope scope = nullptr;
516        napi_open_handle_scope(env, &scope);
517        if (scope == nullptr) {
518            return;
519        }
520        napi_value arrayBuffer = nullptr;
521        size_t bufferSize = stdEncodeInfo->soutputLen;
522        napi_create_arraybuffer(env, bufferSize, &data, &arrayBuffer);
523        if (memcpy_s(data, bufferSize,
524            reinterpret_cast<const void*>(stdEncodeInfo->sinputEncoding), bufferSize) != EOK) {
525            HILOG_ERROR("copy ret to arraybuffer error");
526            napi_delete_async_work(env, stdEncodeInfo->worker);
527            return;
528        }
529        napi_value result = nullptr;
530        napi_create_typedarray(env, napi_uint8_array, bufferSize, arrayBuffer, 0, &result);
531        napi_resolve_deferred(env, stdEncodeInfo->deferred, result);
532        napi_delete_async_work(env, stdEncodeInfo->worker);
533        napi_close_handle_scope(env, scope);
534        delete[] stdEncodeInfo->sinputEncoding;
535        delete stdEncodeInfo;
536    }
537
538    void Base64::ReadStdEncodeToString(napi_env env, void *data)
539    {
540        auto stdEncodeInfo = reinterpret_cast<EncodeInfo*>(data);
541        unsigned char *rets = EncodeAchieves(env, stdEncodeInfo);
542        stdEncodeInfo->sinputEncoding = rets;
543    }
544
545    void Base64::EndStdEncodeToString(napi_env env, napi_status status, void *buffer)
546    {
547        auto stdEncodeInfo = reinterpret_cast<EncodeInfo*>(buffer);
548        napi_handle_scope scope = nullptr;
549        napi_open_handle_scope(env, &scope);
550        if (scope == nullptr) {
551            return;
552        }
553        const char *encString = reinterpret_cast<const char*>(stdEncodeInfo->sinputEncoding);
554        napi_value resultStr = nullptr;
555        napi_create_string_utf8(env, encString, strlen(encString), &resultStr);
556        napi_resolve_deferred(env, stdEncodeInfo->deferred, resultStr);
557        napi_delete_async_work(env, stdEncodeInfo->worker);
558        napi_close_handle_scope(env, scope);
559        delete[] stdEncodeInfo->sinputEncoding;
560        delete stdEncodeInfo;
561    }
562
563    napi_value Base64::Decode(napi_env env, napi_value src, Type valueType)
564    {
565        napi_valuetype valuetype = napi_undefined;
566        napi_typeof(env, src, &valuetype);
567        napi_typedarray_type type;
568        size_t length = 0;
569        void *resultData = nullptr;
570        char *inputString = nullptr;
571        char *inputDecode = nullptr;
572        if (valuetype != napi_valuetype::napi_string) {
573            if (napi_get_typedarray_info(env, src, &type, &length, &resultData, nullptr, nullptr) != napi_ok) {
574                std::string errMsg =
575                    "Parameter error. The type of Parameter must be Uint8Array or string.";
576                napi_throw_error(env, "401", errMsg.c_str());
577                return nullptr;
578            }
579        }
580        if (valuetype == napi_valuetype::napi_string) {
581            size_t prolen = 0;
582            napi_get_value_string_utf8(env, src, nullptr, 0, &prolen);
583            if (prolen > 0) {
584                inputString = new char[prolen + 1];
585                if (memset_s(inputString, prolen + 1, '\0', prolen + 1) != EOK) {
586                    napi_throw_error(env, "-1", "decode inputString memset_s failed");
587                    return nullptr;
588                }
589            } else {
590                napi_throw_error(env, "-2", "prolen is error !");
591                return nullptr;
592            }
593            napi_get_value_string_utf8(env, src, inputString, prolen + 1, &prolen);
594            CreateDecodePromise(env, inputString, prolen, valueType);
595        } else if (type == napi_typedarray_type::napi_uint8_array && length > 0) {
596            inputDecode = static_cast<char*>(resultData);
597            CreateDecodePromise(env, inputDecode, length, valueType);
598        } else {
599            std::string errMsg =
600                "Parameter error. The type of Parameter must be Uint8Array or string and the length greater than 0.";
601            napi_throw_error(env, "401", errMsg.c_str());
602            FreeMemory(inputString);
603            return nullptr;
604        }
605        return stdDecodeInfo_->promise;
606    }
607
608    void Base64::CreateDecodePromise(napi_env env, char *inputDecode, size_t length, Type valueType)
609    {
610        napi_value resourceName = nullptr;
611        stdDecodeInfo_ = new DecodeInfo();
612        stdDecodeInfo_->sinputDecode = inputDecode;
613        stdDecodeInfo_->slength = length;
614        stdDecodeInfo_->env = env;
615        stdDecodeInfo_->valueType = valueType;
616        napi_create_promise(env, &stdDecodeInfo_->deferred, &stdDecodeInfo_->promise);
617        napi_create_string_utf8(env, "ReadStdDecode", NAPI_AUTO_LENGTH, &resourceName);
618        napi_create_async_work(env, nullptr, resourceName, ReadStdDecode, EndStdDecode,
619                               reinterpret_cast<void*>(stdDecodeInfo_), &stdDecodeInfo_->worker);
620        napi_queue_async_work_with_qos(env, stdDecodeInfo_->worker, napi_qos_user_initiated);
621    }
622
623    int Finds(char ch, Type valueType)
624    {
625        bool flag = false;
626        if (valueType == Type::BASIC_URL_SAFE || valueType == Type::MIME_URL_SAFE) {
627            flag = true;
628        }
629        int tableLen = flag ? TRAGET_SIXTYFIVE - 1 : TRAGET_SIXTYFIVE;
630        const char *searchArray = flag ? BASEURL : BASE;
631        int couts = 0;
632        for (int i = 0; i < tableLen; i++) {
633            if (searchArray[i] == ch) {
634                couts = i;
635            }
636        }
637        return couts;
638    }
639
640    size_t DecodeOut(size_t equalCount, size_t retLen, DecodeInfo *decodeInfo)
641    {
642        switch (equalCount) {
643            case 0:
644                retLen += TRAGET_FOUR;
645                break;
646            case 1:
647                retLen += TRAGET_FOUR;
648                decodeInfo->decodeOutLen -= 1;
649                break;
650            case TRAGET_TWO:
651                retLen += TRAGET_THREE;
652                decodeInfo->decodeOutLen -= TRAGET_TWO;
653                break;
654            default:
655                retLen += TRAGET_TWO;
656                break;
657        }
658        return retLen;
659    }
660
661    unsigned char *DecodeAchieves(napi_env env, DecodeInfo *decodeInfo)
662    {
663        const char *input = decodeInfo->sinputDecode;
664        size_t inputLen = decodeInfo->slength;
665        size_t retLen = 0;
666        retLen = (inputLen / TRAGET_FOUR) * TRAGET_THREE;
667        decodeInfo->decodeOutLen = retLen;
668        size_t equalCount = 0;
669        unsigned char *retDecode = nullptr;
670        if (*(input + inputLen - 1) == '=') {
671            equalCount++;
672        }
673        if (*(input + inputLen - TRAGET_TWO) == '=') {
674            equalCount++;
675        }
676        retLen = DecodeOut(equalCount, retLen, decodeInfo);
677        if (retLen > 0) {
678            retDecode = new unsigned char[retLen + 1];
679            if (memset_s(retDecode, retLen + 1, '\0', retLen + 1) != EOK) {
680                FreeMemory(retDecode);
681                napi_throw_error(decodeInfo->env, "-1", "decode retDecode memset_s failed");
682                return nullptr;
683            }
684        } else {
685            napi_throw_error(decodeInfo->env, "-2", "retLen is error !");
686            return nullptr;
687        }
688        if (decodeInfo->valueType == Type::BASIC_URL_SAFE || decodeInfo->valueType == Type::MIME_URL_SAFE) {
689            size_t remainder = inputLen % TRAGET_FOUR;
690            if (remainder == TRAGET_TWO) {
691                decodeInfo->decodeOutLen += 1;
692            } else if (remainder == TRAGET_THREE) {
693                decodeInfo->decodeOutLen += TRAGET_TWO;
694            }
695        }
696
697        unsigned char *result = nullptr;
698        result = DecodeAchievesInner(inputLen, equalCount, input, decodeInfo, retDecode);
699        if (result == nullptr) {
700            FreeMemory(retDecode);
701        }
702        return result;
703    }
704
705    unsigned char *DecodeAchievesInner(size_t inputLen, size_t equalCount,
706                                       const char *input, DecodeInfo *decodeInfo, unsigned char *retDecode)
707    {
708        size_t inp = 0;
709        size_t temp = 0;
710        size_t bitWise = 0;
711        size_t index = 0;
712        while (inp < (inputLen - equalCount)) {
713            temp = 0;
714            bitWise = 0;
715            while (temp < TRAGET_FOUR) {
716                if (inp >= (inputLen - equalCount)) {
717                    break;
718                }
719                int findData = Finds(input[inp], decodeInfo->valueType);
720                if (findData == -1) {
721                    return nullptr;
722                }
723                bitWise = (bitWise << TRAGET_SIX) | static_cast<size_t>(findData);
724                inp++;
725                temp++;
726            }
727            bitWise = bitWise << ((TRAGET_FOUR - temp) * TRAGET_SIX);
728            for (size_t i = 0; i < TRAGET_THREE; i++) {
729                if (i == temp) {
730                    break;
731                }
732                retDecode[index++] = static_cast<char>((bitWise >> ((TRAGET_TWO - i) * TRAGET_EIGHT)) & XFF_FLG);
733            }
734        }
735        retDecode[index] = 0;
736        return retDecode;
737    }
738
739    void Base64::ReadStdDecode(napi_env env, void *data)
740    {
741        auto stdDecodeInfo = reinterpret_cast<DecodeInfo*>(data);
742        unsigned char *rets = DecodeAchieves(env, stdDecodeInfo);
743        stdDecodeInfo->sinputDecoding = rets;
744    }
745    void Base64::EndStdDecode(napi_env env, napi_status status, void *buffer)
746    {
747        auto stdDecodeInfo = reinterpret_cast<DecodeInfo*>(buffer);
748        void *data = nullptr;
749        napi_handle_scope scope = nullptr;
750        napi_open_handle_scope(env, &scope);
751        if (scope == nullptr) {
752            return;
753        }
754        napi_value arrayBuffer = nullptr;
755        size_t bufferSize = stdDecodeInfo->decodeOutLen;
756        napi_create_arraybuffer(env, bufferSize, &data, &arrayBuffer);
757        if (memcpy_s(data, bufferSize,
758            reinterpret_cast<const void*>(stdDecodeInfo->sinputDecoding), bufferSize) != EOK) {
759            HILOG_ERROR("copy ret to arraybuffer error");
760            napi_delete_async_work(env, stdDecodeInfo->worker);
761            return;
762        }
763        napi_value result = nullptr;
764        napi_create_typedarray(env, napi_uint8_array, bufferSize, arrayBuffer, 0, &result);
765        napi_resolve_deferred(env, stdDecodeInfo->deferred, result);
766        napi_delete_async_work(env, stdDecodeInfo->worker);
767        napi_close_handle_scope(env, scope);
768        delete[] stdDecodeInfo->sinputDecoding;
769        delete stdDecodeInfo;
770    }
771
772    /* Memory cleanup function */
773    void FreeMemory(char *&address)
774    {
775        if (address != nullptr) {
776            delete[] address;
777            address = nullptr;
778        }
779    }
780    void FreeMemory(unsigned char *&address)
781    {
782        if (address != nullptr) {
783            delete[] address;
784            address = nullptr;
785        }
786    }
787}
788