Mercurial > libbase64
annotate base64.hpp @ 19:436f5c3243bf
Add C implementation
While here, update years
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 24 Jan 2020 13:57:48 +0100 |
parents | bdc4fde21426 |
children | 9205a516264d |
rev | line source |
---|---|
0 | 1 /* |
2 * base64.hpp -- base64 encoding and decoding | |
3 * | |
19 | 4 * Copyright (c) 2013-2020 David Demelier <markand@malikania.fr> |
0 | 5 * |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #ifndef BASE64_HPP | |
20 #define BASE64_HPP | |
21 | |
22 /** | |
23 * \file base64.hpp | |
24 * \brief Base64 encoding and decoding. | |
25 * \author David Demelier <markand@malikania.fr> | |
9
24e675edeab8
Remove bitbucket-pipelines.yml
David Demelier <markand@malikania.fr>
parents:
5
diff
changeset
|
26 * \version 2.0.0-dev |
0 | 27 */ |
28 | |
29 /** | |
30 * \page Base64 Base64 | |
31 * \brief Base64 encoding and decoding. | |
32 * | |
33 * The %base64 library let you encode and decode %base64 data from std::string | |
34 * and iterators. | |
35 * | |
36 * ## Encoding | |
37 * | |
38 * You can encode like this: | |
39 * | |
40 * ````cpp | |
41 * std::string b64 = base64::encode("Hello world!"); | |
42 * ```` | |
43 * | |
44 * ## Decoding | |
45 * | |
46 * And you can decode like this: | |
47 * | |
48 * ```` | |
49 * try { | |
18 | 50 * std::string text = base64::decode(msg); |
0 | 51 * } catch (const std::exception &ex) { |
18 | 52 * std::cerr << ex.what() << std::endl; |
0 | 53 * } |
54 * ```` | |
55 */ | |
56 | |
57 #include <cassert> | |
58 #include <cctype> | |
59 #include <stdexcept> | |
60 #include <string> | |
17
0b524d7b7669
Use C++17 std::string_view
David Demelier <markand@malikania.fr>
parents:
15
diff
changeset
|
61 #include <string_view> |
0 | 62 |
63 /** | |
64 * \brief main %base64 namespace. | |
65 */ | |
66 namespace base64 { | |
67 | |
68 /** | |
69 * Check if the character is a %base64 character, A-Za-z0-9 and +/. | |
70 * | |
71 * \param ch the character to test | |
72 * \return true if valid | |
73 */ | |
18 | 74 inline auto is_base64(char ch) noexcept -> bool |
0 | 75 { |
18 | 76 return std::isalnum(ch) != 0 || ch == '+' || ch == '/'; |
0 | 77 } |
78 | |
79 /** | |
80 * Check if the given character is a valid character in %base64 string, | |
81 * including '='. | |
82 * | |
83 * \param ch the character | |
84 * \return true if the character is valid | |
85 */ | |
18 | 86 inline auto is_valid(char ch) noexcept -> bool |
0 | 87 { |
18 | 88 return is_base64(ch) || ch == '='; |
0 | 89 } |
90 | |
91 /** | |
92 * Get the %base64 character from the 6-bits value. | |
93 * | |
94 * \pre value must be valid (< 64) | |
95 * \param value the value | |
96 * \return the %base64 character for value | |
97 */ | |
18 | 98 inline auto lookup(unsigned char value) noexcept -> char |
0 | 99 { |
18 | 100 static std::string_view table("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); |
0 | 101 |
18 | 102 assert(value < 64); |
0 | 103 |
18 | 104 return table[value]; |
0 | 105 } |
106 | |
107 /** | |
108 * Get the integer value from the %base64 character. | |
109 * | |
9
24e675edeab8
Remove bitbucket-pipelines.yml
David Demelier <markand@malikania.fr>
parents:
5
diff
changeset
|
110 * \pre is_base64(ch) |
0 | 111 * \param ch the %base64 character |
112 * \return the integer value for the %base64 character ch | |
113 * ```` | |
114 * auto b64 = base64::rlookup('D') // 3 | |
115 * ```` | |
116 */ | |
18 | 117 inline auto rlookup(char ch) noexcept -> unsigned char |
0 | 118 { |
18 | 119 assert(is_base64(ch)); |
0 | 120 |
18 | 121 if (ch >= '0' && ch <= '9') |
122 return static_cast<unsigned char>(ch + 4); | |
123 if (ch >= 'A' && ch <= 'Z') | |
124 return static_cast<unsigned char>(ch - 65); | |
125 if (ch >= 'a' && ch <= 'z') | |
126 return static_cast<unsigned char>(ch - 71); | |
0 | 127 |
18 | 128 return (ch == '+') ? 62U : 63U; |
0 | 129 } |
130 | |
131 /** | |
132 * Encode the input to the output. | |
133 * | |
134 * Requirements: | |
135 * - **InputIt** must be [InputIterator](http://en.cppreference.com/w/cpp/concept/InputIterator) | |
136 * - **OutputIt** must be [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator) | |
137 * | |
138 * \param input the beginning | |
139 * \param end the end of the data | |
140 * \param output the output destination | |
141 * \return output | |
142 */ | |
143 template <typename InputIt, typename OutputIt> | |
18 | 144 auto encode(InputIt input, InputIt end, OutputIt output) -> OutputIt |
0 | 145 { |
18 | 146 while (input != end) { |
147 char inputbuf[3] = { 0, 0, 0 }; | |
148 int count; | |
0 | 149 |
18 | 150 for (count = 0; count < 3 && input != end; ++count) |
151 inputbuf[count] = *input++; | |
0 | 152 |
18 | 153 *output++ = lookup(inputbuf[0] >> 2 & 0x3f); |
154 *output++ = lookup((inputbuf[0] << 4 & 0x3f) | (inputbuf[1] >> 4 & 0x0f)); | |
155 *output++ = (count < 2) ? '=' : lookup((inputbuf[1] << 2 & 0x3c) | (inputbuf[2] >> 6 & 0x03)); | |
156 *output++ = (count < 3) ? '=' : lookup(inputbuf[2] & 0x3f); | |
157 } | |
0 | 158 |
18 | 159 return output; |
0 | 160 } |
161 | |
162 /** | |
163 * Decode the input to the output. | |
164 * | |
165 * Requirements: | |
166 * - **InputIt** must be [InputIterator](http://en.cppreference.com/w/cpp/concept/InputIterator) | |
167 * - **OutputIt** must be [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator) | |
168 * | |
169 * \param input the beginning | |
170 * \param end the end of the data | |
171 * \param output the output destination | |
172 * \return output | |
173 * \throw std::invalid_argument on bad %base64 string | |
174 */ | |
175 template <typename InputIt, typename OutputIt> | |
18 | 176 auto decode(InputIt input, InputIt end, OutputIt output) -> OutputIt |
0 | 177 { |
18 | 178 while (input != end) { |
179 char inputbuf[4] = { -1, -1, -1, -1 }; | |
180 int count; | |
0 | 181 |
18 | 182 for (count = 0; count < 4 && input != end; ++count) { |
183 // Check if the character is valid and get its value. | |
184 if ((*input == '=' && count <= 1) || !is_valid(*input)) | |
185 throw std::invalid_argument("invalid base64 string"); | |
186 if (is_base64(*input)) | |
187 inputbuf[count] = static_cast<char>(rlookup(*input)); | |
0 | 188 |
18 | 189 input++; |
190 } | |
0 | 191 |
18 | 192 if (count != 4) |
193 throw std::invalid_argument("truncated string"); | |
0 | 194 |
18 | 195 *output++ = static_cast<char>(((inputbuf[0] << 2) & 0xfc) | ((inputbuf[1] >> 4) & 0x03)); |
0 | 196 |
18 | 197 if (inputbuf[2] != -1) |
198 *output++ = static_cast<char>(((inputbuf[1] << 4) & 0xf0) | ((inputbuf[2] >> 2) & 0x0f)); | |
199 if (inputbuf[3] != -1) { | |
200 // "XY=Z" is not allowed. | |
201 if (inputbuf[2] == -1) | |
202 throw std::invalid_argument("invalid base64 string"); | |
0 | 203 |
18 | 204 *output++ = static_cast<char>(((inputbuf[2] << 6) & 0xc0) | (inputbuf[3] & 0x3f)); |
205 } | |
206 } | |
0 | 207 |
18 | 208 return output; |
0 | 209 } |
210 | |
211 /** | |
212 * Encode a string. | |
213 * | |
214 * \param input the input string | |
215 * \return the %base64 formatted string | |
216 */ | |
18 | 217 inline auto encode(std::string_view input) -> std::string |
0 | 218 { |
18 | 219 std::string result; |
0 | 220 |
18 | 221 encode(input.begin(), input.end(), std::back_inserter(result)); |
0 | 222 |
18 | 223 return result; |
0 | 224 } |
225 | |
226 /** | |
227 * Decode a string. | |
228 * | |
229 * \param input the %base64 formatted string | |
230 * \return the original string | |
231 * \throw std::invalid_argument on bad %base64 string | |
232 */ | |
18 | 233 inline auto decode(std::string_view input) -> std::string |
0 | 234 { |
18 | 235 std::string result; |
0 | 236 |
18 | 237 decode(input.begin(), input.end(), std::back_inserter(result)); |
0 | 238 |
18 | 239 return result; |
0 | 240 } |
241 | |
242 } // !base64 | |
243 | |
244 #endif // !BASE64_HPP |