• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <numeric>
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         ret = std::accumulate(charArrayFour.begin(), charArrayFour.end(), std::string(),
113                               [](const std::string &str_append, uint8_t const &idx) {
114                                   return str_append + BASE64_CHARS[idx];
115                               });
116 
117         index = 0;
118     }
119     if (index == 0) {
120         return ret;
121     }
122 
123     for (auto i = index; i < CHAR_ARRAY_LENGTH_THREE; ++i) {
124         charArrayThree[i] = 0;
125     }
126     MakeCharFour(charArrayThree, charArrayFour);
127 
128     for (size_t i = 0; i < index + 1; ++i) {
129         ret += BASE64_CHARS[charArrayFour[i]];
130     }
131 
132     while (index < CHAR_ARRAY_LENGTH_THREE) {
133         ret += '=';
134         ++index;
135     }
136     return ret;
137 }
138 
Decode(const std::string & encoded)139 std::string Decode(const std::string &encoded)
140 {
141     auto it = encoded.begin();
142     size_t index = 0;
143     std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> charArrayThree = {0};
144     std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> charArrayFour = {0};
145     std::string ret;
146 
147     while (it != encoded.end() && IsBase64Char(*it)) {
148         charArrayFour[index] = *it;
149         ++index;
150         ++it;
151         if (index != CHAR_ARRAY_LENGTH_FOUR) {
152             continue;
153         }
154         for (index = 0; index < CHAR_ARRAY_LENGTH_FOUR; ++index) {
155             charArrayFour[index] = BASE64_CHARS.find(static_cast<char>(charArrayFour[index]));
156         }
157         MakeCharTree(charArrayFour, charArrayThree);
158         ret = std::accumulate(charArrayThree.begin(), charArrayThree.end(), std::string(),
159                               [](std::string &str_append, uint8_t const &iter) {
160                                   return str_append + static_cast<char>(iter);
161                               });
162         index = 0;
163     }
164     if (index == 0) {
165         return ret;
166     }
167 
168     for (auto i = index; i < CHAR_ARRAY_LENGTH_FOUR; ++i) {
169         charArrayFour[i] = 0;
170     }
171     for (unsigned char &i : charArrayFour) {
172         std::string::size_type idx = BASE64_CHARS.find(static_cast<char>(i));
173         if (idx != std::string::npos) {
174             i = static_cast<unsigned char>(idx);
175         }
176     }
177     MakeCharTree(charArrayFour, charArrayThree);
178 
179     for (size_t i = 0; i < index - 1; i++) {
180         ret += static_cast<char>(charArrayThree[i]);
181     }
182     return ret;
183 }
184 } // namespace OHOS::NetManagerStandard::Base64
185