| /* |
| From: http://www.adp-gmbh.ch/cpp/common/base64.html |
| |
| base64.cpp and base64.h |
| |
| Copyright (C) 2004-2008 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 |
| |
| This file was modified by jmarantz@google.com to: |
| - Add a static map and an initializer function |
| - add a web-safe variant that uses '-' and '_' in lieu of '+' and '/' |
| - change the 'decode' interface to return false if the input contains |
| characters not in the expected char-set. |
| - removed is_base64 helper function and instead rely on the char_maps. |
| - use a static constant for the padding character '=' |
| */ |
| |
| #include "base64.h" |
| #include <assert.h> |
| |
| static const char base64_chars[] = |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| "abcdefghijklmnopqrstuvwxyz" |
| "0123456789+/"; |
| |
| static const char web64_chars[] = |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| "abcdefghijklmnopqrstuvwxyz" |
| "0123456789-_"; |
| |
| static unsigned int base64_char_map[256], web64_char_map[256]; |
| static bool initialized = false; |
| static const unsigned int kInvalidChar = 0xffffffff; |
| static const char kPadChar = '='; |
| |
| // Be sure to call this function before calling any other functions |
| // in this file when using multiple threads. |
| void base64_init() { |
| if (!initialized) { |
| initialized = true; |
| for (int i = 0; i < 256; ++i) { |
| base64_char_map[i] = kInvalidChar; |
| web64_char_map[i] = kInvalidChar; |
| } |
| for (int i = 0; i < sizeof(base64_chars) - 1; ++i) { |
| base64_char_map[base64_chars[i]] = i; |
| } |
| for (int i = 0; i < sizeof(web64_chars) - 1; ++i) { |
| web64_char_map[web64_chars[i]] = i; |
| } |
| } |
| } |
| |
| static inline std::string encode( |
| const char* char_set, unsigned char const* bytes_to_encode, |
| unsigned int in_len) { |
| base64_init(); |
| std::string ret; |
| int i = 0; |
| int j = 0; |
| unsigned char char_array_3[3]; |
| unsigned char char_array_4[4]; |
| |
| while (in_len--) { |
| char_array_3[i++] = *(bytes_to_encode++); |
| if (i == 3) { |
| char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; |
| char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + |
| ((char_array_3[1] & 0xf0) >> 4); |
| char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + |
| ((char_array_3[2] & 0xc0) >> 6); |
| char_array_4[3] = char_array_3[2] & 0x3f; |
| |
| for (i = 0; i < 4 ; i++) |
| ret += char_set[char_array_4[i]]; |
| i = 0; |
| } |
| } |
| |
| if (i) { |
| for (j = i; j < 3; j++) { |
| char_array_3[j] = '\0'; |
| } |
| |
| char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; |
| char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + |
| ((char_array_3[1] & 0xf0) >> 4); |
| char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + |
| ((char_array_3[2] & 0xc0) >> 6); |
| char_array_4[3] = char_array_3[2] & 0x3f; |
| |
| for (j = 0; (j < i + 1); j++) |
| ret += char_set[char_array_4[j]]; |
| |
| while ((i++ < 3)) { |
| ret += kPadChar; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static inline bool decode( |
| unsigned int* char_map, const std::string& encoded_string, |
| std::string* output) { |
| base64_init(); |
| int in_len = encoded_string.size(); |
| int i = 0; |
| int j = 0; |
| int in_ = 0; |
| unsigned char char_array_4[4], char_array_3[3]; |
| std::string ret; |
| |
| while (in_len-- && (encoded_string[in_] != kPadChar)) { |
| char_array_4[i++] = encoded_string[in_]; |
| in_++; |
| if (i == 4) { |
| for (i = 0; i <4; i++) { |
| unsigned int char_index = char_map[char_array_4[i]]; |
| if (char_index == kInvalidChar) { |
| return false; |
| } |
| char_array_4[i] = char_index; |
| } |
| |
| char_array_3[0] = (char_array_4[0] << 2) + |
| ((char_array_4[1] & 0x30) >> 4); |
| char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + |
| ((char_array_4[2] & 0x3c) >> 2); |
| char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; |
| |
| for (i = 0; (i < 3); i++) |
| *output += char_array_3[i]; |
| i = 0; |
| } |
| } |
| |
| if (i) { |
| for (j = i; j < 4; j++) |
| char_array_4[j] = 0; |
| |
| for (j = 0; j < i; j++) { |
| unsigned int char_index = char_map[char_array_4[j]]; |
| if (char_index == kInvalidChar) { |
| return false; |
| } |
| char_array_4[j] = char_index; |
| } |
| |
| char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); |
| char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + |
| ((char_array_4[2] & 0x3c) >> 2); |
| char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; |
| |
| for (j = 0; (j < i - 1); j++) { |
| *output += char_array_3[j]; |
| } |
| } |
| |
| return true; |
| } |
| |
| |
| std::string base64_encode(unsigned char const* bytes_to_encode, |
| unsigned int in_len) { |
| return encode(base64_chars, bytes_to_encode, in_len); |
| } |
| |
| std::string web64_encode(unsigned char const* bytes_to_encode, |
| unsigned int in_len) { |
| return encode(web64_chars, bytes_to_encode, in_len); |
| } |
| |
| bool base64_decode(const std::string& encoded_string, std::string* output) { |
| return decode(base64_char_map, encoded_string, output); |
| } |
| |
| bool web64_decode(const std::string& encoded_string, std::string* output) { |
| return decode(web64_char_map, encoded_string, output); |
| } |