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