Untitled

mail@pastecode.io avatar
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