/*
 * This library is mainly intended to demonstrate how to program a sub
 * library.
 */

#define NO_SUB_PRAGMAS

#include <libraries/xpksub.h>

#define A3000 XPKMF_A3000SPEED

XMINFO RlenMode = {
	NULL,    // next
	100,     // upto
	A3000,   // flags
	0,       // packmem
	0,       // unpackmem
	140,     // packspeed,   K/sec
	1043,    // unpackspeed, K/sec
	45,      // ratio,      *0.1%
	0,       // reserved
	"normal" // description
};

static struct XpkInfo RlenInfo = {
		1,               /* info version */
		0,               /* lib  version */
		0,               /* master vers  */
		0,               /* pad          */
		"RLEN",          /* short name   */
		"Run Length 1.0",/* long name    */
		"Fast and simple compression usable for simple data", /* description*/
		'RLEN',          /* 4 letter ID  */
		XPKIF_PK_CHUNK | /* flags        */
		XPKIF_UP_CHUNK,
		32000,           /* max in chunk */
		0,               /* min in chunk */
		32000,           /* def in chunk */
		NULL,            /* pk message   */
		NULL,            /* up message   */
		NULL,            /* pk past msg  */
		NULL,            /* up past msg  */
		50,              /* def mode     */
		0,               /* pad          */
		&RlenMode        /* modes        */
};

/*
 * Returns an info structure about our packer
 */
struct XpkInfo * __saveds __asm
XpksPackerInfo( void )
{
	return &RlenInfo;
}


void __saveds __asm
XpksPackFree( REG __a0 XPARAMS* xpar )
{
}

/*
 * This forces the next chunk to be uncompressable independent from the
 * previous one. This is always the case in RLEN.
 */
long __saveds __asm
XpksPackReset( REG __a0 XPARAMS* xpar )
{
	return 0;
}


void __saveds __asm
XpksUnpackFree( REG __a0 XPARAMS* xpar )
{
}

/*
 * Pack a chunk
 */
long __saveds __asm
XpksPackChunk( REG __a0 XPARAMS *xpar )
{
	UBYTE *get =xpar->InBuf,          *start=xpar->InBuf;
	UBYTE *end =get+xpar->InLen,      *put=xpar->OutBuf;
	UBYTE *wend=put+xpar->OutBufLen;
	int   run, i;

	for( ;; ) {
		run= get[0]==get[1] && get[1]==get[2];

		if( put+(get-start)+4 > wend )
			return XPKERR_EXPANSION;

		if( run || get-start==127 || get==end ) { /* write uncompressed */
			if( get-start ) {
				*put++=get-start;
				for( i=get-start; i>0; i-- )
					*put++=*start++;
			}
			if( get==end ) {
				*put++=0;
				break;
			}
			start=get;
		}

		if( run ) {                                /* write compressed   */
			for( i=3; get+i<end && get[i-1]==get[i] && i<127; i++ ) ;
			*put++=-i;
			*put++=get[0];
			get+=i;
			start=get;
		} else 
			get++;
	}
	xpar->OutLen=put-(UBYTE*)xpar->OutBuf;

	return 0;
}


long __saveds __asm
XpksUnpackChunk( REG __a0 XPARAMS* xpar )
{
	char *get=xpar->InBuf, *put=xpar->OutBuf, v;
	int   i;

	while( i=*get++ )
		if( i>0 )
			for( ; i>0; i-- )
				*put++=*get++;
		else 
			for( i=-i,v=*get++; i>0; i-- )
				*put++=v;

	return 0;
}
