/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss of reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#include "lpc-internals.h"

/*
*	The UUENCODE format, which was very popular until MIME came along,
*	is a method of encoding binary data in ASCII text. The UU bit stands
*	for unix-to-unix as the encoding scheme was part of the uu* toolset,
*	the pre-www era communication solution for unix systems. Since the
*	advent of MIME the uuencode format has mostly been limited to some
*	USENET groups, most prominently the alt.binaries.pictures.erotica.*
*	hierarchy :-)
*
*	The uuencoded text contains lines, normally terminated by LF (0x0a).
*	Each line starts with a length character, which is the number of bytes
*	encoded in the line + 0x20, the ASCII code for space. The max. number is
*	45 (which will generate 60 characters) and is encoded as 'M'. The 60
*	character limit was deemed to be safe from auto-wrapping by email
*	and newsreader clients.
*
*	Then each three input bytes are cut into 4 chunks of 6-bit numbers:
*
*	|   1st byte    |   2nd byte    |   3rd byte    |
*	|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
*
*	|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|
*	| 1st 6 bit | 2nd 6 bit | 3rd 6 bit | 4th 6 bit |
*
*	and then each of these 6-bits are added to 0x20 (ASCII space).
*	Thus the largest generated character code is 0x5F, the code for '_'
*
*	In addition, the space character can be substituted with the 0x60
*	character, which is the back-tick, '`'. That is, ' ' and '`' both
*	mean binary 000000. That substitution is frequent especially when
*	a line would otherwise end with a space, for some tools would strip
*	all trailing spaces from lines to save bandwidth.
*
*	If the number of bytes encoded is not an exact multiple of 3,
*	then after the last useful byte one or two filler bytes shall be
*	added and encoded. It doesn't matter what the filler is, because the
*	decoder will throw away all the excess bytes anyway. However, the
*	encoded line must always contain an integer multiple of 4 characters,
*	so valid lines are always 4*N+1 bytes.
*
*	It should be noted that the real uuencoder utility tools put a header line
*	and a finishing line around the actual encoded binary. The routines below
*	do nothing but the raw encoding/decoding.
*
*	It should also be noted that uuencode does not provide any form of data
*	integrity check. If you delete lines, swap them around and so on, then
*	you will decode garbage without receiving any warnings. It is up to you
*	to guarantee error-free delivery of the encoded text.
*/

/****************************************************************************/
/*					Public functions										*/
/****************************************************************************/

/*
*	Uuencode a line (up to 45 bytes)
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*	The encoded 'data' is placed in a 'buff'.
*	Returns the length of the encoded line or -1 on error.
*/

int		_lpc_UuEncode( char *buff, char *data, int dlen )
{
int		b0, b1, b2;
int		retv;

	if ( dlen < 1 || dlen > 45 ) return( -1 );

	*buff++ = ' ' + dlen;

	for ( retv = 1 ; dlen > 0 ; retv += 4, dlen -= 3 ) {

		b0 = *data++;
		b1 = dlen > 1 ? *data++ : 0;
		b2 = dlen > 2 ? *data++ : 0;

		*buff++ = ( ( b0 >> 2 ) & 0x3f ) + ' ';
		*buff++ = ( ( b0 << 4 ) & 0x30 ) + ( ( b1 >> 4 ) & 0x0f ) + ' ';
		*buff++ = ( ( b1 << 2 ) & 0x3c ) + ( ( b2 >> 6 ) & 0x03 ) + ' ';
		*buff++ = ( b2 & 0x3f ) + ' ';
	}

	if ( buff[ -1 ] == ' ' ) buff[ -1 ] = '`';
	*buff = '\0';
	return( retv );
}

/*
*	Decodes a uuencoded line
*	~~~~~~~~~~~~~~~~~~~~~~~~
*	The content of 'buff' is decoded and the result is stored in 'data'.
*	In case of an error, a -1 is returned, otherwise the data length
*	that can be 0-45 (inclusive). The dlen parameter is the length
*	of the source (encoded) line, in bytes.
*/

int		_lpc_UuDecode( char *data, char *buff, int blen )
{
int		b[ 4 ], d[ 3 ];
int		len, tmp, cnt;

	len = ( *buff++ & 0xff ) - ' ';
	if ( len < 0 || len > 45 ) return( -1 );
	if ( blen < ( ( len + 2 ) / 3 ) * 4 + 1 ) return( -1 );
	for ( tmp = len ; tmp > 0 ; ) {

		for ( cnt = 0 ; cnt < 4 ; cnt++ ) {

			b[ cnt ] = ( *buff++ & 0xff ) - ' ';
			if ( b[ cnt ] < 0 || b[ cnt ] > 64 ) return( -1 );
			b[ cnt ] &= 63;
		}

		d[ 0 ] = ( b[ 0 ] << 2 ) | ( b[ 1 ] >> 4 );
		d[ 1 ] = ( b[ 1 ] << 4 ) | ( b[ 2 ] >> 2 );
		d[ 2 ] = ( b[ 2 ] << 6 ) | b[ 3 ];

		for ( cnt = 0 ; cnt < 3 && tmp-- > 0 ; ) *data++ = d[ cnt++ ];
	}

	return( len );
}

