blob: 8f1f81020b10df7787044fae6ef7dc8197dae7c4 [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/* ====================================================================
2 * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the Apache Group
19 * for use in the Apache HTTP server project (http://www.apache.org/)."
20 *
21 * 4. The names "Apache Server" and "Apache Group" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For written permission, please contact
24 * apache@apache.org.
25 *
26 * 5. Products derived from this software may not be called "Apache"
27 * nor may "Apache" appear in their names without prior written
28 * permission of the Apache Group.
29 *
30 * 6. Redistributions of any form whatsoever must retain the following
31 * acknowledgment:
32 * "This product includes software developed by the Apache Group
33 * for use in the Apache HTTP server project (http://www.apache.org/)."
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46 * OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Group and was originally based
51 * on public domain software written at the National Center for
52 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
53 * For more information on the Apache Group and the Apache HTTP server
54 * project, please see <http://www.apache.org/>.
55 *
56 */
57
58#include "wpi/Base64.h"
59
60#include "wpi/SmallVector.h"
61#include "wpi/raw_ostream.h"
62
63namespace wpi {
64
65// aaaack but it's fast and const should make it shared text page.
66static const unsigned char pr2six[256] = {
67 // ASCII table
68 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
69 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
70 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60,
71 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
72 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64,
73 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
74 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
75 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
76 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
77 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
78 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
79 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
80 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
81 64, 64, 64, 64, 64, 64, 64, 64, 64};
82
Austin Schuh812d0d12021-11-04 20:16:48 -070083size_t Base64Decode(raw_ostream& os, std::string_view encoded) {
84 auto bytes_begin = reinterpret_cast<const unsigned char*>(encoded.data());
85 auto bytes_end = bytes_begin + encoded.size();
86 const unsigned char* end = bytes_begin;
87 while (pr2six[*end] <= 63 && end != bytes_end) {
88 ++end;
89 }
90 size_t nprbytes = end - bytes_begin;
91 if (nprbytes == 0) {
92 return 0;
93 }
Brian Silverman8fce7482020-01-05 13:18:21 -080094
Austin Schuh812d0d12021-11-04 20:16:48 -070095 const unsigned char* cur = bytes_begin;
Brian Silverman8fce7482020-01-05 13:18:21 -080096
97 while (nprbytes > 4) {
98 os << static_cast<unsigned char>(pr2six[cur[0]] << 2 | pr2six[cur[1]] >> 4);
99 os << static_cast<unsigned char>(pr2six[cur[1]] << 4 | pr2six[cur[2]] >> 2);
100 os << static_cast<unsigned char>(pr2six[cur[2]] << 6 | pr2six[cur[3]]);
101 cur += 4;
102 nprbytes -= 4;
103 }
104
105 // Note: (nprbytes == 1) would be an error, so just ignore that case
Austin Schuh812d0d12021-11-04 20:16:48 -0700106 if (nprbytes > 1) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800107 os << static_cast<unsigned char>(pr2six[cur[0]] << 2 | pr2six[cur[1]] >> 4);
Austin Schuh812d0d12021-11-04 20:16:48 -0700108 }
109 if (nprbytes > 2) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800110 os << static_cast<unsigned char>(pr2six[cur[1]] << 4 | pr2six[cur[2]] >> 2);
Austin Schuh812d0d12021-11-04 20:16:48 -0700111 }
112 if (nprbytes > 3) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800113 os << static_cast<unsigned char>(pr2six[cur[2]] << 6 | pr2six[cur[3]]);
Austin Schuh812d0d12021-11-04 20:16:48 -0700114 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800115
Austin Schuh812d0d12021-11-04 20:16:48 -0700116 return (end - bytes_begin) + ((4 - nprbytes) & 3);
Brian Silverman8fce7482020-01-05 13:18:21 -0800117}
118
Austin Schuh812d0d12021-11-04 20:16:48 -0700119size_t Base64Decode(std::string_view encoded, std::string* plain) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800120 plain->resize(0);
121 raw_string_ostream os(*plain);
122 size_t rv = Base64Decode(os, encoded);
123 os.flush();
124 return rv;
125}
126
Austin Schuh812d0d12021-11-04 20:16:48 -0700127std::string_view Base64Decode(std::string_view encoded, size_t* num_read,
128 SmallVectorImpl<char>& buf) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800129 buf.clear();
130 raw_svector_ostream os(buf);
131 *num_read = Base64Decode(os, encoded);
132 return os.str();
133}
134
Austin Schuh812d0d12021-11-04 20:16:48 -0700135size_t Base64Decode(std::string_view encoded, std::vector<uint8_t>* plain) {
136 plain->resize(0);
137 raw_uvector_ostream os(*plain);
138 return Base64Decode(os, encoded);
139}
140
141span<uint8_t> Base64Decode(std::string_view encoded, size_t* num_read,
142 SmallVectorImpl<uint8_t>& buf) {
143 buf.clear();
144 raw_usvector_ostream os(buf);
145 *num_read = Base64Decode(os, encoded);
146 return os.array();
147}
148
Brian Silverman8fce7482020-01-05 13:18:21 -0800149static const char basis_64[] =
150 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
151
Austin Schuh812d0d12021-11-04 20:16:48 -0700152void Base64Encode(raw_ostream& os, std::string_view plain) {
153 if (plain.empty()) {
154 return;
155 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800156 size_t len = plain.size();
157
158 size_t i;
159 for (i = 0; (i + 2) < len; i += 3) {
160 os << basis_64[(plain[i] >> 2) & 0x3F];
161 os << basis_64[((plain[i] & 0x3) << 4) |
162 (static_cast<int>(plain[i + 1] & 0xF0) >> 4)];
163 os << basis_64[((plain[i + 1] & 0xF) << 2) |
164 (static_cast<int>(plain[i + 2] & 0xC0) >> 6)];
165 os << basis_64[plain[i + 2] & 0x3F];
166 }
167 if (i < len) {
168 os << basis_64[(plain[i] >> 2) & 0x3F];
169 if (i == (len - 1)) {
170 os << basis_64[((plain[i] & 0x3) << 4)];
171 os << '=';
172 } else {
173 os << basis_64[((plain[i] & 0x3) << 4) |
174 (static_cast<int>(plain[i + 1] & 0xF0) >> 4)];
175 os << basis_64[((plain[i + 1] & 0xF) << 2)];
176 }
177 os << '=';
178 }
179}
180
Austin Schuh812d0d12021-11-04 20:16:48 -0700181void Base64Encode(std::string_view plain, std::string* encoded) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800182 encoded->resize(0);
183 raw_string_ostream os(*encoded);
184 Base64Encode(os, plain);
185 os.flush();
186}
187
Austin Schuh812d0d12021-11-04 20:16:48 -0700188std::string_view Base64Encode(std::string_view plain,
189 SmallVectorImpl<char>& buf) {
190 buf.clear();
191 raw_svector_ostream os(buf);
192 Base64Encode(os, plain);
193 return os.str();
194}
195
196void Base64Encode(raw_ostream& os, span<const uint8_t> plain) {
197 Base64Encode(os, std::string_view{reinterpret_cast<const char*>(plain.data()),
198 plain.size()});
199}
200
201void Base64Encode(span<const uint8_t> plain, std::string* encoded) {
202 encoded->resize(0);
203 raw_string_ostream os(*encoded);
204 Base64Encode(os, plain);
205 os.flush();
206}
207
208std::string_view Base64Encode(span<const uint8_t> plain,
209 SmallVectorImpl<char>& buf) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800210 buf.clear();
211 raw_svector_ostream os(buf);
212 Base64Encode(os, plain);
213 return os.str();
214}
215
216} // namespace wpi