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

#include <xpk/xpksub.h>
#include <exec/memory.h>
#include <pragma/exec_lib.h>

#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"

#define SCANBUFLEN 32768

/*
 * Pack a chunk
 */

struct NukeData {
	APTR	inbuf;
	APTR	outbuf;
	APTR	last;
	APTR	next;
	ULONG	cwri;
	ULONG	uwri;
	ULONG	uend;
	ULONG	delpos;
	UWORD	ulen;
	UWORD	clen;
	UWORD	ustop;
	UWORD	ustart;
	UWORD	ucount;
	UWORD	scanrange;
	UWORD	room1;
	UWORD	room2;
	UWORD	room4;
	UWORD	roomN;
	UWORD	data1;
	UWORD	data2;
	ULONG	data4;
	ULONG	dataN;
	ULONG	dest1;
	ULONG	dest2;
	ULONG	dest4;
	ULONG	destN;
	ULONG	dummy;
	ULONG	contbuf;
	ULONG	flags;
};

#ifdef __cplusplus
extern "C" {
#endif

LONG   __asm AsmPack  (register __a4 struct NukeData *ND);
STRPTR __asm AsmUnpack(register __a1 STRPTR wread, register __a4 STRPTR bread,
                        register __a0 STRPTR dst, register __a2 STRPTR end);
#ifdef __cplusplus
}
#endif

#define PACKMEM   (65536+SCANBUFLEN)*sizeof(UWORD)+sizeof(struct NukeData)

static struct XpkMode NukeMode = {
  NULL,       // Next mode
  100,        // Handles up to
  XPKMF_A3000SPEED,      // Flags
  PACKMEM,    // Packing memory
  0,          // Unpacking memory
  36,         // Packing speed
  630,        // Unpacking speed
  454,        // Compression ratio
  0,          // Reserved
  "normal",   // Description
};

static struct XpkInfo NukeInfo = {
	1,               /* info version */
	1,               /* lib  version */
	0,               /* master vers  */
	1,               /* ModesVersion */
	"NUKE"  ,        /* short name   */
	"Nuke",          /* long name    */
	"A relatively efficient packer that unpacks very quickly", /* Description */
	0x4E554B45,	/* 'NUKE', 4 letter ID  */
	XPKIF_PK_CHUNK | /* flags        */
	XPKIF_UP_CHUNK,
	30000,           /* max in chunk */
	10,              /* min in chunk */
	30000,           /* def in chunk */
	"Nuking",        /* pk message   */
	"Unnuking",      /* up message   */
	"Nuked",         /* pk past msg  */
	"Unnuked",       /* up past msg  */
	50,              /* DefMode      */
	0,               /* Pad          */
	&NukeMode,       /* ModeDesc     */
	0,               /* MinModeDesc  */
	0,               /* MaxModeDesc  */
	{0}              /* reserved     */
};


/*
 * Returns an info structure about our packer
 */

struct XpkInfo * __asm XpksPackerInfo(void)
{
	return &NukeInfo;
}

void __asm XpksPackFree(register __a0 struct XpkSubParams *xpar)
{
  struct NukeData *ND=(struct NukeData *)xpar->xsp_Sub[0];

  if(!ND)
    return;
  if( ND->last ) FreeMem( ND->last, 65536     *sizeof(UWORD));
  if( ND->next ) FreeMem( ND->next, SCANBUFLEN*sizeof(UWORD));
  FreeMem( ND, sizeof(struct NukeData));
}

struct NukeData *alloctabs(struct XpkSubParams *xpar)
{
  struct NukeData *ND;

  if ((xpar->xsp_Sub[0] = (LONG) (ND = (struct NukeData *) AllocMem(sizeof(struct NukeData),MEMF_CLEAR))) &&
      (ND->last = AllocMem(65536*sizeof(UWORD),0)) &&
      (ND->next = AllocMem(SCANBUFLEN*sizeof(UWORD),0)))
    return ND;
  else
  {
    XpksPackFree(xpar);
    return 0;
  }
}

LONG __asm XpksPackChunk(register __a0 struct XpkSubParams *xpar)
{
  struct NukeData *ND = (struct NukeData *)xpar->xsp_Sub[0];

  if (!ND)
    if (!(ND=alloctabs(xpar)))
      return XPKERR_NOMEM;

  ND->inbuf = xpar->xsp_InBuf;
  ND->outbuf= xpar->xsp_OutBuf;
  ND->ulen  = xpar->xsp_InLen;
  ND->clen  = xpar->xsp_OutBufLen-4;

  memset(ND->last,0,65536*sizeof(UWORD));
  memset(ND->next,0,SCANBUFLEN*sizeof(UWORD));

  if(((LONG)(xpar->xsp_OutLen = AsmPack(ND)))<0 || xpar->xsp_OutLen>xpar->xsp_InLen)
    return XPKERR_EXPANSION;
  return 0;
}

LONG __asm XpksUnpackChunk(register __a0 struct XpkSubParams *xpar)
{
//  APTR end;

//  end=
  AsmUnpack(xpar->xsp_InBuf,  (STRPTR)xpar->xsp_InBuf  + xpar->xsp_InLen,
	        xpar->xsp_OutBuf, (STRPTR)xpar->xsp_OutBuf + xpar->xsp_OutLen);

//  if( xpar->xsp_OutBuf+xpar->xsp_OutLen != end )
//    return XPKERR_CORRUPTPKD;

  return 0;
}

