/src/node/src/base64-inl.h
Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef SRC_BASE64_INL_H_ |
2 | | #define SRC_BASE64_INL_H_ |
3 | | |
4 | | #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
5 | | |
6 | | #include "base64.h" |
7 | | #include "libbase64.h" |
8 | | #include "util.h" |
9 | | |
10 | | namespace node { |
11 | | |
12 | | static constexpr char base64_table_url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
13 | | "abcdefghijklmnopqrstuvwxyz" |
14 | | "0123456789-_"; |
15 | | |
16 | | extern const int8_t unbase64_table[256]; |
17 | | |
18 | | |
19 | 23 | inline static int8_t unbase64(uint8_t x) { |
20 | 23 | return unbase64_table[x]; |
21 | 23 | } Unexecuted instantiation: cares_wrap.cc:node::unbase64(unsigned char) Unexecuted instantiation: node_sockaddr.cc:node::unbase64(unsigned char) string_bytes.cc:node::unbase64(unsigned char) Line | Count | Source | 19 | 23 | inline static int8_t unbase64(uint8_t x) { | 20 | 23 | return unbase64_table[x]; | 21 | 23 | } |
Unexecuted instantiation: inspector_socket.cc:node::unbase64(unsigned char) |
22 | | |
23 | | |
24 | 90 | inline uint32_t ReadUint32BE(const unsigned char* p) { |
25 | 90 | return static_cast<uint32_t>(p[0] << 24U) | |
26 | 90 | static_cast<uint32_t>(p[1] << 16U) | |
27 | 90 | static_cast<uint32_t>(p[2] << 8U) | |
28 | 90 | static_cast<uint32_t>(p[3]); |
29 | 90 | } |
30 | | |
31 | | #ifdef _MSC_VER |
32 | | #pragma warning(push) |
33 | | // MSVC C4003: not enough actual parameters for macro 'identifier' |
34 | | #pragma warning(disable : 4003) |
35 | | #endif |
36 | | |
37 | | template <typename TypeName> |
38 | | bool base64_decode_group_slow(char* const dst, const size_t dstlen, |
39 | | const TypeName* const src, const size_t srclen, |
40 | 1 | size_t* const i, size_t* const k) { |
41 | 1 | uint8_t hi; |
42 | 1 | uint8_t lo; |
43 | 1 | #define V(expr) \ |
44 | 3 | for (;;) { \ |
45 | 3 | const uint8_t c = static_cast<uint8_t>(src[*i]); \ |
46 | 3 | lo = unbase64(c); \ |
47 | 3 | *i += 1; \ |
48 | 3 | if (lo < 64) break; /* Legal character. */ \ |
49 | 3 | if (c == '=' || *i >= srclen) return false; /* Stop decoding. */ \ |
50 | 0 | } \ |
51 | 3 | expr; \ |
52 | 3 | if (*i >= srclen) return false; \ |
53 | 3 | if (*k >= dstlen) return false; \ |
54 | 3 | hi = lo; |
55 | 3 | V(/* Nothing. */); |
56 | 3 | V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); |
57 | 3 | V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); |
58 | 2 | V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); |
59 | 0 | #undef V |
60 | 0 | return true; // Continue decoding. |
61 | 0 | } Unexecuted instantiation: bool node::base64_decode_group_slow<char>(char*, unsigned long, char const*, unsigned long, unsigned long*, unsigned long*) bool node::base64_decode_group_slow<unsigned short>(char*, unsigned long, unsigned short const*, unsigned long, unsigned long*, unsigned long*) Line | Count | Source | 40 | 1 | size_t* const i, size_t* const k) { | 41 | 1 | uint8_t hi; | 42 | 1 | uint8_t lo; | 43 | 1 | #define V(expr) \ | 44 | 1 | for (;;) { \ | 45 | 1 | const uint8_t c = static_cast<uint8_t>(src[*i]); \ | 46 | 1 | lo = unbase64(c); \ | 47 | 1 | *i += 1; \ | 48 | 1 | if (lo < 64) break; /* Legal character. */ \ | 49 | 1 | if (c == '=' || *i >= srclen) return false; /* Stop decoding. */ \ | 50 | 1 | } \ | 51 | 1 | expr; \ | 52 | 1 | if (*i >= srclen) return false; \ | 53 | 1 | if (*k >= dstlen) return false; \ | 54 | 1 | hi = lo; | 55 | 3 | V(/* Nothing. */); | 56 | 3 | V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); | 57 | 3 | V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); | 58 | 2 | V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); | 59 | 0 | #undef V | 60 | 0 | return true; // Continue decoding. | 61 | 0 | } |
|
62 | | |
63 | | #ifdef _MSC_VER |
64 | | #pragma warning(pop) |
65 | | #endif |
66 | | |
67 | | template <typename TypeName> |
68 | | size_t base64_decode_fast(char* const dst, const size_t dstlen, |
69 | | const TypeName* const src, const size_t srclen, |
70 | 2 | const size_t decoded_size) { |
71 | 2 | const size_t available = dstlen < decoded_size ? dstlen : decoded_size; |
72 | 2 | const size_t max_k = available / 3 * 3; |
73 | 2 | size_t max_i = srclen / 4 * 4; |
74 | 2 | size_t i = 0; |
75 | 2 | size_t k = 0; |
76 | 7 | while (i < max_i && k < max_k) { |
77 | 5 | const unsigned char txt[] = { |
78 | 5 | static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 0]))), |
79 | 5 | static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 1]))), |
80 | 5 | static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 2]))), |
81 | 5 | static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 3]))), |
82 | 5 | }; |
83 | | |
84 | 5 | const uint32_t v = ReadUint32BE(txt); |
85 | | // If MSB is set, input contains whitespace or is not valid base64. |
86 | 5 | if (v & 0x80808080) { |
87 | 0 | if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k)) |
88 | 0 | return k; |
89 | 0 | max_i = i + (srclen - i) / 4 * 4; // Align max_i again. |
90 | 5 | } else { |
91 | 5 | dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); |
92 | 5 | dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); |
93 | 5 | dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F); |
94 | 5 | i += 4; |
95 | 5 | k += 3; |
96 | 5 | } |
97 | 5 | } |
98 | 2 | if (i < srclen && k < dstlen) { |
99 | 1 | base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k); |
100 | 1 | } |
101 | 2 | return k; |
102 | 2 | } Unexecuted instantiation: unsigned long node::base64_decode_fast<char>(char*, unsigned long, char const*, unsigned long, unsigned long) unsigned long node::base64_decode_fast<unsigned short>(char*, unsigned long, unsigned short const*, unsigned long, unsigned long) Line | Count | Source | 70 | 2 | const size_t decoded_size) { | 71 | 2 | const size_t available = dstlen < decoded_size ? dstlen : decoded_size; | 72 | 2 | const size_t max_k = available / 3 * 3; | 73 | 2 | size_t max_i = srclen / 4 * 4; | 74 | 2 | size_t i = 0; | 75 | 2 | size_t k = 0; | 76 | 7 | while (i < max_i && k < max_k) { | 77 | 5 | const unsigned char txt[] = { | 78 | 5 | static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 0]))), | 79 | 5 | static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 1]))), | 80 | 5 | static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 2]))), | 81 | 5 | static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 3]))), | 82 | 5 | }; | 83 | | | 84 | 5 | const uint32_t v = ReadUint32BE(txt); | 85 | | // If MSB is set, input contains whitespace or is not valid base64. | 86 | 5 | if (v & 0x80808080) { | 87 | 0 | if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k)) | 88 | 0 | return k; | 89 | 0 | max_i = i + (srclen - i) / 4 * 4; // Align max_i again. | 90 | 5 | } else { | 91 | 5 | dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); | 92 | 5 | dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); | 93 | 5 | dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F); | 94 | 5 | i += 4; | 95 | 5 | k += 3; | 96 | 5 | } | 97 | 5 | } | 98 | 2 | if (i < srclen && k < dstlen) { | 99 | 1 | base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k); | 100 | 1 | } | 101 | 2 | return k; | 102 | 2 | } |
|
103 | | |
104 | | |
105 | | template <typename TypeName> |
106 | 2 | size_t base64_decoded_size(const TypeName* src, size_t size) { |
107 | | // 1-byte input cannot be decoded |
108 | 2 | if (size < 2) |
109 | 0 | return 0; |
110 | | |
111 | 2 | if (src[size - 1] == '=') { |
112 | 1 | size--; |
113 | 1 | if (src[size - 1] == '=') |
114 | 0 | size--; |
115 | 1 | } |
116 | 2 | return base64_decoded_size_fast(size); |
117 | 2 | } Unexecuted instantiation: unsigned long node::base64_decoded_size<char>(char const*, unsigned long) unsigned long node::base64_decoded_size<unsigned short>(unsigned short const*, unsigned long) Line | Count | Source | 106 | 2 | size_t base64_decoded_size(const TypeName* src, size_t size) { | 107 | | // 1-byte input cannot be decoded | 108 | 2 | if (size < 2) | 109 | 0 | return 0; | 110 | | | 111 | 2 | if (src[size - 1] == '=') { | 112 | 1 | size--; | 113 | 1 | if (src[size - 1] == '=') | 114 | 0 | size--; | 115 | 1 | } | 116 | 2 | return base64_decoded_size_fast(size); | 117 | 2 | } |
|
118 | | |
119 | | |
120 | | template <typename TypeName> |
121 | | size_t base64_decode(char* const dst, const size_t dstlen, |
122 | 2 | const TypeName* const src, const size_t srclen) { |
123 | 2 | const size_t decoded_size = base64_decoded_size(src, srclen); |
124 | 2 | return base64_decode_fast(dst, dstlen, src, srclen, decoded_size); |
125 | 2 | } Unexecuted instantiation: unsigned long node::base64_decode<char>(char*, unsigned long, char const*, unsigned long) unsigned long node::base64_decode<unsigned short>(char*, unsigned long, unsigned short const*, unsigned long) Line | Count | Source | 122 | 2 | const TypeName* const src, const size_t srclen) { | 123 | 2 | const size_t decoded_size = base64_decoded_size(src, srclen); | 124 | 2 | return base64_decode_fast(dst, dstlen, src, srclen, decoded_size); | 125 | 2 | } |
|
126 | | |
127 | | |
128 | | inline size_t base64_encode(const char* src, |
129 | | size_t slen, |
130 | | char* dst, |
131 | | size_t dlen, |
132 | 1 | Base64Mode mode) { |
133 | | // We know how much we'll write, just make sure that there's space. |
134 | 1 | CHECK(dlen >= base64_encoded_size(slen, mode) && |
135 | 1 | "not enough space provided for base64 encode"); |
136 | | |
137 | 1 | dlen = base64_encoded_size(slen, mode); |
138 | | |
139 | 1 | if (mode == Base64Mode::NORMAL) { |
140 | 1 | ::base64_encode(src, slen, dst, &dlen, 0); |
141 | 1 | return dlen; |
142 | 1 | } |
143 | | |
144 | 0 | unsigned a; |
145 | 0 | unsigned b; |
146 | 0 | unsigned c; |
147 | 0 | unsigned i; |
148 | 0 | unsigned k; |
149 | 0 | unsigned n; |
150 | |
|
151 | 0 | const char* table = base64_table_url; |
152 | |
|
153 | 0 | i = 0; |
154 | 0 | k = 0; |
155 | 0 | n = slen / 3 * 3; |
156 | |
|
157 | 0 | while (i < n) { |
158 | 0 | a = src[i + 0] & 0xff; |
159 | 0 | b = src[i + 1] & 0xff; |
160 | 0 | c = src[i + 2] & 0xff; |
161 | |
|
162 | 0 | dst[k + 0] = table[a >> 2]; |
163 | 0 | dst[k + 1] = table[((a & 3) << 4) | (b >> 4)]; |
164 | 0 | dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)]; |
165 | 0 | dst[k + 3] = table[c & 0x3f]; |
166 | |
|
167 | 0 | i += 3; |
168 | 0 | k += 4; |
169 | 0 | } |
170 | |
|
171 | 0 | switch (slen - n) { |
172 | 0 | case 1: |
173 | 0 | a = src[i + 0] & 0xff; |
174 | 0 | dst[k + 0] = table[a >> 2]; |
175 | 0 | dst[k + 1] = table[(a & 3) << 4]; |
176 | 0 | break; |
177 | 0 | case 2: |
178 | 0 | a = src[i + 0] & 0xff; |
179 | 0 | b = src[i + 1] & 0xff; |
180 | 0 | dst[k + 0] = table[a >> 2]; |
181 | 0 | dst[k + 1] = table[((a & 3) << 4) | (b >> 4)]; |
182 | 0 | dst[k + 2] = table[(b & 0x0f) << 2]; |
183 | 0 | break; |
184 | 0 | } |
185 | | |
186 | 0 | return dlen; |
187 | 0 | } |
188 | | |
189 | | } // namespace node |
190 | | |
191 | | #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
192 | | |
193 | | #endif // SRC_BASE64_INL_H_ |