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 #include "db_base64_utils.h"
17
18 #include <algorithm>
19 #include <array>
20
21 namespace DistributedDB {
22 static constexpr const std::string_view BASE64_CHARS = /* NOLINT */
23 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
24 "abcdefghijklmnopqrstuvwxyz"
25 "0123456789+/";
26
27 static constexpr const uint32_t CHAR_ARRAY_LENGTH_THREE = 3;
28 static constexpr const uint32_t CHAR_ARRAY_LENGTH_FOUR = 4;
29
30 enum class BASE64_ENCODE_CONSTANT : uint8_t {
31 BASE64_ENCODE_MASK1 = 0xfc,
32 BASE64_ENCODE_MASK2 = 0x03,
33 BASE64_ENCODE_MASK3 = 0x0f,
34 BASE64_ENCODE_MASK4 = 0x3f,
35 BASE64_ENCODE_MASK5 = 0xf0,
36 BASE64_ENCODE_MASK6 = 0xc0,
37 BASE64_ENCODE_OFFSET2 = 2,
38 BASE64_ENCODE_OFFSET4 = 4,
39 BASE64_ENCODE_OFFSET6 = 6,
40 BASE64_ENCODE_INDEX0 = 0,
41 BASE64_ENCODE_INDEX1 = 1,
42 BASE64_ENCODE_INDEX2 = 2,
43 };
44
45 enum class BASE64_DECODE_CONSTANT : uint8_t {
46 BASE64_DECODE_MASK1 = 0x30,
47 BASE64_DECODE_MASK2 = 0xf,
48 BASE64_DECODE_MASK3 = 0x3c,
49 BASE64_DECODE_MASK4 = 0x3,
50 BASE64_DECODE_OFFSET2 = 2,
51 BASE64_DECODE_OFFSET4 = 4,
52 BASE64_DECODE_OFFSET6 = 6,
53 BASE64_DECODE_INDEX0 = 0,
54 BASE64_DECODE_INDEX1 = 1,
55 BASE64_DECODE_INDEX2 = 2,
56 BASE64_DECODE_INDEX3 = 3,
57 };
58
IsBase64Char(const char c)59 static inline bool IsBase64Char(const char c)
60 {
61 return (isalnum(c) || (c == '+') || (c == '/'));
62 }
63
MakeCharFour(const std::array<uint8_t,CHAR_ARRAY_LENGTH_THREE> & charArrayThree,std::array<uint8_t,CHAR_ARRAY_LENGTH_FOUR> & charArrayFour)64 static void MakeCharFour(const std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> &charArrayThree,
65 std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> &charArrayFour)
66 {
67 const uint8_t table[CHAR_ARRAY_LENGTH_FOUR] = {
68 static_cast<uint8_t>((charArrayThree[static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_INDEX0)] &
69 static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_MASK1)) >>
70 static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_OFFSET2)),
71 static_cast<uint8_t>(((charArrayThree[static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_INDEX0)] &
72 static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_MASK2))
73 << static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_OFFSET4)) +
74 ((charArrayThree[static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_INDEX1)] &
75 static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_MASK5)) >>
76 static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_OFFSET4))),
77 static_cast<uint8_t>(((charArrayThree[static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_INDEX1)] &
78 static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_MASK3))
79 << static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_OFFSET2)) +
80 ((charArrayThree[static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_INDEX2)] &
81 static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_MASK6)) >>
82 static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_OFFSET6))),
83 static_cast<uint8_t>(charArrayThree[static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_INDEX2)] &
84 static_cast<uint8_t>(BASE64_ENCODE_CONSTANT::BASE64_ENCODE_MASK4)),
85 };
86 for (size_t index = 0; index < CHAR_ARRAY_LENGTH_FOUR; ++index) {
87 charArrayFour[index] = table[index];
88 }
89 }
90
MakeCharTree(const std::array<uint8_t,CHAR_ARRAY_LENGTH_FOUR> & charArrayFour,std::array<uint8_t,CHAR_ARRAY_LENGTH_THREE> & charArrayThree)91 static void MakeCharTree(const std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> &charArrayFour,
92 std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> &charArrayThree)
93 {
94 const uint8_t table[CHAR_ARRAY_LENGTH_THREE] = {
95 static_cast<uint8_t>((charArrayFour[static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_INDEX0)]
96 << static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_OFFSET2)) +
97 ((charArrayFour[static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_INDEX1)] &
98 static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_MASK1)) >>
99 static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_OFFSET4))),
100 static_cast<uint8_t>(((charArrayFour[static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_INDEX1)] &
101 static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_MASK2))
102 << static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_OFFSET4)) +
103 ((charArrayFour[static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_INDEX2)] &
104 static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_MASK3)) >>
105 static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_OFFSET2))),
106 static_cast<uint8_t>(((charArrayFour[static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_INDEX2)] &
107 static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_MASK4))
108 << static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_OFFSET6)) +
109 charArrayFour[static_cast<uint8_t>(BASE64_DECODE_CONSTANT::BASE64_DECODE_INDEX3)]),
110 };
111 for (size_t index = 0; index < CHAR_ARRAY_LENGTH_THREE; ++index) {
112 charArrayThree[index] = table[index];
113 }
114 }
115
Encode(const std::vector<uint8_t> & source)116 std::string DBBase64Utils::Encode(const std::vector<uint8_t> &source)
117 {
118 auto it = source.begin();
119 std::string ret;
120 size_t index = 0;
121 std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> charArrayThree = { 0 };
122 std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> charArrayFour = { 0 };
123
124 while (it != source.end()) {
125 charArrayThree[index] = *it;
126 ++index;
127 ++it;
128 if (index != CHAR_ARRAY_LENGTH_THREE) {
129 continue;
130 }
131 MakeCharFour(charArrayThree, charArrayFour);
132 std::for_each(charArrayFour.begin(), charArrayFour.end(), [&ret](uint8_t idx) {
133 ret += BASE64_CHARS[idx];
134 });
135 index = 0;
136 }
137 if (index == 0) {
138 return ret;
139 }
140
141 for (auto i = index; i < CHAR_ARRAY_LENGTH_THREE; ++i) {
142 charArrayThree[i] = 0;
143 }
144 MakeCharFour(charArrayThree, charArrayFour);
145
146 for (size_t i = 0; i < index + 1; ++i) {
147 ret += BASE64_CHARS[charArrayFour[i]];
148 }
149
150 while (index < CHAR_ARRAY_LENGTH_THREE) {
151 ret += '=';
152 ++index;
153 }
154 return ret;
155 }
156
Decode(const std::string & encoded)157 std::vector<uint8_t> DBBase64Utils::Decode(const std::string &encoded)
158 {
159 auto it = encoded.begin();
160 size_t index = 0;
161 std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> charArrayThree = { 0 };
162 std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> charArrayFour = { 0 };
163 std::vector<uint8_t> ret;
164
165 while (it != encoded.end() && IsBase64Char(*it)) {
166 charArrayFour[index] = *it;
167 ++index;
168 ++it;
169 if (index != CHAR_ARRAY_LENGTH_FOUR) {
170 continue;
171 }
172 for (index = 0; index < CHAR_ARRAY_LENGTH_FOUR; ++index) {
173 charArrayFour[index] = BASE64_CHARS.find(static_cast<char>(charArrayFour[index]));
174 }
175 MakeCharTree(charArrayFour, charArrayThree);
176 std::for_each(charArrayThree.begin(), charArrayThree.end(), [&ret](uint8_t idx) {
177 ret.emplace_back(idx);
178 });
179 index = 0;
180 }
181 if (index == 0) {
182 return ret;
183 }
184
185 for (auto i = index; i < CHAR_ARRAY_LENGTH_FOUR; ++i) {
186 charArrayFour[i] = 0;
187 }
188 for (unsigned char &i : charArrayFour) {
189 std::string::size_type idx = BASE64_CHARS.find(static_cast<char>(i));
190 if (idx != std::string::npos) {
191 i = static_cast<unsigned char>(idx);
192 }
193 }
194 MakeCharTree(charArrayFour, charArrayThree);
195
196 for (size_t i = 0; i < index - 1; i++) {
197 ret.emplace_back(charArrayThree[i]);
198 }
199 return ret;
200 }
201
Encode(const std::string & source)202 std::string DBBase64Utils::Encode(const std::string &source)
203 {
204 return Encode(std::vector<uint8_t>(source.begin(), source.end()));
205 }
206
DecodeIfNeed(const std::string & source)207 std::string DBBase64Utils::DecodeIfNeed(const std::string &source)
208 {
209 auto decodeRes = Decode(source);
210 if (decodeRes.empty()) {
211 return source;
212 }
213 return std::string(decodeRes.begin(), decodeRes.end());
214 }
215 }