• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #ifndef PANDA_TOOLING_INSPECTOR_EVALUATION_BASE64_H
17 #define PANDA_TOOLING_INSPECTOR_EVALUATION_BASE64_H
18 
19 #include <array>
20 #include <optional>
21 #include <string>
22 
23 #include "libpandabase/macros.h"
24 #include "libpandabase/utils/span.h"
25 
26 namespace ark::tooling::inspector {
27 class Base64Decoder final {
28 public:
29     Base64Decoder() = delete;
30 
DecodedSize(Span<const uint8_t> input)31     static std::optional<size_t> DecodedSize(Span<const uint8_t> input)
32     {
33         if (input.empty() || input.size() % ENCODED_GROUP_BYTES != 0) {
34             return {};
35         }
36 
37         auto sz = input.size() / ENCODED_GROUP_BYTES * DECODED_GROUP_BYTES;
38         auto last = input.end() - 1;
39         for (size_t i = 0; i < MAX_PADDINGS && *last == PADDING_CHAR; ++i, --last) {
40             --sz;
41         }
42         return sz;
43     }
44 
Decode(const std::string & encoded,std::string & decoded)45     static bool Decode(const std::string &encoded, std::string &decoded)
46     {
47         ASSERT(!encoded.empty());
48 
49         auto sz = encoded.size();
50         Span encodingInput(reinterpret_cast<const uint8_t *>(encoded.c_str()), sz);
51         auto bytecodeSize = Base64Decoder::DecodedSize(encodingInput);
52         if (!bytecodeSize) {
53             return false;
54         }
55         decoded.resize(*bytecodeSize);
56         return Base64Decoder::Decode(reinterpret_cast<uint8_t *>(decoded.data()), encodingInput);
57     }
58 
Decode(uint8_t * output,Span<const uint8_t> input)59     static bool Decode(uint8_t *output, Span<const uint8_t> input)
60     {
61         ASSERT(output);
62 
63         if (input.empty() || input.size() % ENCODED_GROUP_BYTES != 0) {
64             return false;
65         }
66 
67         std::array<uint8_t, ENCODED_GROUP_BYTES> decodingBuffer = {0};
68         size_t baseIdx = 0;
69         auto srcIter = input.begin();
70         for (auto endIter = input.end(); srcIter != endIter && *srcIter != PADDING_CHAR; ++srcIter) {
71             auto decoded = DecodeChar(*srcIter);
72             if (decoded == INVALID_VALUE) {
73                 return false;
74             }
75             decodingBuffer[baseIdx++] = decoded;
76 
77             if (baseIdx == ENCODED_GROUP_BYTES) {
78                 DecodeSextetsGroup(decodingBuffer, Span(output, DECODED_GROUP_BYTES));
79                 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
80                 output += DECODED_GROUP_BYTES;
81                 baseIdx = 0;
82             }
83         }
84 
85         if (baseIdx != 0) {
86             // Decode the remainder part.
87             std::array<uint8_t, DECODED_GROUP_BYTES> decodedRemainder = {0};
88             DecodeSextetsGroup(decodingBuffer, Span(decodedRemainder.data(), DECODED_GROUP_BYTES));
89             for (size_t idx = 0, end = baseIdx - 1; idx < end; ++idx) {
90                 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
91                 *output++ = decodedRemainder[idx];
92             }
93         }
94 
95         // Only padding symbols could remain.
96         // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
97         auto remainder = input.end() - srcIter;
98         return (remainder == 0 || (remainder == 1 && *srcIter == PADDING_CHAR) ||
99                 (remainder == MAX_PADDINGS && *srcIter == PADDING_CHAR && *(srcIter + 1) == PADDING_CHAR));
100         // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
101     }
102 
103 private:
104     static constexpr size_t DECODED_GROUP_BYTES = 3;
105     static constexpr size_t ENCODED_GROUP_BYTES = 4;
106 
107 private:
DecodeChar(uint8_t encoded)108     static uint8_t DecodeChar(uint8_t encoded)
109     {
110         if (encoded >= DECODE_TABLE.size()) {
111             return INVALID_VALUE;
112         }
113         return DECODE_TABLE[encoded];
114     }
115 
116     /// @brief Converts 4 sextets into 3 output bytes.
DecodeSextetsGroup(const std::array<uint8_t,ENCODED_GROUP_BYTES> & decodingBuffer,Span<uint8_t> output)117     static void DecodeSextetsGroup(const std::array<uint8_t, ENCODED_GROUP_BYTES> &decodingBuffer, Span<uint8_t> output)
118     {
119         // 0b00110000
120         static constexpr uint8_t FOURTH_TO_FIFTH_BITS = 0x30U;
121         // 0b00111100
122         static constexpr uint8_t SECOND_TO_FIFTH_BITS = 0x3CU;
123         static constexpr uint8_t TWO_BITS_SHIFT = 2U;
124         static constexpr uint8_t FOUR_BITS_SHIFT = 4U;
125         static constexpr uint8_t SIX_BITS_SHIFT = 6U;
126 
127         ASSERT(output.size() == DECODED_GROUP_BYTES);
128         // NOLINTBEGIN(hicpp-signed-bitwise)
129         output[0UL] =
130             (decodingBuffer[0UL] << TWO_BITS_SHIFT) | ((decodingBuffer[1UL] & FOURTH_TO_FIFTH_BITS) >> FOUR_BITS_SHIFT);
131         output[1UL] =
132             (decodingBuffer[1UL] << FOUR_BITS_SHIFT) | ((decodingBuffer[2UL] & SECOND_TO_FIFTH_BITS) >> TWO_BITS_SHIFT);
133         output[2UL] = (decodingBuffer[2UL] << SIX_BITS_SHIFT) | decodingBuffer[3UL];
134         // NOLINTEND(hicpp-signed-bitwise)
135     }
136 
137 private:
138     static constexpr size_t MAX_PADDINGS = 2U;
139     static constexpr uint8_t PADDING_CHAR = '=';
140     static constexpr uint8_t INVALID_VALUE = 255U;
141     static constexpr std::array<uint8_t, 123> DECODE_TABLE = {
142         255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
143         255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
144         255, 62,  255, 255, 255, 63,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  255, 255, 255, 255, 255,
145         255, 255, 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,  16,  17,  18,
146         19,  20,  21,  22,  23,  24,  25,  255, 255, 255, 255, 255, 255, 26,  27,  28,  29,  30,  31,  32,  33,
147         34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51};
148 };
149 }  // namespace ark::tooling::inspector
150 
151 #endif  // PANDA_TOOLING_INSPECTOR_EVALUATION_BASE64_H
152