Untitled
unknown
plain_text
a month ago
4.3 kB
0
Indexable
Never
static inline bool decodeBase64( const unsigned char *input, unsigned char *output, ssize_t outsize ) { /* * the bytes in the decoder table have the following layout: * bit 7 (sign bit): set iff the character is ignored (white space) * if bit 7 is not set, then * bit 6: set iff the character contains encoded data * if bit 6 is set, then * bits 5-0: the data * otherwise * if bits 5-0 are 111110 (the character is '='), then it's padding * otherwise the character terminates the input (either NUL or error) */ static const char *decoderTable = "........\x80.\x80..\x80..................\x80..........~...\x7ftuvwxyz{|}...=...@ABCDEFGHIJKLMNOPQRSTUVWXY......Z[\\]^_`abcdefghijklmnopqrs....."; /* * the function assumes the input is valid, in particular that it * contains no bytes with bit 7 set */ size_t padSz = 0; for( ; outsize > 0; outsize -= 3 ) { // for each quad (4 encoded input bytes) collect the data in the buffer unsigned int buf = 0; for( unsigned int remaining = 4; ; ) { char ch; // skip over whitespace while( (ch = decoderTable[ *input++ ]) < 0 ); // check if the character contains encoded data or not if( !(ch & 0x40) ) { // it's not a data character -- the loop will terminate if( ch == '=' ) { // it's a padding character ++padSz; // check if it's followed by another (but only if we have even more remaining) if ( remaining > 1 ) { ch = static_cast<char>(*input); if (ch == '=') { ++input; ++padSz; } } if( padSz == remaining ) // must pad to a quad { // store 1 or 2 bytes, dep. on padding size buf >>= 8; if( padSz == 1 ) { output[ 1 ] = static_cast<unsigned char>( buf ); buf >>= 6; } output[ 0 ] = static_cast<unsigned char>( buf >> 2 ); output += 3 - padSz; padSz = 0; break; } else { Err( ERR_INVALID_ARGUMENTS, "Invalid input for Base64 conversion: Padding not at the end of a quad" ); return false; } } else { Err( ERR_INVALID_ARGUMENTS, "Invalid input for Base64 conversion: Can't decode \"\\%d\"", input[-1] ); return false; } } // otherwise it's a data byte -- collect into the buffer buf |= ch & 0x3f; if( --remaining == 0 ) { // store decoded output output[ 2 ] = static_cast<unsigned char>( buf ); buf >>= 8; output[ 1 ] = static_cast<unsigned char>( buf ); output[ 0 ] = static_cast<unsigned char>( buf >> 8 ); output += 3; break; } buf <<= 6; // shift only if not the last iteration } } return true; } /**************************************************************** ** Routine: StrFromBase64 ** Returns: new buffer or NULL if error ** Action : Convert string from Base64 (ala MIME formats?) *****************************************************************/ unsigned char *StrFromBase64( const unsigned char *Str, size_t Size, size_t *DecodedSize ) { size_t sz = 0, padSz = 0, outputSz = 0; char ch = 0; unsigned char *result = 0; const char *cur = reinterpret_cast< const char * >( Str ), *end = cur + Size; // do a rough validity check and compute what the output size would be if the input is valid while( cur != end && (ch = *cur++) > 0 ) { if( ch >= ' ' ) { ++sz; if( ch == '=' ) ++padSz; } } if( ch < 0 || (sz & 3) || sz < padSz * 2 ) Err( ERR_INVALID_ARGUMENTS, "Invalid input for Base64 conversion." ); else { // Decoding Phase: // OutBuf = new unsigned char[ ((Size + 2) / 3) * 4 + 1 ]; // aaa => 5 length for base64 // 4+2 / 4 = 3/2 * 3 - 2 = 1 outputSz = (sz >> 2) * 3 - padSz; result = new unsigned char[ outputSz + 1 ]; // 2 if( result ) { // do the actual decoding if( decodeBase64( Str, result, static_cast< ssize_t >( outputSz ) ) ) result[ outputSz ] = '\0'; else { delete [] result; result = 0; outputSz = 0; } } else { Err( ERR_MEMORY, "Out of memory while converting from base64" ); outputSz = 0; } } if( DecodedSize ) *DecodedSize = outputSz; return result; }
Leave a Comment