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             napi_close_handle_scope(env, scope);
528             return;
529         }
530         napi_value result = nullptr;
531         napi_create_typedarray(env, napi_uint8_array, bufferSize, arrayBuffer, 0, &result);
532         napi_resolve_deferred(env, stdEncodeInfo->deferred, result);
533         napi_delete_async_work(env, stdEncodeInfo->worker);
534         napi_close_handle_scope(env, scope);
535         delete[] stdEncodeInfo->sinputEncoding;
536         delete stdEncodeInfo;
537     }
538 
ReadStdEncodeToString(napi_env env,void * data)539     void Base64::ReadStdEncodeToString(napi_env env, void *data)
540     {
541         auto stdEncodeInfo = reinterpret_cast<EncodeInfo*>(data);
542         unsigned char *rets = EncodeAchieves(env, stdEncodeInfo);
543         stdEncodeInfo->sinputEncoding = rets;
544     }
545 
EndStdEncodeToString(napi_env env,napi_status status,void * buffer)546     void Base64::EndStdEncodeToString(napi_env env, napi_status status, void *buffer)
547     {
548         auto stdEncodeInfo = reinterpret_cast<EncodeInfo*>(buffer);
549         napi_handle_scope scope = nullptr;
550         napi_open_handle_scope(env, &scope);
551         if (scope == nullptr) {
552             return;
553         }
554         const char *encString = reinterpret_cast<const char*>(stdEncodeInfo->sinputEncoding);
555         napi_value resultStr = nullptr;
556         napi_create_string_utf8(env, encString, strlen(encString), &resultStr);
557         napi_resolve_deferred(env, stdEncodeInfo->deferred, resultStr);
558         napi_delete_async_work(env, stdEncodeInfo->worker);
559         napi_close_handle_scope(env, scope);
560         delete[] stdEncodeInfo->sinputEncoding;
561         delete stdEncodeInfo;
562     }
563 
Decode(napi_env env,napi_value src,Type valueType)564     napi_value Base64::Decode(napi_env env, napi_value src, Type valueType)
565     {
566         napi_valuetype valuetype = napi_undefined;
567         napi_typeof(env, src, &valuetype);
568         napi_typedarray_type type;
569         size_t length = 0;
570         void *resultData = nullptr;
571         char *inputString = nullptr;
572         char *inputDecode = nullptr;
573         if (valuetype != napi_valuetype::napi_string) {
574             if (napi_get_typedarray_info(env, src, &type, &length, &resultData, nullptr, nullptr) != napi_ok) {
575                 std::string errMsg =
576                     "Parameter error. The type of Parameter must be Uint8Array or string.";
577                 napi_throw_error(env, "401", errMsg.c_str());
578                 return nullptr;
579             }
580         }
581         if (valuetype == napi_valuetype::napi_string) {
582             size_t prolen = 0;
583             napi_get_value_string_utf8(env, src, nullptr, 0, &prolen);
584             if (prolen > 0) {
585                 inputString = new char[prolen + 1];
586                 if (memset_s(inputString, prolen + 1, '\0', prolen + 1) != EOK) {
587                     napi_throw_error(env, "-1", "decode inputString memset_s failed");
588                     return nullptr;
589                 }
590             } else {
591                 napi_throw_error(env, "-2", "prolen is error !");
592                 return nullptr;
593             }
594             napi_get_value_string_utf8(env, src, inputString, prolen + 1, &prolen);
595             CreateDecodePromise(env, inputString, prolen, valueType);
596         } else if (type == napi_typedarray_type::napi_uint8_array && length > 0) {
597             inputDecode = static_cast<char*>(resultData);
598             CreateDecodePromise(env, inputDecode, length, valueType);
599         } else {
600             std::string errMsg =
601                 "Parameter error. The type of Parameter must be Uint8Array or string and the length greater than 0.";
602             napi_throw_error(env, "401", errMsg.c_str());
603             FreeMemory(inputString);
604             return nullptr;
605         }
606         return stdDecodeInfo_->promise;
607     }
608 
CreateDecodePromise(napi_env env,char * inputDecode,size_t length,Type valueType)609     void Base64::CreateDecodePromise(napi_env env, char *inputDecode, size_t length, Type valueType)
610     {
611         napi_value resourceName = nullptr;
612         stdDecodeInfo_ = new DecodeInfo();
613         stdDecodeInfo_->sinputDecode = inputDecode;
614         stdDecodeInfo_->slength = length;
615         stdDecodeInfo_->env = env;
616         stdDecodeInfo_->valueType = valueType;
617         napi_create_promise(env, &stdDecodeInfo_->deferred, &stdDecodeInfo_->promise);
618         napi_create_string_utf8(env, "ReadStdDecode", NAPI_AUTO_LENGTH, &resourceName);
619         napi_create_async_work(env, nullptr, resourceName, ReadStdDecode, EndStdDecode,
620                                reinterpret_cast<void*>(stdDecodeInfo_), &stdDecodeInfo_->worker);
621         napi_queue_async_work_with_qos(env, stdDecodeInfo_->worker, napi_qos_user_initiated);
622     }
623 
Finds(char ch,Type valueType)624     int Finds(char ch, Type valueType)
625     {
626         bool flag = false;
627         if (valueType == Type::BASIC_URL_SAFE || valueType == Type::MIME_URL_SAFE) {
628             flag = true;
629         }
630         int tableLen = flag ? TRAGET_SIXTYFIVE - 1 : TRAGET_SIXTYFIVE;
631         const char *searchArray = flag ? BASEURL : BASE;
632         int couts = 0;
633         for (int i = 0; i < tableLen; i++) {
634             if (searchArray[i] == ch) {
635                 couts = i;
636             }
637         }
638         return couts;
639     }
640 
DecodeOut(size_t equalCount,size_t retLen,DecodeInfo * decodeInfo)641     size_t DecodeOut(size_t equalCount, size_t retLen, DecodeInfo *decodeInfo)
642     {
643         switch (equalCount) {
644             case 0:
645                 retLen += TRAGET_FOUR;
646                 break;
647             case 1:
648                 retLen += TRAGET_FOUR;
649                 decodeInfo->decodeOutLen -= 1;
650                 break;
651             case TRAGET_TWO:
652                 retLen += TRAGET_THREE;
653                 decodeInfo->decodeOutLen -= TRAGET_TWO;
654                 break;
655             default:
656                 retLen += TRAGET_TWO;
657                 break;
658         }
659         return retLen;
660     }
661 
DecodeAchieves(napi_env env,DecodeInfo * decodeInfo)662     unsigned char *DecodeAchieves(napi_env env, DecodeInfo *decodeInfo)
663     {
664         const char *input = decodeInfo->sinputDecode;
665         size_t inputLen = decodeInfo->slength;
666         size_t retLen = 0;
667         retLen = (inputLen / TRAGET_FOUR) * TRAGET_THREE;
668         decodeInfo->decodeOutLen = retLen;
669         size_t equalCount = 0;
670         unsigned char *retDecode = nullptr;
671         if (*(input + inputLen - 1) == '=') {
672             equalCount++;
673         }
674         if (*(input + inputLen - TRAGET_TWO) == '=') {
675             equalCount++;
676         }
677         retLen = DecodeOut(equalCount, retLen, decodeInfo);
678         if (retLen > 0) {
679             retDecode = new unsigned char[retLen + 1];
680             if (memset_s(retDecode, retLen + 1, '\0', retLen + 1) != EOK) {
681                 FreeMemory(retDecode);
682                 napi_throw_error(decodeInfo->env, "-1", "decode retDecode memset_s failed");
683                 return nullptr;
684             }
685         } else {
686             napi_throw_error(decodeInfo->env, "-2", "retLen is error !");
687             return nullptr;
688         }
689         if (decodeInfo->valueType == Type::BASIC_URL_SAFE || decodeInfo->valueType == Type::MIME_URL_SAFE) {
690             size_t remainder = inputLen % TRAGET_FOUR;
691             if (remainder == TRAGET_TWO) {
692                 decodeInfo->decodeOutLen += 1;
693             } else if (remainder == TRAGET_THREE) {
694                 decodeInfo->decodeOutLen += TRAGET_TWO;
695             }
696         }
697 
698         unsigned char *result = nullptr;
699         result = DecodeAchievesInner(inputLen, equalCount, input, decodeInfo, retDecode);
700         if (result == nullptr) {
701             FreeMemory(retDecode);
702         }
703         return result;
704     }
705 
DecodeAchievesInner(size_t inputLen,size_t equalCount,const char * input,DecodeInfo * decodeInfo,unsigned char * retDecode)706     unsigned char *DecodeAchievesInner(size_t inputLen, size_t equalCount,
707                                        const char *input, DecodeInfo *decodeInfo, unsigned char *retDecode)
708     {
709         size_t inp = 0;
710         size_t temp = 0;
711         size_t bitWise = 0;
712         size_t index = 0;
713         while (inp < (inputLen - equalCount)) {
714             temp = 0;
715             bitWise = 0;
716             while (temp < TRAGET_FOUR) {
717                 if (inp >= (inputLen - equalCount)) {
718                     break;
719                 }
720                 int findData = Finds(input[inp], decodeInfo->valueType);
721                 if (findData == -1) {
722                     return nullptr;
723                 }
724                 bitWise = (bitWise << TRAGET_SIX) | static_cast<size_t>(findData);
725                 inp++;
726                 temp++;
727             }
728             bitWise = bitWise << ((TRAGET_FOUR - temp) * TRAGET_SIX);
729             for (size_t i = 0; i < TRAGET_THREE; i++) {
730                 if (i == temp) {
731                     break;
732                 }
733                 retDecode[index++] = static_cast<char>((bitWise >> ((TRAGET_TWO - i) * TRAGET_EIGHT)) & XFF_FLG);
734             }
735         }
736         retDecode[index] = 0;
737         return retDecode;
738     }
739 
ReadStdDecode(napi_env env,void * data)740     void Base64::ReadStdDecode(napi_env env, void *data)
741     {
742         auto stdDecodeInfo = reinterpret_cast<DecodeInfo*>(data);
743         unsigned char *rets = DecodeAchieves(env, stdDecodeInfo);
744         stdDecodeInfo->sinputDecoding = rets;
745     }
EndStdDecode(napi_env env,napi_status status,void * buffer)746     void Base64::EndStdDecode(napi_env env, napi_status status, void *buffer)
747     {
748         auto stdDecodeInfo = reinterpret_cast<DecodeInfo*>(buffer);
749         void *data = nullptr;
750         napi_handle_scope scope = nullptr;
751         napi_open_handle_scope(env, &scope);
752         if (scope == nullptr) {
753             return;
754         }
755         napi_value arrayBuffer = nullptr;
756         size_t bufferSize = stdDecodeInfo->decodeOutLen;
757         napi_create_arraybuffer(env, bufferSize, &data, &arrayBuffer);
758         if (memcpy_s(data, bufferSize,
759             reinterpret_cast<const void*>(stdDecodeInfo->sinputDecoding), bufferSize) != EOK) {
760             HILOG_ERROR("copy ret to arraybuffer error");
761             napi_delete_async_work(env, stdDecodeInfo->worker);
762             napi_close_handle_scope(env, scope);
763             return;
764         }
765         napi_value result = nullptr;
766         napi_create_typedarray(env, napi_uint8_array, bufferSize, arrayBuffer, 0, &result);
767         napi_resolve_deferred(env, stdDecodeInfo->deferred, result);
768         napi_delete_async_work(env, stdDecodeInfo->worker);
769         napi_close_handle_scope(env, scope);
770         delete[] stdDecodeInfo->sinputDecoding;
771         delete stdDecodeInfo;
772     }
773 
774     /* Memory cleanup function */
FreeMemory(char * & address)775     void FreeMemory(char *&address)
776     {
777         if (address != nullptr) {
778             delete[] address;
779             address = nullptr;
780         }
781     }
FreeMemory(unsigned char * & address)782     void FreeMemory(unsigned char *&address)
783     {
784         if (address != nullptr) {
785             delete[] address;
786             address = nullptr;
787         }
788     }
789 }
790