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 "base64_utils.h"
17
18 #include <array>
19
20 namespace OHOS::NetStack::Base64 {
21 #ifdef __linux__
22 static std::string 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 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 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 inline 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[BASE64_ENCODE_INDEX0] & BASE64_ENCODE_MASK1) >> BASE64_ENCODE_OFFSET2),
69 static_cast<uint8_t>(((charArrayThree[BASE64_ENCODE_INDEX0] & BASE64_ENCODE_MASK2) << BASE64_ENCODE_OFFSET4) +
70 ((charArrayThree[BASE64_ENCODE_INDEX1] & BASE64_ENCODE_MASK5) >> BASE64_ENCODE_OFFSET4)),
71 static_cast<uint8_t>(((charArrayThree[BASE64_ENCODE_INDEX1] & BASE64_ENCODE_MASK3) << BASE64_ENCODE_OFFSET2) +
72 ((charArrayThree[BASE64_ENCODE_INDEX2] & BASE64_ENCODE_MASK6) >> BASE64_ENCODE_OFFSET6)),
73 static_cast<uint8_t>(charArrayThree[BASE64_ENCODE_INDEX2] & BASE64_ENCODE_MASK4),
74 };
75 for (size_t index = 0; index < CHAR_ARRAY_LENGTH_FOUR; ++index) {
76 charArrayFour[index] = table[index];
77 }
78 }
79
MakeCharTree(const std::array<uint8_t,CHAR_ARRAY_LENGTH_FOUR> & charArrayFour,std::array<uint8_t,CHAR_ARRAY_LENGTH_THREE> & charArrayThree)80 static inline void MakeCharTree(const std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> &charArrayFour,
81 std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> &charArrayThree)
82 {
83 const uint8_t table[CHAR_ARRAY_LENGTH_THREE] = {
84 static_cast<uint8_t>((charArrayFour[BASE64_DECODE_INDEX0] << BASE64_DECODE_OFFSET2) +
85 ((charArrayFour[BASE64_DECODE_INDEX1] & BASE64_DECODE_MASK1) >> BASE64_DECODE_OFFSET4)),
86 static_cast<uint8_t>(((charArrayFour[BASE64_DECODE_INDEX1] & BASE64_DECODE_MASK2) << BASE64_DECODE_OFFSET4) +
87 ((charArrayFour[BASE64_DECODE_INDEX2] & BASE64_DECODE_MASK3) >> BASE64_DECODE_OFFSET2)),
88 static_cast<uint8_t>(((charArrayFour[BASE64_DECODE_INDEX2] & BASE64_DECODE_MASK4) << BASE64_DECODE_OFFSET6) +
89 charArrayFour[BASE64_DECODE_INDEX3]),
90 };
91 for (size_t index = 0; index < CHAR_ARRAY_LENGTH_THREE; ++index) {
92 charArrayThree[index] = table[index];
93 }
94 }
95
96 #endif
97
Encode(const std::string & source)98 std::string Encode(const std::string &source)
99 {
100 #ifdef __linux__
101 auto it = source.begin();
102 std::string ret;
103 size_t index = 0;
104 std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> charArrayThree = {0};
105 std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> charArrayFour = {0};
106
107 while (it != source.end()) {
108 charArrayThree[index] = *it;
109 ++index;
110 ++it;
111 if (index != CHAR_ARRAY_LENGTH_THREE) {
112 continue;
113 }
114 MakeCharFour(charArrayThree, charArrayFour);
115 for (auto idx : charArrayFour) {
116 ret += BASE64_CHARS[idx];
117 }
118 index = 0;
119 }
120 if (index == 0) {
121 return ret;
122 }
123
124 for (auto i = index; i < CHAR_ARRAY_LENGTH_THREE; ++i) {
125 charArrayThree[i] = 0;
126 }
127 MakeCharFour(charArrayThree, charArrayFour);
128
129 for (size_t i = 0; i < index + 1; ++i) {
130 ret += BASE64_CHARS[charArrayFour[i]];
131 }
132
133 while (index < CHAR_ARRAY_LENGTH_THREE) {
134 ret += '=';
135 ++index;
136 }
137 return ret;
138 #else
139 return {};
140 #endif
141 }
142
Decode(const std::string & encoded)143 std::string Decode(const std::string &encoded)
144 {
145 #ifdef __linux__
146 auto it = encoded.begin();
147 size_t index = 0;
148 std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> charArrayThree = {0};
149 std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> charArrayFour = {0};
150 std::string ret;
151
152 while (it != encoded.end() && IsBase64Char(*it)) {
153 charArrayFour[index] = *it;
154 ++index;
155 ++it;
156 if (index != CHAR_ARRAY_LENGTH_FOUR) {
157 continue;
158 }
159 for (index = 0; index < CHAR_ARRAY_LENGTH_FOUR; ++index) {
160 charArrayFour[index] = BASE64_CHARS.find(static_cast<char>(charArrayFour[index]));
161 }
162 MakeCharTree(charArrayFour, charArrayThree);
163 for (auto idx : charArrayThree) {
164 ret += static_cast<char>(idx);
165 }
166 index = 0;
167 }
168 if (index == 0) {
169 return ret;
170 }
171
172 for (auto i = index; i < CHAR_ARRAY_LENGTH_FOUR; ++i) {
173 charArrayFour[i] = 0;
174 }
175 for (unsigned char &i : charArrayFour) {
176 i = BASE64_CHARS.find(static_cast<char>(i));
177 }
178 MakeCharTree(charArrayFour, charArrayThree);
179
180 for (size_t i = 0; i < index - 1; i++) {
181 ret += static_cast<char>(charArrayThree[i]);
182 }
183 return ret;
184 #else
185 return {};
186 #endif
187 }
188 } // namespace OHOS::NetStack::Base64