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_DECODE_H
17 #define API_BASE_UTIL_BASE64_DECODE_H
18
19 #include <base/containers/string_view.h>
20 #include <base/containers/vector.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 uint8_t FROM_BASE64[] = {
27 62U, // '+' (ascii 43)
28 0, 0, 0, // invalid
29 63U, // '/' (ascii 47)
30 52U, 53U, 54U, 55U, 56U, 57U, 58U, 59U, 60U, 61U, //'0' '9' (ascii 48-57)
31 0, 0, 0, // invalid
32 0, // '=' padding (ascii 61)
33 0, 0, 0, // invalid
34 0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 11U, 12U, 13U, 14U, 15U, 16U, 17U, 18U, 19U, 20U, 21U, 22U, 23U, 24U,
35 25U, //'A' 'Z' (ascii 65-90)
36 0, 0, 0, 0, 0, 0, // invalid
37 26U, 27U, 28U, 29U, 30U, 31U, 32U, 33U, 34U, 35U, 36U, 37U, 38U, 39U, 40U, 41U, 42U, 43U, 44U, 45U, 46U, 47U, 48U,
38 49U, 50U, 51U //'a' 'z' (ascii 97-122)
39 };
40
41 inline uint8_t FromBase64(uint8_t c)
42 {
43 // Map characters to values from the table if they are in the 43..122 range. Invalid characters will return zeros.
44 if (c >= 43 && c <= 122) {
45 return FROM_BASE64[c - 43];
46 } else {
47 return 0;
48 }
49 }
50
51 inline uint32_t FromBase64(const char*& src)
52 {
53 uint32_t bits = static_cast<uint32_t>(Detail::FromBase64((uint8_t)(*src++))) << (3u * 6u);
54 bits |= Detail::FromBase64((uint8_t)(*src++)) << (2u * 6u);
55 bits |= Detail::FromBase64((uint8_t)(*src++)) << (1u * 6u);
56 bits |= Detail::FromBase64((uint8_t)(*src++)) << (0u * 6u);
57 return bits;
58 }
59
60 inline void DecodeQuartets(uint8_t* dst, const char* src, signed left)
61 {
62 for (; left >= 4; left -= 4) {
63 auto bits = FromBase64(src);
64 *dst++ = uint8_t((bits >> 16u) & 0xff);
65 *dst++ = uint8_t((bits >> 8u) & 0xff);
66 *dst++ = uint8_t((bits >> 0u) & 0xff);
67 }
68 }
69
70 inline size_t CountPadding(string_view encodedString)
71 {
72 auto end = encodedString.end();
73 auto first = --end;
74 while (*first == '=') {
75 --first;
76 }
77 return static_cast<size_t>(end - first);
78 }
79 } // namespace Detail
80
81 /** Decode base64 encoded data.
82 * A base64 encoded string should be padded to the next four bytes with '=' characters.
83 * @param encodedString String containing the base64 encoded data.
84 * @return Decoded data.
85 */
Base64Decode(string_view encodedString)86 inline vector<uint8_t> Base64Decode(string_view encodedString)
87 {
88 // the length of the decoded binary data will be 3/4 of the encoded string.
89 vector<uint8_t> decodedBinary(encodedString.size() * 3u / 4u);
90
91 Detail::DecodeQuartets(decodedBinary.data(), encodedString.data(), static_cast<signed>(encodedString.size()));
92 decodedBinary.erase(
93 decodedBinary.cend() - static_cast<ptrdiff_t>(Detail::CountPadding(encodedString)), decodedBinary.cend());
94 return decodedBinary;
95 }
96 BASE_END_NAMESPACE()
97 #endif // API_BASE_UTIL_BASE64_DECODE_H
98