fork download
  1. #include <iostream>
  2. #include <cstring>
  3. using namespace std;
  4.  
  5. #include <string>
  6.  
  7. #if __cplusplus >= 201703L
  8. #include <string_view>
  9. #endif // __cplusplus >= 201703L
  10.  
  11. std::string base64_encode (std::string const& s, bool url = false);
  12. std::string base64_encode_pem (std::string const& s);
  13. std::string base64_encode_mime(std::string const& s);
  14.  
  15. std::string base64_decode(std::string const& s, bool remove_linebreaks = false);
  16. std::string base64_encode(unsigned char const*, size_t len, bool url = false);
  17.  
  18. #if __cplusplus >= 201703L
  19. //
  20. // Interface with std::string_view rather than const std::string&
  21. // Requires C++17
  22. // Provided by Yannic Bonenberger (https://g...content-available-to-author-only...b.com/Yannic)
  23. //
  24. std::string base64_encode (std::string_view s, bool url = false);
  25. std::string base64_encode_pem (std::string_view s);
  26. std::string base64_encode_mime(std::string_view s);
  27.  
  28. std::string base64_decode(std::string_view s, bool remove_linebreaks = false);
  29. #endif // __cplusplus >= 201703L
  30.  
  31.  
  32. #include <algorithm>
  33. #include <stdexcept>
  34.  
  35. //
  36. // Depending on the url parameter in base64_chars, one of
  37. // two sets of base64 characters needs to be chosen.
  38. // They differ in their last two characters.
  39. //
  40. static const char* base64_chars[2] = {
  41. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  42. "abcdefghijklmnopqrstuvwxyz"
  43. "0123456789"
  44. "+/",
  45.  
  46. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  47. "abcdefghijklmnopqrstuvwxyz"
  48. "0123456789"
  49. "-_"};
  50.  
  51. static unsigned int pos_of_char(const unsigned char chr) {
  52. //
  53. // Return the position of chr within base64_encode()
  54. //
  55.  
  56. if (chr >= 'A' && chr <= 'Z') return chr - 'A';
  57. else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1;
  58. else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
  59. else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
  60. else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_'
  61. else
  62. //
  63. // 2020-10-23: Throw std::exception rather than const char*
  64. //(Pablo Martin-Gomez, https://g...content-available-to-author-only...b.com/Bouska)
  65. //
  66. throw std::runtime_error("Input is not valid base64-encoded data.");
  67. }
  68.  
  69. static std::string insert_linebreaks(std::string str, size_t distance) {
  70. //
  71. // Provided by https://g...content-available-to-author-only...b.com/JomaCorpFX, adapted by me.
  72. //
  73. if (!str.length()) {
  74. return "";
  75. }
  76.  
  77. size_t pos = distance;
  78.  
  79. while (pos < str.size()) {
  80. str.insert(pos, "\n");
  81. pos += distance + 1;
  82. }
  83.  
  84. return str;
  85. }
  86.  
  87. template <typename String, unsigned int line_length>
  88. static std::string encode_with_line_breaks(String s) {
  89. return insert_linebreaks(base64_encode(s, false), line_length);
  90. }
  91.  
  92. template <typename String>
  93. static std::string encode_pem(String s) {
  94. return encode_with_line_breaks<String, 64>(s);
  95. }
  96.  
  97. template <typename String>
  98. static std::string encode_mime(String s) {
  99. return encode_with_line_breaks<String, 76>(s);
  100. }
  101.  
  102. template <typename String>
  103. static std::string encode(String s, bool url) {
  104. return base64_encode(reinterpret_cast<const unsigned char*>(s.data()), s.length(), url);
  105. }
  106.  
  107. std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) {
  108.  
  109. size_t len_encoded = (in_len +2) / 3 * 4;
  110.  
  111. unsigned char trailing_char = url ? '.' : '=';
  112.  
  113. //
  114. // Choose set of base64 characters. They differ
  115. // for the last two positions, depending on the url
  116. // parameter.
  117. // A bool (as is the parameter url) is guaranteed
  118. // to evaluate to either 0 or 1 in C++ therefore,
  119. // the correct character set is chosen by subscripting
  120. // base64_chars with url.
  121. //
  122. const char* base64_chars_ = base64_chars[url];
  123.  
  124. std::string ret;
  125. ret.reserve(len_encoded);
  126.  
  127. unsigned int pos = 0;
  128.  
  129. while (pos < in_len) {
  130. ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
  131.  
  132. if (pos+1 < in_len) {
  133. ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
  134.  
  135. if (pos+2 < in_len) {
  136. ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
  137. ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]);
  138. }
  139. else {
  140. ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
  141. ret.push_back(trailing_char);
  142. }
  143. }
  144. else {
  145.  
  146. ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
  147. ret.push_back(trailing_char);
  148. ret.push_back(trailing_char);
  149. }
  150.  
  151. pos += 3;
  152. }
  153.  
  154.  
  155. return ret;
  156. }
  157.  
  158. template <typename String>
  159. static std::string decode(String const& encoded_string, bool remove_linebreaks) {
  160. //
  161. // decode(…) is templated so that it can be used with String = const std::string&
  162. // or std::string_view (requires at least C++17)
  163. //
  164.  
  165. if (encoded_string.empty()) return std::string();
  166.  
  167. if (remove_linebreaks) {
  168.  
  169. std::string copy(encoded_string);
  170.  
  171. copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end());
  172.  
  173. return base64_decode(copy, false);
  174. }
  175.  
  176. size_t length_of_string = encoded_string.length();
  177. size_t pos = 0;
  178.  
  179. //
  180. // The approximate length (bytes) of the decoded string might be one or
  181. // two bytes smaller, depending on the amount of trailing equal signs
  182. // in the encoded string. This approximation is needed to reserve
  183. // enough space in the string to be returned.
  184. //
  185. size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
  186. std::string ret;
  187. ret.reserve(approx_length_of_decoded_string);
  188.  
  189. while (pos < length_of_string) {
  190. //
  191. // Iterate over encoded input string in chunks. The size of all
  192. // chunks except the last one is 4 bytes.
  193. //
  194. // The last chunk might be padded with equal signs or dots
  195. // in order to make it 4 bytes in size as well, but this
  196. // is not required as per RFC 2045.
  197. //
  198. // All chunks except the last one produce three output bytes.
  199. //
  200. // The last chunk produces at least one and up to three bytes.
  201. //
  202.  
  203. size_t pos_of_char_1 = pos_of_char(encoded_string.at(pos+1) );
  204.  
  205. //
  206. // Emit the first output byte that is produced in each chunk:
  207. //
  208. ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char(encoded_string.at(pos+0)) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4)));
  209.  
  210. if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045)
  211. encoded_string.at(pos+2) != '=' &&
  212. encoded_string.at(pos+2) != '.' // accept URL-safe base 64 strings, too, so check for '.' also.
  213. )
  214. {
  215. //
  216. // Emit a chunk's second byte (which might not be produced in the last chunk).
  217. //
  218. unsigned int pos_of_char_2 = pos_of_char(encoded_string.at(pos+2) );
  219. ret.push_back(static_cast<std::string::value_type>( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2)));
  220.  
  221. if ( ( pos + 3 < length_of_string ) &&
  222. encoded_string.at(pos+3) != '=' &&
  223. encoded_string.at(pos+3) != '.'
  224. )
  225. {
  226. //
  227. // Emit a chunk's third byte (which might not be produced in the last chunk).
  228. //
  229. ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string.at(pos+3)) ));
  230. }
  231. }
  232.  
  233. pos += 4;
  234. }
  235.  
  236. return ret;
  237. }
  238.  
  239. std::string base64_decode(std::string const& s, bool remove_linebreaks) {
  240. return decode(s, remove_linebreaks);
  241. }
  242.  
  243. std::string base64_encode(std::string const& s, bool url) {
  244. return encode(s, url);
  245. }
  246.  
  247. std::string base64_encode_pem (std::string const& s) {
  248. return encode_pem(s);
  249. }
  250.  
  251. std::string base64_encode_mime(std::string const& s) {
  252. return encode_mime(s);
  253. }
  254.  
  255. #if __cplusplus >= 201703L
  256. //
  257. // Interface with std::string_view rather than const std::string&
  258. // Requires C++17
  259. // Provided by Yannic Bonenberger (https://g...content-available-to-author-only...b.com/Yannic)
  260. //
  261.  
  262. std::string base64_encode(std::string_view s, bool url) {
  263. return encode(s, url);
  264. }
  265.  
  266. std::string base64_encode_pem(std::string_view s) {
  267. return encode_pem(s);
  268. }
  269.  
  270. std::string base64_encode_mime(std::string_view s) {
  271. return encode_mime(s);
  272. }
  273.  
  274. std::string base64_decode(std::string_view s, bool remove_linebreaks) {
  275. return decode(s, remove_linebreaks);
  276. }
  277.  
  278. #endif // __cplusplus >= 201703L
  279.  
  280. int main() {
  281. uint8_t bytes[] = {255, 0, 0, 128};
  282. auto encoded_str = base64_encode(bytes, 4);
  283. cout << encoded_str << "\n";
  284.  
  285. auto decoded_str = base64_decode(encoded_str);
  286. uint8_t decoded_bytes[8];
  287. std::memcpy(decoded_bytes, decoded_str.data(), decoded_str.size());
  288. cout << (int)decoded_bytes[0] << " " << (int)decoded_bytes[1] << " " << (int)decoded_bytes[2] << " " << (int)decoded_bytes[3] << "\n";
  289. return 0;
  290. }
Success #stdin #stdout 0.01s 5288KB
stdin
Standard input is empty
stdout
/wAAgA==
255 0 0 128