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