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