Line data Source code
1 : #include "base64.h"
2 :
3 : #include <cstddef>
4 : #include <cstdint>
5 :
6 : namespace datadog {
7 : namespace tracing {
8 :
9 : constexpr uint8_t k_sentinel = 255;
10 : constexpr uint8_t _ = k_sentinel; // for brevity
11 : constexpr uint8_t k_eol = 0;
12 :
13 : // Invalid inputs are mapped to the value 255. '=' maps to 0.
14 : constexpr uint8_t k_base64_table[] = {
15 : _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
16 : _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
17 : _, _, _, _, _, _, _, 62, _, _, _, 63, 52, 53, 54, 55, 56, 57,
18 : 58, 59, 60, 61, _, _, _, k_eol, _, _, _, 0, 1, 2, 3, 4, 5, 6,
19 : 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
20 : 25, _, _, _, _, _, _, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
21 : 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, _, _, _,
22 : _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
23 : _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
24 : _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
25 : _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
26 : _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
27 : _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
28 : _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
29 : _, _, _, _};
30 :
31 34 : std::string base64_decode(StringView input) {
32 34 : const size_t in_size = input.size();
33 :
34 34 : std::string output;
35 34 : output.reserve(in_size);
36 :
37 34 : size_t i = 0;
38 :
39 2542 : for (; i + 4 < in_size;) {
40 2511 : uint32_t c0 = k_base64_table[static_cast<size_t>(input[i++])];
41 2511 : uint32_t c1 = k_base64_table[static_cast<size_t>(input[i++])];
42 2511 : uint32_t c2 = k_base64_table[static_cast<size_t>(input[i++])];
43 2511 : uint32_t c3 = k_base64_table[static_cast<size_t>(input[i++])];
44 :
45 2511 : if (c0 == k_sentinel || c1 == k_sentinel || c2 == k_sentinel ||
46 : c3 == k_sentinel) {
47 3 : return "";
48 : }
49 :
50 2508 : output.push_back(c0 << 2 | (c1 & 0xF0) >> 4);
51 2508 : output.push_back((c1 & 0x0F) << 4 | ((c2 & 0x3C) >> 2));
52 2508 : output.push_back(((c2 & 0x03) << 6) | (c3 & 0x3F));
53 : }
54 :
55 : // If padding is missing, return the empty string in lieu of an Error.
56 31 : if ((in_size - i) < 4) return "";
57 :
58 28 : uint32_t c0 = k_base64_table[static_cast<size_t>(input[i++])];
59 28 : uint32_t c1 = k_base64_table[static_cast<size_t>(input[i++])];
60 28 : uint32_t c2 = k_base64_table[static_cast<size_t>(input[i++])];
61 28 : uint32_t c3 = k_base64_table[static_cast<size_t>(input[i++])];
62 :
63 28 : if (c0 == k_sentinel || c1 == k_sentinel || c2 == k_sentinel ||
64 : c3 == k_sentinel) {
65 1 : return "";
66 : }
67 :
68 27 : if (c2 == k_eol) {
69 : // The last quadruplet is of the form "xx==", where only one character needs
70 : // to be decoded.
71 2 : output.push_back(c0 << 2 | (c1 & 0xF0) >> 4);
72 25 : } else if (c3 == k_eol) {
73 : // The last quadruplet is of the form "xxx=", where only two character needs
74 : // to be decoded.
75 7 : output.push_back(c0 << 2 | (c1 & 0xF0) >> 4);
76 7 : output.push_back((c1 & 0x0F) << 4 | ((c2 & 0x3C) >> 2));
77 : } else {
78 : // The last quadruplet is not padded -> common use case
79 18 : output.push_back(c0 << 2 | (c1 & 0xF0) >> 4);
80 18 : output.push_back((c1 & 0x0F) << 4 | ((c2 & 0x3C) >> 2));
81 18 : output.push_back(((c2 & 0x03) << 6) | (c3 & 0x3F));
82 : }
83 :
84 27 : return output;
85 34 : }
86 :
87 : } // namespace tracing
88 : } // namespace datadog
|