123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /*
- base64.cpp and base64.h
- base64 encoding and decoding with C++.
- More information at
- https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
- Version: 2.rc.03 (release candidate)
- Copyright (C) 2004-2017, 2020 René Nyffenegger
- This source code is provided 'as-is', without any express or implied
- warranty. In no event will the author be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this source code must not be misrepresented; you must not
- claim that you wrote the original source code. If you use this source code
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original source code.
- 3. This notice may not be removed or altered from any source distribution.
- René Nyffenegger rene.nyffenegger@adp-gmbh.ch
- */
- #include "Base64.h"
- //
- // Depending on the url parameter in base64_chars, one of
- // two sets of base64 characters needs to be chosen.
- // They differ in their last two characters.
- //
- const char* base64_chars[2] = {
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "+/",
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "-_"};
- static std::size_t pos_of_char(const unsigned char chr) {
- //
- // Return the position of chr within base64_encode()
- //
- if (chr >= 'A' && chr <= 'Z') return chr - 'A';
- else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1;
- else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
- else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
- else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_'
- throw "If input is correct, this line should never be reached.";
- }
- static std::string insert_linebreaks(std::string str, size_t distance) {
- //
- // Provided by https://github.com/JomaCorpFX, adapted by me.
- //
- if (!str.length()) {
- return "";
- }
- size_t pos = distance;
- while (pos < str.size()) {
- str.insert(pos, "\n");
- pos += distance + 1;
- }
- return str;
- }
- template <typename String, unsigned int line_length>
- static std::string encode_with_line_breaks(String s) {
- return insert_linebreaks(base64_encode(s, false), line_length);
- }
- template <typename String>
- static std::string encode_pem(String s) {
- return encode_with_line_breaks<String, 64>(s);
- }
- template <typename String>
- static std::string encode_mime(String s) {
- return encode_with_line_breaks<String, 76>(s);
- }
- template <typename String>
- static std::string encode(String s, bool url) {
- return base64_encode(reinterpret_cast<const unsigned char*>(s.data()), s.length(), url);
- }
- std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len, bool url) {
- unsigned int len_encoded = (in_len +2) / 3 * 4;
- unsigned char trailing_char = url ? '.' : '=';
- //
- // Choose set of base64 characters. They differ
- // for the last two positions, depending on the url
- // parameter.
- // A bool (as is the parameter url) is guaranteed
- // to evaluate to either 0 or 1 in C++ therfore,
- // the correct character set is chosen by subscripting
- // base64_chars with url.
- //
- const char* base64_chars_ = base64_chars[url];
- std::string ret;
- ret.reserve(len_encoded);
- unsigned int pos = 0;
- while (pos < in_len) {
- ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
- if (pos+1 < in_len) {
- ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
- if (pos+2 < in_len) {
- ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
- ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]);
- }
- else {
- ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
- ret.push_back(trailing_char);
- }
- }
- else {
- ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
- ret.push_back(trailing_char);
- ret.push_back(trailing_char);
- }
- pos += 3;
- }
- return ret;
- }
- template <typename String>
- static std::string decode(String encoded_string, bool remove_linebreaks) {
- //
- // decode(…) is templated so that it can be used with String = const std::string&
- // or std::string_view (requires at least C++17)
- //
- if (remove_linebreaks) {
- if (! encoded_string.length() ) {
- return "";
- }
- std::string copy(encoded_string);
- size_t pos=0;
- while ((pos = copy.find("\n", pos)) != std::string::npos) {
- copy.erase(pos, 1);
- }
- return base64_decode(copy, false);
- }
- int length_of_string = encoded_string.length();
- if (!length_of_string) return std::string("");
- size_t in_len = length_of_string;
- size_t pos = 0;
- //
- // The approximate length (bytes) of the decoded string might be one ore
- // two bytes smaller, depending on the amount of trailing equal signs
- // in the encoded string. This approximation is needed to reserve
- // enough space in the string to be returned.
- //
- size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
- std::string ret;
- ret.reserve(approx_length_of_decoded_string);
- while (pos < in_len) {
- unsigned int pos_of_char_1 = pos_of_char(encoded_string[pos+1] );
- ret.push_back( ( (pos_of_char(encoded_string[pos+0]) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4));
- if (encoded_string[pos+2] != '=' && encoded_string[pos+2] != '.') { // accept URL-safe base 64 strings, too, so check for '.' also.
- unsigned int pos_of_char_2 = pos_of_char(encoded_string[pos+2] );
- ret.push_back( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2));
- if (encoded_string[pos+3] != '=' && encoded_string[pos+3] != '.') {
- ret.push_back( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string[pos+3]) );
- }
- }
- pos += 4;
- }
- return ret;
- }
- std::string base64_decode(std::string const& s, bool remove_linebreaks) {
- return decode(s, remove_linebreaks);
- }
- std::string base64_encode(std::string const& s, bool url) {
- return encode(s, url);
- }
- std::string base64_encode_pem (std::string const& s) {
- return encode_pem(s);
- }
- std::string base64_encode_mime(std::string const& s) {
- return encode_mime(s);
- }
- #if __cplusplus >= 201703L
- //
- // Interface with std::string_view rather than const std::string&
- // Requires C++17
- // Provided by Yannic Bonenberger (https://github.com/Yannic)
- //
- std::string base64_encode(std::string_view s, bool url) {
- return encode(s, url);
- }
- std::string base64_encode_pem(std::string_view s) {
- return encode_pem(s);
- }
- std::string base64_encode_mime(std::string_view s) {
- return encode_mime(s);
- }
- std::string base64_decode(std::string_view s, bool remove_linebreaks) {
- return decode(s, remove_linebreaks);
- }
- #endif // __cplusplus >= 201703L
|