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 
24 namespace 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 */
EncodeSync(napi_env env, napi_value src, Type valueType)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 */
EncodeToStringSync(napi_env env, napi_value src, Type valueType)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 
EncodeAchieve(const unsigned char *input, size_t inputLen, Type valueType)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 
EncodeAchieveInner(const unsigned char *input, unsigned char *ret, const char *searchArray, size_t inputLen, Type valueType)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 */
DecodeSync(napi_env env, napi_value src, Type valueType)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 
DecodeSyncInner(napi_env env, napi_value src, Type valueType)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 
DecodeAchieve(napi_env env, const char *input, size_t inputLen, Type valueType)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 
DecodeAchieveInner(napi_env env, const char *input, size_t inputLen, size_t equalCount, Type valueType)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 
DecodeOut(size_t equalCount, size_t retLen)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 */
Finds(napi_env env, char ch, Type valueType)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 
Encode(napi_env env, napi_value src, Type valueType)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 
EncodeToString(napi_env env, napi_value src, Type valueType)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 
CreateEncodePromise(napi_env env, unsigned char *inputDecode, size_t length, Type valueType)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 
CreateEncodeToStringPromise(napi_env env, unsigned char *inputDecode, size_t length, Type valueType)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 
EncodeAchieves(napi_env env, EncodeInfo *encodeInfo)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 
EncodeAchievesInner(unsigned char *ret, EncodeInfo *encodeInfo, const char *searchArray, size_t inputLen, const unsigned char *input)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 
ReadStdEncode(napi_env env, void *data)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 
EndStdEncode(napi_env env, napi_status status, void *buffer)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 
ReadStdEncodeToString(napi_env env, void *data)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 
EndStdEncodeToString(napi_env env, napi_status status, void *buffer)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 
Decode(napi_env env, napi_value src, Type valueType)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 
CreateDecodePromise(napi_env env, char *inputDecode, size_t length, Type valueType)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 
Finds(char ch, Type valueType)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 
DecodeOut(size_t equalCount, size_t retLen, DecodeInfo *decodeInfo)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 
DecodeAchieves(napi_env env, DecodeInfo *decodeInfo)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 
DecodeAchievesInner(size_t inputLen, size_t equalCount, const char *input, DecodeInfo *decodeInfo, unsigned char *retDecode)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 
ReadStdDecode(napi_env env, void *data)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     }
EndStdDecode(napi_env env, napi_status status, void *buffer)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 */
FreeMemory(char *&address)773     void FreeMemory(char *&address)
774     {
775         if (address != nullptr) {
776             delete[] address;
777             address = nullptr;
778         }
779     }
FreeMemory(unsigned char *&address)780     void FreeMemory(unsigned char *&address)
781     {
782         if (address != nullptr) {
783             delete[] address;
784             address = nullptr;
785         }
786     }
787 }
788