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 <array>
17 #include <algorithm>
18
19 #include "base64_utils.h"
20
21 namespace OHOS::NetManagerStandard::Base64 {
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
Encode(const std::string & source)96 std::string Encode(const std::string &source)
97 {
98 auto it = source.begin();
99 std::string ret;
100 size_t index = 0;
101 std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> charArrayThree = {0};
102 std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> charArrayFour = {0};
103
104 while (it != source.end()) {
105 charArrayThree[index] = *it;
106 ++index;
107 ++it;
108 if (index != CHAR_ARRAY_LENGTH_THREE) {
109 continue;
110 }
111 MakeCharFour(charArrayThree, charArrayFour);
112 std::for_each(charArrayFour.begin(), charArrayFour.end(), [&ret](uint8_t idx) {
113 ret += BASE64_CHARS[idx];
114 });
115 index = 0;
116 }
117 if (index == 0) {
118 return ret;
119 }
120
121 for (auto i = index; i < CHAR_ARRAY_LENGTH_THREE; ++i) {
122 charArrayThree[i] = 0;
123 }
124 MakeCharFour(charArrayThree, charArrayFour);
125
126 for (size_t i = 0; i < index + 1; ++i) {
127 ret += BASE64_CHARS[charArrayFour[i]];
128 }
129
130 while (index < CHAR_ARRAY_LENGTH_THREE) {
131 ret += '=';
132 ++index;
133 }
134 return ret;
135 }
136
Decode(const std::string & encoded)137 std::string Decode(const std::string &encoded)
138 {
139 auto it = encoded.begin();
140 size_t index = 0;
141 std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> charArrayThree = {0};
142 std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> charArrayFour = {0};
143 std::string ret;
144
145 while (it != encoded.end() && IsBase64Char(*it)) {
146 charArrayFour[index] = *it;
147 ++index;
148 ++it;
149 if (index != CHAR_ARRAY_LENGTH_FOUR) {
150 continue;
151 }
152 for (index = 0; index < CHAR_ARRAY_LENGTH_FOUR; ++index) {
153 charArrayFour[index] = BASE64_CHARS.find(static_cast<char>(charArrayFour[index]));
154 }
155 MakeCharTree(charArrayFour, charArrayThree);
156 std::for_each(charArrayThree.begin(), charArrayThree.end(), [&ret](uint8_t idx) {
157 ret += static_cast<char>(idx);
158 });
159 index = 0;
160 }
161 if (index == 0) {
162 return ret;
163 }
164
165 for (auto i = index; i < CHAR_ARRAY_LENGTH_FOUR; ++i) {
166 charArrayFour[i] = 0;
167 }
168 for (unsigned char &i : charArrayFour) {
169 std::string::size_type idx = BASE64_CHARS.find(static_cast<char>(i));
170 if (idx != std::string::npos) {
171 i = static_cast<unsigned char>(idx);
172 }
173 }
174 MakeCharTree(charArrayFour, charArrayThree);
175
176 for (size_t i = 0; i < index - 1; i++) {
177 ret += static_cast<char>(charArrayThree[i]);
178 }
179 return ret;
180 }
181 } // namespace OHOS::NetManagerStandard::Base64
182