/*----------------------------------------------------------------------*
 * packer.c Convert data to "cmpByteRun1" run compression.     11/15/85
 *
 * By Jerry Morrison and Steve Shaw, Electronic Arts.
 * This software is in the public domain.
 *
 *	control bytes:
 *	 [0..127]   : followed by n+1 bytes of data.
 *	 [-1..-127] : followed by byte to be repeated (-n)+1 times.
 *	 -128       : NOOP.
 *
 * This version for the Commodore-Amiga computer.
 *----------------------------------------------------------------------*/
#include <exec/types.h>
#include "packer.h"

#define DUMP	0
#define RUN	1

#define MinRun 3	
#define MaxRun 128
#define MaxDat 128

static LONG putSize;

#define GetByte()	(*source++)
#define PutByte(c)	{ *dest++ = (c);   ++putSize; }

static char buf[256];	/* [TBD] should be 128?  on stack?*/

static BYTE *PutDump( BYTE *dest,int nn)
{
  int i;

  PutByte(nn-1);
  for( i = 0 ; i < nn ; i++)
    PutByte(buf[i]);
  return(dest);
}

static BYTE *PutRun(BYTE *dest,int nn,int cc)
{
	PutByte(-(nn-1));
	PutByte(cc);
	return(dest);
}

#define OutDump(nn)   dest = PutDump(dest, nn)
#define OutRun(nn,cc) dest = PutRun(dest, nn, cc)

/*----------- PackRow --------------------------------------------------*/
/* Given POINTERS TO POINTERS, packs one row, updating the source and
   destination pointers.  RETURNs count of packed bytes.*/
ULONG PackRow(BYTE* source,BYTE* dest,ULONG rowSize)
{
  char c,lastc;
  BOOL mode = DUMP;
  short nbuf;   		/* number of chars in buffer */
  short rstart = 0;	/* buffer index current run starts */

  putSize = 0;
  buf[0] = lastc = c = GetByte();  /* so have valid lastc */
  nbuf = 1;
  rowSize--;	/* since one byte eaten.*/

  for( ; rowSize ; --rowSize )
  {
    buf[nbuf++] = c = GetByte();
    switch( mode )
    {
      case DUMP:
        /* If the buffer is full, write the length byte then the data */
        if( nbuf>MaxDat )
        {
          OutDump(nbuf-1);  
          buf[0] = c; 
          nbuf = 1;
          rstart = 0; 
          break;
        }

        if( c == lastc )
        {
          if( nbuf-rstart >= MinRun )
          {
            if( rstart > 0 )
            OutDump(rstart);
            mode = RUN;
          }
          else if( rstart == 0 )
            mode = RUN;	/* no dump in progress, so can't lose by making these 2 a run.*/
        }
        else
          rstart = nbuf-1;  /* first of run */ 
        break;

      case RUN:
        if( (c != lastc) || (nbuf-rstart > MaxRun) )
        {
          /* output run */
          OutRun(nbuf-1-rstart,lastc);
          buf[0] = c;
          nbuf = 1; rstart = 0;
          mode = DUMP;
        }
        break;
    }

    lastc = c;
  }

  switch( mode )
  {
    case DUMP:
      OutDump(nbuf);
      break;
    case RUN:
      OutRun(nbuf-rstart,lastc);
      break;
	}

  if( putSize & 0x01 )
    PutByte(-128);

  return (ULONG)putSize;
}
