Untitled
unknown
plain_text
a year ago
4.3 kB
6
Indexable
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;
}
Editor is loading...
Leave a Comment