
/* These really aren't necessary.. */
typedef unsigned char uchar;
typedef unsigned short int uint;

#define NO_SUB_PRAGMAS
#define A3000 XPKMF_A3000SPEED
#define HASH_LEN 4096-1		/* Use a 4096 dictionary. If you ever
				   think of changing this number you
				   also have to modify the .asm-files.
									*/
/* However, since this version only manage a gap of 4098 bytes, a larger
   dictionary hardly improves compression. If you apply long-longpatterns
   it might be usefull...
*/

#include <string.h>
#include <stdlib.h>

#include <libraries/xpksub.h>


/* Quick assembler unpack routine */
long __asm unpack (register __a0 char *);
uchar *__asm pack_one (register __a0 uint *, register __a1 uchar *,
       register __a2 uchar *, register __a3 uchar *, register __a6 uchar **,
		       register __d6 uchar *);


XMINFO RdcnMode =
{
  NULL,				/* next 		*/
  100,				/* upto 		*/
  A3000,			/* flags 		*/
  4,				/* packmem 		*/
  0,				/* unpackmem 		*/
  150,				/* packspeed,   K/sec 	*/
  630,				/* unpackspeed, K/sec 	*/
  320,				/* ratio,      *0.1% 	*/
  0,				/* reserved 		*/
  "normal"			/* description 		*/
};

static struct XpkInfo RdcnInfo =
{
  1,				/* info version */
  0,				/* lib  version */
  0,				/* master vers  */
  0,				/* pad          */
  "RDCN",			/* short name   */
  "Ross Data Compression 1.0",	/* long name    */
  "Packs fatser than BLZW, depacks faster than NUKE",	/* description	*/
  0x5244434e,			/* 4 letter ID  */
  XPKIF_PK_CHUNK | XPKIF_UP_CHUNK,	/* flags        */
  65535,			/* max in chunk */
  0,				/* min in chunk */
  65500,			/* def in chunk */
  NULL,				/* pk message   */
  NULL,				/* up message   */
  NULL,				/* pk past msg  */
  NULL,				/* up past msg  */
  100,				/* def mode     */
  0,				/* pad          */
  &RdcnMode			/* modes        */
};

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


void __saveds __asm
XpksPackFree (REG __a0 XPARAMS * xpar)
{
  if (xpar->Sub[0] != 0)
    {				/* Any dictionary-mem allocated? */
      free ((char *) xpar->Sub[0]);
      xpar->Sub[0] = 0;
    }
}

/*
 * This forces the next chunk to be uncompressable independent from the
 * previous one. Ie. it clears the hash table
 * This really shouldn't be necessary with RDCN, _but_ a future xpkmaster
 * _might_ use different memory-chunks for every call to the packer.
 */
long __saveds __asm
XpksPackReset (REG __a0 XPARAMS * xpar)
{
  char *ptr = (char *) xpar->Sub[0];
  if (ptr != 0)
    {
      memset (ptr, 0, 4096 * sizeof (uchar **));
    }

  return 0;
}


void __saveds __asm
XpksUnpackFree (REG __a0 XPARAMS * xpar)
{
  /* Decompression does not need any additional data */
}


/* Pack a chunk */

long __saveds __asm
XpksPackChunk (REG __a0 XPARAMS * xpar)
{

  uchar **hash_tbl;
  uint *ctrl_idx;
  uchar *out_idx, *outbuff_end;
  uchar *anchor;

  uchar *inbuff = xpar->InBuf;
  uint inbuff_len = xpar->InLen;
  uchar *outbuff = xpar->OutBuf;

  uchar *in_idx = inbuff;
  uchar *inbuff_end = inbuff + inbuff_len;
  hash_tbl = (char **) xpar->Sub[0];
  ctrl_idx = (uint *) outbuff;


    out_idx = outbuff + sizeof (uint);
  outbuff_end = outbuff + xpar->OutBufLen - 48;



  if (xpar->Sub[0] == 0)
    {

      xpar->Sub[0] = (long) calloc (4100, sizeof (uchar **));
      hash_tbl = (char **) xpar->Sub[0];
    }


  /* Skip the compression for a small buffer */

  if (inbuff_len <= 18 || xpar->Sub[0] == 0)
    return XPKERR_EXPANSION;


  /* Scan through inbuff */

  anchor = pack_one (ctrl_idx, in_idx, out_idx, inbuff_end, hash_tbl, outbuff_end);


  if (anchor == NULL)
    return XPKERR_EXPANSION;

  xpar->OutLen = anchor - outbuff;
  return 0;
}

long __saveds __asm
XpksUnpackChunk (REG __a0 XPARAMS * xpar)
{
  long fep;
  fep = unpack ((char *)xpar);
  return fep;

}
