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 #ifndef API_BASE_UTIL_BASE64_ENCODE_H
17 #define API_BASE_UTIL_BASE64_ENCODE_H
18
19 #include <base/containers/array_view.h>
20 #include <base/containers/string.h>
21 #include <base/namespace.h>
22 #include <base/util/log.h>
23
BASE_BEGIN_NAMESPACE()24 BASE_BEGIN_NAMESPACE()
25 namespace Detail {
26 static constexpr const char TO_BASE64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27
28 inline void ToBase64(const uint8_t* threeBytes, char* output)
29 {
30 output[0U] = TO_BASE64[threeBytes[0u] >> 2u];
31 output[1U] = TO_BASE64[((threeBytes[0u] << 4u) | (threeBytes[1u] >> 4u)) & 0x3f];
32 output[2U] = TO_BASE64[((threeBytes[1u] << 2u) | (threeBytes[2u] >> 6u)) & 0x3f];
33 output[3U] = TO_BASE64[threeBytes[2u] & 0x3f];
34 }
35
36 inline void ToBase64(const uint8_t* threeBytes, char* output, signed left)
37 {
38 output[0U] = TO_BASE64[threeBytes[0u] >> 2u];
39 output[1U] = TO_BASE64[((threeBytes[0u] << 4u) | (threeBytes[1u] >> 4u)) & 0x3f];
40
41 output[2U] = left > 1 ? (TO_BASE64[((threeBytes[1u] << 2u) | (threeBytes[2u] >> 6u)) & 0x3f]) : '=';
42 output[3U] = left > 2 ? TO_BASE64[threeBytes[2u] & 0x3f] : '=';
43 }
44
45 inline signed EncodeTriplets(char*& dst, const uint8_t*& src, signed left)
46 {
47 for (; left >= 3; left -= 3) {
48 Detail::ToBase64(src, dst);
49 src += 3U;
50 dst += 4U;
51 }
52 return left;
53 }
54
55 inline void FillTriplet(uint8_t* dst, const uint8_t*& src, signed left)
56 {
57 switch (left) {
58 case 2:
59 *dst++ = *src++;
60 [[fallthrough]];
61 case 1:
62 *dst++ = *src++;
63 }
64 }
65
66 inline void EncodeTail(char* dst, const uint8_t* src, signed left)
67 {
68 if (left) {
69 uint8_t rest[3] { 0, 0, 0 };
70 FillTriplet(rest, src, left);
71 Detail::ToBase64(rest, dst, left);
72 }
73 }
74 } // namespace Detail
75
76 /** Base 64 encode data.
77 * @param binaryData Data to encode.
78 * @return Data as a base64 string.
79 */
Base64Encode(array_view<const uint8_t> binaryData)80 inline string Base64Encode(array_view<const uint8_t> binaryData)
81 {
82 // The length of the encoded binary data will be about 4/3 of the encoded string.
83 string encodedString((binaryData.size() + 2U) / 3U * 4U, '=');
84
85 auto dst = encodedString.data();
86 auto src = binaryData.data();
87 signed left = static_cast<signed>(binaryData.size());
88
89 // First write the full groups of three bytes
90 left = Detail::EncodeTriplets(dst, src, left);
91
92 // Add the rest of the bytes that was not divisible by three
93 Detail::EncodeTail(dst, src, left);
94
95 return encodedString;
96 }
97 BASE_END_NAMESPACE()
98 #endif // API_BASE_UTIL_BASE64_ENCODE_H