/*
 * This library is mainly intended to demonstrate how to program a sub
 * library.
 *
 * Now it's a serious sub-library.  ;)
 *
 * v1.1  Modified by Daniel J. Andrea II to fix a bug in picking the filename
 *        out of the LZX archive.  Also changed to using the address of the 
 *        input buffer instead of ExecBase->ThisTask for the filenames.  The
 *        old method ALWAYS gave back the same address, irregardless of who was
 *        using the sublibrary.  Using the input buffer address should produce
 *        a unique value so multiple invocations of the library won't walk all
 *        over it's own data.  Unpacking data packed with the old version will
 *        still work because the name of the file stored in the LZX archive is
 *        pulled straight out of the archive itself, though multiple simultaneous
 *        invocations of older packed data may still walk all over it's own data
 *        from other invocations.  Changed some of the DEFINE values to make
 *        source all English and removed sections referring to conditional
 *        compilation if Z_PIPE was defined (I never used this anyways since LZX
 *        doesn't work properly with pipes).  Also added some debug stuff to have
 *        LZX redirect it's output to a file in T:, add 'DEFINE=LZXDEBUG' to the
 *        CMFLAGS section of the SMakefile to enable.
 *
 $VER: xpk LZX libs 1.1 (04-Sept-97) © 1997 Daniel J. Andrea II
 */

#define NO_SUB_PRAGMAS
#define MaksymalnyC 0x80000
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libraries/xpksub.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <exec/exec.h>

#define A3000 XPKMF_A3000SPEED

XMINFO RlenMode4 = {
	NULL,    	// next
	100,     	// upto
	A3000,   	// flags
	0,       	// packmem
	0,       	// unpackmem
	30,     	// packspeed,   K/sec
	150,    	// unpackspeed, K/sec
	500,      	// ratio,      *0.1%
	0,       	// reserved
	"best" 		// description
};
XMINFO RlenMode3 = {
	&RlenMode4,  // next
	80,     	// upto
	A3000,   	// flags
	0,       	// packmem
	0,       	// unpackmem
	31,     	// packspeed,   K/sec
	150,    	// unpackspeed, K/sec
	480,      	// ratio,      *0.1%
	0,       	// reserved
	"better" 	// description
};
XMINFO RlenMode2 = {
	&RlenMode3,  // next
	60,     	// upto
	A3000,   	// flags
	0,       	// packmem
	0,       	// unpackmem
	32,     	// packspeed,   K/sec
	150,    	// unpackspeed, K/sec
	460,      	// ratio,      *0.1%
	0,       	// reserved
	"good" 		// description
};
XMINFO RlenMode1 = {
	&RlenMode2,  // next
	40,     	// upto
	A3000,   	// flags
	0,       	// packmem
	0,       	// unpackmem
	33,     	// packspeed,   K/sec
	150,    	// unpackspeed, K/sec
	440,      	// ratio,      *0.1%
	0,       	// reserved
	"poor" 		// description
};
XMINFO RlenMode = {
	&RlenMode1,	// next
	20,     	// upto
	A3000,   	// flags
	0,       	// packmem
	0,       	// unpackmem
	34,     	// packspeed,   K/sec
	150,    	// unpackspeed, K/sec
	10,      	// ratio,      *0.1%
	0,       	// reserved
	"none" 		// description
};
#ifndef DEMOLZX
char *mody="012339";
#else
char *mody="012333";
#endif
static struct XpkInfo RlenInfo = {
		1,               /* info version */
		0,               /* lib  version */
		0,               /* master vers  */
		0,               /* pad          */
#ifndef CODE_DELTA
		"ELZX",          /* short name   */
		"External LZX  ",/* long name    */
		"very good compression library      middle speed   ", /* description*/
		'ELZX',          /* 4 letter ID  */
#else
		"SLZX",          /* short name   */
		"LZX with delta",/* long name    */
		"External LZX compression for samples and mods     ", /* description*/
		'SLZX',          /* 4 letter ID  */
#endif
		XPKIF_PK_CHUNK | /* flags        */
		XPKIF_UP_CHUNK |
		XPKIF_MODES,
		MaksymalnyC,     /* max in chunk */
		1,               /* min in chunk */
		MaksymalnyC,     /* def in chunk */
		NULL,            /* pk message   */
		NULL,            /* up message   */
		NULL,            /* pk past msg  */
		NULL,            /* up past msg  */
		80,              /* 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,*put=xpar->OutBuf;
#ifdef CODE_DELTA
	UBYTE *docel=xpar->OutBuf;
	int   i;
#endif

// Moje dodatki
	char temp1[100],temp2[100],sysus[100];
	struct Library *DOSBase;
	BPTR tmp; 

	DOSBase=OpenLibrary("dos.library",37);
	sprintf(temp1,"t:ltf%x",get);
	sprintf(temp2,"t:ltf%x.lzx",get);
#ifndef DEMOLZX
#ifdef LZXDEBUG
	sprintf(sysus,"lzx -Qf -%c a <nil: >>T:XPKLZXDEBUG.log %s %s",mody[((xpar->Mode|1)-1)/20],temp2,temp1);
#else
	sprintf(sysus,"lzx -Qf -%c a <>nil: %s %s",mody[((xpar->Mode|1)-1)/20],temp2,temp1);
#endif
#else
#ifdef LZXDEBUG
	sprintf(sysus,"lzx -%c a <nil: >>T:XPKLZXDEBUG.log %s %s",mody[((xpar->Mode|1)-1)/20],temp2,temp1);
#else
	sprintf(sysus,"lzx -%c a <>nil: %s %s",mody[((xpar->Mode|1)-1)/20],temp2,temp1);
#endif
#endif
	DeleteFile(temp2);
	tmp=Open(temp1,MODE_NEWFILE);
#ifdef CODE_DELTA
	for(i=0;docel<put+xpar->InLen;*docel++=*get-i,i=*get++) {};
	Write(tmp,put,xpar->InLen);
#else
	Write(tmp,get,xpar->InLen);
#endif
	Close(tmp);
	SystemTagList(sysus,(void *)0);
	tmp=Open(temp2,MODE_OLDFILE);
	Seek(tmp,0,OFFSET_END);
	if ( Seek(tmp,0,OFFSET_BEGINNING) < MaksymalnyC )
		xpar->OutLen=Read(tmp,put,MaksymalnyC);
	 else
#ifndef CODE_DELTA
		CopyMem(get,put,xpar->OutLen=xpar->InLen);
#else
		xpar->OutLen=MaksymalnyC;
#endif
	Close(tmp);
	DeleteFile(temp1);
	DeleteFile(temp2);
	CloseLibrary(DOSBase);
	return 0;
}

long __saveds __asm
XpksUnpackChunk( REG __a0 XPARAMS* xpar )
{
	char *get=xpar->InBuf, *put=xpar->OutBuf;
#ifdef CODE_DELTA
	int		x,i;
#endif
	char temp1[100],temp2[100],sysus[100],nmln;
	struct Library *DOSBase;
	BPTR tmp;

	if ( MaksymalnyC == xpar->InLen ) 
#ifndef CODE_DELTA
		CopyMem(get,put,MaksymalnyC);
#else
		for(x=0,i=MaksymalnyC;i--;*put+=x,x=*put++);
#endif
	 else {
		DOSBase=OpenLibrary("dos.library",37);
		strcpy(temp1,"t:");
    
    /* The following two lines of code had a bug in the original version.
       It assumed a set length for the file name inside the archive.  
       The byte at offset 0x28 is the length of the filename, so that is
       now used instead.    DJA, 04-Sept-97 v1.01  */
    
    nmln=get[0x28];
		strncat(temp1,get+0x29,nmln);
		sprintf(temp2,"t:ltf%0x.lzx",get);
		tmp=Open(temp2,MODE_NEWFILE);
		Write(tmp,get,xpar->InLen);
		Close(tmp);
#ifdef LZXDEBUG
		sprintf(sysus,"lzx x <nil: >>T:XPKLZXDEBUG.log %s t:",temp2);
#else
		sprintf(sysus,"lzx x <>nil: %s t:",temp2);
#endif
		SystemTagList(sysus,(void *)0);
		tmp=Open(temp1,MODE_OLDFILE);
#ifdef CODE_DELTA
		i=Read(tmp,put,MaksymalnyC);
		for(x=0;i--;*put+=x,x=*put++){};
#else
		Read(tmp,put,MaksymalnyC);
#endif
		Close(tmp);
		DeleteFile(temp1);
		DeleteFile(temp2);
		CloseLibrary(DOSBase);
	}
	return 0;
}
