From f4f77dfcb10de2f6affa4d783481674ea37ebe35 Mon Sep 17 00:00:00 2001 From: Gymee Date: Tue, 6 Dec 2022 17:20:06 +0800 Subject: [PATCH] Refactor and fix pt_base64 Issue: https://gitee.com/openharmony/arkcompiler_toolchain/issues/I6KOXP Signed-off-by: Gymee Change-Id: I53d869e1c5dd7ffbd34ad849d069275cb5dce36f --- .../baseptbase64decode_fuzzer.cpp | 12 +- .../baseptbase64encode_fuzzer.cpp | 7 +- tooling/agent/debugger_impl.cpp | 12 +- tooling/agent/debugger_impl.h | 2 +- tooling/base/pt_base64.cpp | 162 ++++----- tooling/base/pt_base64.h | 19 +- tooling/test/pt_base64_test.cpp | 313 ++++++++++++++---- 7 files changed, 373 insertions(+), 154 deletions(-) diff --git a/test/fuzztest/base/ptbase64/baseptbase64decode_fuzzer/baseptbase64decode_fuzzer.cpp b/test/fuzztest/base/ptbase64/baseptbase64decode_fuzzer/baseptbase64decode_fuzzer.cpp index ca20c2c5..7ae102ad 100644 --- a/test/fuzztest/base/ptbase64/baseptbase64decode_fuzzer/baseptbase64decode_fuzzer.cpp +++ b/test/fuzztest/base/ptbase64/baseptbase64decode_fuzzer/baseptbase64decode_fuzzer.cpp @@ -30,11 +30,13 @@ namespace OHOS { { auto cn = std::make_unique(); auto vm = cn->GetEcvm(); - auto str = cn->GetString(data, size); - std::string output; - std::string input; - panda::ecmascript::tooling::PtBase64::Encode(str, output); - panda::ecmascript::tooling::PtBase64::Decode(input, output); + auto src = cn->GetString(data, size); + std::string dest; + dest.resize(PtBase64::EncodedSize(src.size())); + PtBase64::Encode(dest.data(), src.data(), src.size()); + src = dest; + dest.resize(PtBase64::DecodedSize(src.size())); + PtBase64::Decode(dest.data(), src.data(), src.size()); cn->DestroyEcvm(vm); } } diff --git a/test/fuzztest/base/ptbase64/baseptbase64encode_fuzzer/baseptbase64encode_fuzzer.cpp b/test/fuzztest/base/ptbase64/baseptbase64encode_fuzzer/baseptbase64encode_fuzzer.cpp index 132a13d1..98fb58b5 100644 --- a/test/fuzztest/base/ptbase64/baseptbase64encode_fuzzer/baseptbase64encode_fuzzer.cpp +++ b/test/fuzztest/base/ptbase64/baseptbase64encode_fuzzer/baseptbase64encode_fuzzer.cpp @@ -30,9 +30,10 @@ namespace OHOS { { auto cn = std::make_unique(); auto vm = cn->GetEcvm(); - auto str = cn->GetString(data, size); - std::string output; - PtBase64::Encode(str, output); + auto src = cn->GetString(data, size); + std::string dest; + dest.resize(PtBase64::EncodedSize(src.size())); + PtBase64::Encode(dest.data(), src.data(), src.size()); cn->DestroyEcvm(vm); } } diff --git a/tooling/agent/debugger_impl.cpp b/tooling/agent/debugger_impl.cpp index 1f2e3c3e..0a82f712 100644 --- a/tooling/agent/debugger_impl.cpp +++ b/tooling/agent/debugger_impl.cpp @@ -597,7 +597,7 @@ DispatchResponse DebuggerImpl::EvaluateOnCallFrame(const EvaluateOnCallFramePara return DispatchResponse::Fail("Invalid callFrameId."); } - std::string dest; + std::vector dest; if (!DecodeAndCheckBase64(expression, dest)) { LOG_DEBUGGER(ERROR) << "EvaluateValue: base64 decode failed"; auto ret = CmptEvaluateValue(callFrameId, expression, result); @@ -751,7 +751,7 @@ DispatchResponse DebuggerImpl::SetBreakpointByUrl(const SetBreakpointByUrlParams LOG_DEBUGGER(INFO) << "set breakpoint location: " << location.ToString(); Local condFuncRef = FunctionRef::Undefined(vm_); if (condition.has_value() && !condition.value().empty()) { - std::string dest; + std::vector dest; if (!DecodeAndCheckBase64(condition.value(), dest)) { LOG_DEBUGGER(ERROR) << "SetBreakpointByUrl: base64 decode failed"; return false; @@ -1239,10 +1239,12 @@ Local DebuggerImpl::ConvertToLocal(const std::string &varValue) return taggedValue; } -bool DebuggerImpl::DecodeAndCheckBase64(const std::string &src, std::string &dest) +bool DebuggerImpl::DecodeAndCheckBase64(const std::string &src, std::vector &dest) { - uint32_t numOctets = PtBase64::Decode(src, dest); - if (numOctets > panda_file::File::MAGIC_SIZE && + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + if ((done && numOctets > panda_file::File::MAGIC_SIZE) && memcmp(dest.data(), panda_file::File::MAGIC.data(), panda_file::File::MAGIC_SIZE) == 0) { return true; } diff --git a/tooling/agent/debugger_impl.h b/tooling/agent/debugger_impl.h index cae0a29d..6cfb8c39 100644 --- a/tooling/agent/debugger_impl.h +++ b/tooling/agent/debugger_impl.h @@ -156,7 +156,7 @@ private: void UpdateScopeObject(const FrameHandler *frameHandler, std::string_view varName, Local newVal); void ClearSingleStepper(); Local ConvertToLocal(const std::string &varValue); - bool DecodeAndCheckBase64(const std::string &src, std::string &dest); + bool DecodeAndCheckBase64(const std::string &src, std::vector &dest); bool IsSkipLine(const JSPtLocation &location); bool CheckPauseOnException(); diff --git a/tooling/base/pt_base64.cpp b/tooling/base/pt_base64.cpp index 66d6c8db..ff5b4d39 100644 --- a/tooling/base/pt_base64.cpp +++ b/tooling/base/pt_base64.cpp @@ -16,10 +16,7 @@ #include "base/pt_base64.h" namespace panda::ecmascript::tooling { -static const uint8_t DECODE_STR_LEN = 3; -static const uint8_t ENCODE_STR_LEN = 4; -static const uint8_t INVAILD_STR = 255; -static uint8_t decodeMap[] = { +static const unsigned char DECODE_TABLE[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, @@ -27,99 +24,104 @@ static uint8_t decodeMap[] = { 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 +}; + +static const char ENCODE_TABLE[] = { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/" }; -static char encodeMap[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"}; -uint32_t PtBase64::Decode(const std::string &input, std::string &output) + +std::pair PtBase64::Decode(void *output, const char *input, std::size_t len) { - size_t srcLen = input.size(); - if (srcLen < ENCODE_STR_LEN || srcLen % ENCODE_STR_LEN != 0) { - return 0; + if (len < ENCODED_GROUP_BYTES || len % ENCODED_GROUP_BYTES != 0) { + return {0, false}; } - std::string strDecode; - uint32_t decodeLen = srcLen / ENCODE_STR_LEN * DECODE_STR_LEN; - strDecode.resize(decodeLen); - - uint32_t i = 0; - uint32_t j = 0; - uint32_t equalsCnt = 0; - const char* src = input.data(); - char base64Char[ENCODE_STR_LEN]; - while (srcLen--) { - if (*src != '=') { - auto const v = decodeMap[static_cast(*src)]; - if (v == INVAILD_STR) { - return 0; - } - base64Char[j++] = v; - } else { - base64Char[j++] = '\0'; - equalsCnt++; + auto *src = reinterpret_cast(input); + char *dest = static_cast(output); + char base64Chars[ENCODED_GROUP_BYTES]; + int8_t i = 0; + while (len-- && *src != '=') { + auto v = DECODE_TABLE[*src]; + if (v == INVAILD_VALUE) { + break; } - if (j == ENCODE_STR_LEN) { - // 2: shift 2bits, 4: shift 4bits - strDecode[i] = (base64Char[0] << 2) | ((base64Char[1] & 0x30) >> 4); - // 2: shift 2bits, 4: shift 4bits - strDecode[i + 1] = (base64Char[1] << 4) | ((base64Char[2] & 0x3c) >> 2); - // 2: shift 2bits, 3: the last encode str, 6: shift 6bits - strDecode[i + 2] = (base64Char[2] << 6) | base64Char[3]; - j = 0; - i += DECODE_STR_LEN; + base64Chars[i++] = v; + + if (i == ENCODED_GROUP_BYTES) { + *dest++ = (base64Chars[0] << 2) | ((base64Chars[1] & 0x30) >> 4); + *dest++ = (base64Chars[1] << 4) | ((base64Chars[2] & 0x3c) >> 2); + *dest++ = (base64Chars[2] << 6) | base64Chars[3]; + i = 0; } src++; } - decodeLen -= equalsCnt; - strDecode.resize(decodeLen); - output = std::move(strDecode); - return decodeLen; + + if (i != 0) { + char tmp[UNENCODED_GROUP_BYTES]; + tmp[0] = (base64Chars[0] << 2) | ((base64Chars[1] & 0x30) >> 4); + tmp[1] = (base64Chars[1] << 4) | ((base64Chars[2] & 0x3c) >> 2); + tmp[2] = (base64Chars[2] << 6) | base64Chars[3]; + for (int8_t j = 0; j < i - 1; j++) { + *dest++ = tmp[j]; + } + } + + len++; // get the remaining length and also avoid underflow + size_t decodedLen = dest - static_cast(output); + bool decodedDone = false; + if (len == 0 || (len == 1 && *src == '=') || (len == 2 && *src == '=' && *(src + 1) == '=')) { + decodedDone = true; + } + + return {decodedLen, decodedDone}; } -uint32_t PtBase64::Encode(const std::string &input, std::string &output) +size_t PtBase64::Encode(char *output, const void *input, std::size_t len) { - uint32_t srcLen = input.size(); - if (srcLen == 0) { + if (len == 0) { return 0; } - uint32_t lastLen = srcLen % DECODE_STR_LEN; - uint32_t encodeLen; - uint32_t equalsCnt; - if (lastLen == 0) { - encodeLen = srcLen / DECODE_STR_LEN * ENCODE_STR_LEN; - equalsCnt = 0; - } else { - encodeLen = (srcLen / DECODE_STR_LEN + 1) * ENCODE_STR_LEN; - equalsCnt = DECODE_STR_LEN - lastLen; - } - - uint32_t i = 0; - uint32_t j = 0; - uint32_t index = 0; - std::string strEncode; - strEncode.resize(encodeLen); - const char* src = input.data(); - while (i + 3 < encodeLen) { // 3: the last encode str - index = src[j] >> 2; // 2: shift 2bits - strEncode[i] = encodeMap[index]; - index = ((src[j] & 0x03) << 4) | (src[j + 1] >> 4); // 4: shift 4bits - strEncode[i + 1] = encodeMap[index]; - index = ((src[j + 1] & 0x0F) << 2) | (src[j + 2] >> 6); // 2: shift 2bits, 6: shift 6bits - strEncode[i + 2] = encodeMap[index]; // 2: the second char - index = src[j + 2] & 0x3F; // 2: the second char - strEncode[i + 3] = encodeMap[index]; // 3: the third char + auto *src = static_cast(input); + char *dest = output; + for (auto n = len / UNENCODED_GROUP_BYTES; n--;) { + *dest++ = ENCODE_TABLE[src[0] >> 2]; + *dest++ = ENCODE_TABLE[((src[0] & 0x03) << 4) | (src[1] >> 4)]; + *dest++ = ENCODE_TABLE[((src[1] & 0x0f) << 2) | (src[2] >> 6)]; + *dest++ = ENCODE_TABLE[src[2] & 0x3f]; - i += ENCODE_STR_LEN; - j += DECODE_STR_LEN; + src += UNENCODED_GROUP_BYTES; } - if (equalsCnt == 1) { - strEncode[encodeLen - 1] = '='; - } else if (equalsCnt == 2) { // 2: Equal's count - strEncode[encodeLen - 1] = '='; - strEncode[encodeLen - 2] = '='; // 2: the last two chars + int8_t remainder = len % UNENCODED_GROUP_BYTES; + int8_t paddingCnt = (UNENCODED_GROUP_BYTES - remainder) % UNENCODED_GROUP_BYTES; + switch (paddingCnt) { + case 1: + *dest++ = ENCODE_TABLE[src[0] >> 2]; + *dest++ = ENCODE_TABLE[((src[0] & 0x03) << 4) | (src[1] >> 4)]; + *dest++ = ENCODE_TABLE[((src[1] & 0x0f) << 2)]; + *dest++ = '='; + break; + case 2: + *dest++ = ENCODE_TABLE[src[0] >> 2]; + *dest++ = ENCODE_TABLE[((src[0] & 0x03) << 4)]; + *dest++ = '='; + *dest++ = '='; + break; + default: + break; } - output = std::move(strEncode); - return encodeLen; + return dest - output; } } // namespace panda::ecmascript::tooling \ No newline at end of file diff --git a/tooling/base/pt_base64.h b/tooling/base/pt_base64.h index 43092841..3bb9db5f 100644 --- a/tooling/base/pt_base64.h +++ b/tooling/base/pt_base64.h @@ -24,8 +24,23 @@ public: PtBase64() = default; ~PtBase64() = default; - static uint32_t Decode(const std::string &input, std::string &output); - static uint32_t Encode(const std::string &input, std::string &output); + static std::size_t constexpr DecodedSize(std::size_t n) + { + return n / ENCODED_GROUP_BYTES * UNENCODED_GROUP_BYTES; + } + + static std::size_t constexpr EncodedSize(std::size_t n) + { + return ENCODED_GROUP_BYTES * ((n + 2) / UNENCODED_GROUP_BYTES); + } + + static std::pair Decode(void *output, const char *input, std::size_t len); + static size_t Encode(char *output, const void *input, std::size_t len); + +private: + static constexpr uint8_t UNENCODED_GROUP_BYTES = 3; + static constexpr uint8_t ENCODED_GROUP_BYTES = 4; + static constexpr uint8_t INVAILD_VALUE = 255; }; } // namespace panda::ecmascript::tooling #endif diff --git a/tooling/test/pt_base64_test.cpp b/tooling/test/pt_base64_test.cpp index 61c1fa29..85f1c1d3 100644 --- a/tooling/test/pt_base64_test.cpp +++ b/tooling/test/pt_base64_test.cpp @@ -40,78 +40,275 @@ public: } }; -HWTEST_F_L0(PtBase64Test, ShortTextTest) + +HWTEST_F_L0(PtBase64Test, EncodeAndDecodeEmptyString) { - std::string dec = "Hello"; - std::string enc; - std::string des; - uint32_t len = PtBase64::Encode(dec, enc); - EXPECT_EQ(static_cast(len), 8); - EXPECT_EQ(enc, "SGVsbG8="); - - len = PtBase64::Decode(enc, des); - EXPECT_EQ(static_cast(len), 5); - EXPECT_EQ(des, "Hello"); + std::string src; + std::string dest; + + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + EXPECT_EQ(numOctets, 0u); + EXPECT_FALSE(done); + + size_t len = PtBase64::Encode(dest.data(), src.data(), src.size()); + EXPECT_EQ(len, 0u); + EXPECT_EQ(dest, ""); } -HWTEST_F_L0(PtBase64Test, LongTextTest) +HWTEST_F_L0(PtBase64Test, EncodeAndDecodeShortText001) { - std::string enc = "SWYgeW91IGNhbiBzZWUgdGhpcyBtZXNzYWdlLCBpdCBtZWFucyB0aGF0IFB0QmFzZTY0RGVjb2RlIHdvcmtzIHdlbGw="; - std::string dec = "If you can see this message, it means that PtBase64Decode works well"; - std::string des; + std::string src; + std::string dest; + size_t len = 0; - uint32_t len = PtBase64::Encode(dec, des); - EXPECT_EQ(static_cast(len), 92); - EXPECT_EQ(enc, des); + { + src = "1"; + dest.resize(PtBase64::EncodedSize(src.size())); + len = PtBase64::Encode(dest.data(), src.data(), src.size()); + EXPECT_EQ(len, 4u); + EXPECT_EQ(dest, "MQ=="); + src = dest; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + EXPECT_EQ(numOctets, 1u); + EXPECT_EQ(dest, "1"); + } + + { + src = "12"; + dest.resize(PtBase64::EncodedSize(src.size())); + len = PtBase64::Encode(dest.data(), src.data(), src.size()); + EXPECT_EQ(len, 4u); + EXPECT_EQ(dest, "MTI="); + src = dest; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + EXPECT_EQ(numOctets, 2u); + EXPECT_EQ(dest, "12"); + } - len = PtBase64::Decode(enc, des); - EXPECT_EQ(static_cast(len), 68); - EXPECT_EQ(des, dec); + { + src = "123"; + dest.resize(PtBase64::EncodedSize(src.size())); + len = PtBase64::Encode(dest.data(), src.data(), src.size()); + EXPECT_EQ(len, 4u); + EXPECT_EQ(dest, "MTIz"); + src = dest; + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + EXPECT_EQ(numOctets, 3u); + EXPECT_EQ(dest, "123"); + } } -HWTEST_F_L0(PtBase64Test, ErrorTextTest) +HWTEST_F_L0(PtBase64Test, EncodeAndDecodeShortText002) { - std::string src = "SGVsbG8=="; - std::string des; - PtBase64 ptBase64; - uint32_t len = ptBase64.Decode(src, des); - EXPECT_EQ(static_cast(len), 0); - EXPECT_EQ(des, ""); - - len = PtBase64::Encode("", des); - EXPECT_EQ(static_cast(len), 0); - EXPECT_EQ(des, ""); + std::string dest; + std::string src = "hello"; + dest.resize(PtBase64::EncodedSize(src.size())); + size_t len = PtBase64::Encode(dest.data(), src.data(), src.size()); + EXPECT_EQ(len, 8u); + EXPECT_EQ(dest, "aGVsbG8="); + src = dest; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + EXPECT_EQ(numOctets, 5u); + EXPECT_TRUE(done); + EXPECT_EQ(dest, "hello"); } -HWTEST_F_L0(PtBase64Test, EncodeTest) +HWTEST_F_L0(PtBase64Test, EncodeAndDecodeLongText) { - std::string src = "a"; - std::string des; - uint32_t len = PtBase64::Encode(src, des); - EXPECT_EQ(static_cast(len), 4); - - src = "aa"; - len = PtBase64::Encode(src, des); - EXPECT_EQ(static_cast(len), 4); - - src = "aaa"; - len = PtBase64::Encode(src, des); - EXPECT_EQ(static_cast(len), 4); + std::string src = "If you can see this message, it means that PtBase64Decode works well"; + std::string dest; + std::string encoded = "SWYgeW91IGNhbiBzZWUgdGhpcyBtZXNzYWdlLCBpdCBtZWFucyB0aGF0IFB0QmFzZ" \ + "TY0RGVjb2RlIHdvcmtzIHdlbGw="; + + dest.resize(PtBase64::EncodedSize(src.size())); + size_t len = PtBase64::Encode(dest.data(), src.data(), src.size()); + EXPECT_EQ(len, 92u); + EXPECT_EQ(dest, encoded); + + std::string decoded; + decoded.resize(PtBase64::DecodedSize(encoded.size())); + auto [numOctets, done] = PtBase64::Decode(decoded.data(), encoded.data(), encoded.size()); + decoded.resize(numOctets); + EXPECT_EQ(numOctets, 68u); + EXPECT_TRUE(done); + EXPECT_EQ(decoded, src); } -HWTEST_F_L0(PtBase64Test, DecodeTest) +HWTEST_F_L0(PtBase64Test, EncodeUnprintableCharacter) { - std::string str = ""; - std::string des; - uint32_t len = PtBase64::Decode(str, des); - EXPECT_EQ(static_cast(len), 0); - - str = "Hello"; - len = PtBase64::Decode(str, des); - EXPECT_EQ(static_cast(len), 0); - - str = "HelloABC"; - len = PtBase64::Decode(str, des); - EXPECT_EQ(static_cast(len), 6); + std::string src = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::string dest; + dest.resize(PtBase64::EncodedSize(src.size())); + size_t len = PtBase64::Encode(dest.data(), src.data(), src.size()); + EXPECT_EQ(len, 12u); + EXPECT_EQ(dest, "AQIDBAUGBwgJ"); +} + +HWTEST_F_L0(PtBase64Test, DecodeErrorNumberBase64Text) +{ + std::string src; + std::string dest; + { + src = "ABC"; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + EXPECT_EQ(numOctets, 0u); + EXPECT_EQ(dest, ""); + } + + { + src = "ABCDE"; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + EXPECT_EQ(numOctets, 0u); + EXPECT_EQ(dest, ""); + } + + { + src = "ABCDEF"; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + EXPECT_EQ(numOctets, 0u); + EXPECT_EQ(dest, ""); + } +} + +HWTEST_F_L0(PtBase64Test, EncodeAndDecodeBytesArray) +{ + std::vector src = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + }; + std::string dest; + std::string encoded = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4O" \ + "To7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3Bxcn" \ + "N0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6y" \ + "trq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm" \ + "5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=="; + dest.resize(PtBase64::EncodedSize(src.size())); + size_t len = PtBase64::Encode(dest.data(), src.data(), src.size()); + EXPECT_EQ(len, 344u); + EXPECT_EQ(dest, encoded); + + std::vector decoded; + decoded.resize(PtBase64::DecodedSize(encoded.size())); + auto [numOctets, done] = PtBase64::Decode(decoded.data(), encoded.data(), encoded.size()); + decoded.resize(numOctets); + EXPECT_EQ(numOctets, 256u); + EXPECT_TRUE(done); + EXPECT_EQ(memcmp(decoded.data(), src.data(), numOctets), 0); +} + +HWTEST_F_L0(PtBase64Test, EncodeAndDecodeUnicodeCharacter001) +{ + std::string src = u8"😀"; + std::string dest; + dest.resize(PtBase64::EncodedSize(src.size())); + size_t len = PtBase64::Encode(dest.data(), src.data(), src.size()); + EXPECT_EQ(len, 8u); + EXPECT_EQ(dest, "8J+YgA=="); + src = dest; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + EXPECT_EQ(numOctets, 4u); + EXPECT_TRUE(done); + EXPECT_EQ(dest, u8"😀"); +} + +HWTEST_F_L0(PtBase64Test, EncodeAndDecodeUnicodeCharacter002) +{ + std::string src = "测试Base64加密解密"; + std::string dest; + dest.resize(PtBase64::EncodedSize(src.size())); + size_t len = PtBase64::Encode(dest.data(), src.data(), src.size()); + EXPECT_EQ(len, 32u); + EXPECT_EQ(dest, "5rWL6K+VQmFzZTY05Yqg5a+G6Kej5a+G"); + src = dest; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + EXPECT_EQ(numOctets, 24u); + EXPECT_TRUE(done); + EXPECT_EQ(dest, "测试Base64加密解密"); +} + +HWTEST_F_L0(PtBase64Test, EncodeAndDecodeInvalidCharacters) +{ + std::string src; + std::string dest; + { + src = "AB#="; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + EXPECT_EQ(numOctets, 1u); + EXPECT_FALSE(done); + } + + { + src = "#AB="; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + EXPECT_EQ(numOctets, 0u); + EXPECT_FALSE(done); + } + + { + src = "AB=#"; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + EXPECT_EQ(numOctets, 1u); + EXPECT_FALSE(done); + } + + { + src = "Zm9vYmFy \r\n\t"; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + EXPECT_EQ(numOctets, 6u); + EXPECT_FALSE(done); + } + + { + src = "=ABC"; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + EXPECT_EQ(numOctets, 0u); + EXPECT_FALSE(done); + } + + { + src = "==AB"; + dest.resize(PtBase64::DecodedSize(src.size())); + auto [numOctets, done] = PtBase64::Decode(dest.data(), src.data(), src.size()); + EXPECT_EQ(numOctets, 0u); + EXPECT_FALSE(done); + } } } \ No newline at end of file -- Gitee