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 #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 case 1:
61 *dst++ = *src++;
62 }
63 }
64
65 inline void EncodeTail(char* dst, const uint8_t* src, signed left)
66 {
67 if (left) {
68 uint8_t rest[3] { 0, 0, 0 };
69 FillTriplet(rest, src, left);
70 Detail::ToBase64(rest, dst, left);
71 }
72 }
73 } // namespace Detail
74
75 /** Base 64 encode data.
76 * @param binaryData Data to encode.
77 * @return Data as a base64 string.
78 */
Base64Encode(array_view<const uint8_t> binaryData)79 inline string Base64Encode(array_view<const uint8_t> binaryData)
80 {
81 // The length of the encoded binary data will be about 4/3 of the encoded string.
82 string encodedString((binaryData.size() + 2U) / 3U * 4U, '=');
83
84 auto dst = encodedString.data();
85 auto src = binaryData.data();
86 signed left = static_cast<signed>(binaryData.size());
87
88 // First write the full groups of three bytes
89 left = Detail::EncodeTriplets(dst, src, left);
90
91 // Add the rest of the bytes that was not divisible by three
92 Detail::EncodeTail(dst, src, left);
93
94 return encodedString;
95 }
96 BASE_END_NAMESPACE()
97 #endif // API_BASE_UTIL_BASE64_ENCODE_H