#include "ace/Codecs.h" #include "ace/Log_Category.h" #include "ace/OS_Memory.h" #include "ace/OS_NS_ctype.h" #if defined (ACE_HAS_ALLOC_HOOKS) # include "ace/Malloc_Base.h" #endif /* ACE_HAS_ALLOC_HOOKS */ namespace { // Just in case ... #undef alphabet #undef pad #undef max_columns // Symbols which form the Base64 alphabet (Defined as per RFC 2045) ACE_Byte const alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // The padding character used in the encoding ACE_Byte const pad = '='; // Number of columns per line of encoded output (Can have a maximum // value of 76). int const max_columns = 72; } ACE_BEGIN_VERSIONED_NAMESPACE_DECL bool ACE_Base64::init_ = false; ACE_Byte ACE_Base64::decoder_[256]; ACE_Byte ACE_Base64::member_[256]; ACE_Byte* ACE_Base64::encode (const ACE_Byte* input, const size_t input_len, size_t* output_len, bool is_chunked) { if (!ACE_Base64::init_) ACE_Base64::init(); if (!input) return 0; ACE_Byte* result = 0; size_t length = ((input_len + 2) / 3) * 4; size_t num_lines = length / max_columns + 1; length += num_lines + 1; #if defined (ACE_HAS_ALLOC_HOOKS) ACE_ALLOCATOR_RETURN (result, static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_Byte) * length)), 0); #else ACE_NEW_RETURN (result, ACE_Byte[length], 0); #endif /* ACE_HAS_ALLOC_HOOKS */ int char_count = 0; int bits = 0; size_t pos = 0; int cols = 0; for (size_t i = 0; i < input_len; ++i) { bits += input[i]; ++char_count; if (char_count == 3) { result[pos++] = alphabet[bits >> 18]; result[pos++] = alphabet[(bits >> 12) & 0x3f]; result[pos++] = alphabet[(bits >> 6) & 0x3f]; result[pos++] = alphabet[bits & 0x3f]; cols += 4; if (cols == max_columns) { if (is_chunked) result[pos++] = '\n'; cols = 0; } bits = 0; char_count = 0; } else { bits <<= 8; } } if (char_count != 0) { bits <<= (16 - (8 * char_count)); result[pos++] = alphabet[bits >> 18]; result[pos++] = alphabet[(bits >> 12) & 0x3f]; cols += 2; if (char_count == 1) { result[pos++] = pad; result[pos++] = pad; cols += 2; } else { result[pos++] = alphabet[(bits >> 6) & 0x3f]; result[pos++] = pad; cols += 2; } } if (cols > 0 && is_chunked) result[pos++] = '\n'; result[pos] = 0; *output_len = pos; return result; } size_t ACE_Base64::length (const ACE_Byte* input) { if (!ACE_Base64::init_) ACE_Base64::init(); ACE_Byte* ptr = const_cast (input); while (*ptr != 0 && (member_[*(ptr)] == 1 || *ptr == pad || ACE_OS::ace_isspace (*ptr))) ++ptr; size_t len = ptr - input; len = ((len + 3) / 4) * 3 + 1 ; return len; } ACE_Byte* ACE_Base64::decode (const ACE_Byte* input, size_t* output_len) { if (!ACE_Base64::init_) ACE_Base64::init(); if (!input) return 0; size_t result_len = ACE_Base64::length (input); ACE_Byte* result = 0; #if defined (ACE_HAS_ALLOC_HOOKS) ACE_ALLOCATOR_RETURN (result, static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_Byte) * result_len)), 0); #else ACE_NEW_RETURN (result, ACE_Byte[result_len], 0); #endif /* ACE_HAS_ALLOC_HOOKS */ ACE_Byte* ptr = const_cast (input); while (*ptr != 0 && (member_[*(ptr)] == 1 || *ptr == pad || ACE_OS::ace_isspace (*ptr))) ++ptr; size_t input_len = ptr - input; int char_count = 0; int bits = 0; size_t pos = 0; size_t i = 0; for (; i < input_len; ++i) { if (input[i] == pad) break; if (!ACE_Base64::member_[input[i]]) continue; bits += decoder_[input[i]]; ++char_count; if (char_count == 4) { result[pos++] = static_cast (bits >> 16); result[pos++] = static_cast ((bits >> 8) & 0xff); result[pos++] = static_cast (bits & 0xff); bits = 0; char_count = 0; } else { bits <<= 6; } } int errors = 0; if ( i == input_len) { if (char_count) { ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("Decoding incomplete: atleast %d bits truncated\n"), (4 - char_count) * 6)); ++errors; } } else { switch (char_count) { case 1: ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("Decoding incomplete: atleast 2 bits missing\n"))); ++errors; break; case 2: result[pos++] = static_cast (bits >> 10); break; case 3: result[pos++] = static_cast (bits >> 16); result[pos++] = static_cast ((bits >> 8) & 0xff); break; } } if (errors) { #if defined (ACE_HAS_ALLOC_HOOKS) ACE_Allocator::instance()->free(result); #else delete[] result; #endif /* ACE_HAS_ALLOC_HOOKS */ return 0; } result[pos] = 0; *output_len = pos; return result; } void ACE_Base64::init () { if (!ACE_Base64::init_) { for (ACE_Byte i = 0; i < sizeof (alphabet); ++i) { ACE_Base64::decoder_[alphabet[i]] = i; ACE_Base64::member_ [alphabet[i]] = 1; } ACE_Base64::init_ = true; } return; } ACE_END_VERSIONED_NAMESPACE_DECL