home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
packery
/
xpkilzr
/
source
/
cilzr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1977-12-31
|
9KB
|
252 lines
/**-----------------------------------------------------------------------
* Bloque de includes, por fin me ocupan menos de una pagina de
* impresisn, lo que hay que hacer para tener todos los prototipos..
*
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#define NO_SUB_PRAGMAS
#include <libraries/xpksub.h>
#include "cbitio.h" /* custom includes */
#include "ilzr.h"
/**-----------------------------------------------------------------------
* Prototipos para todas estas paridas necesarias para compilar.
*
**/
/**-----------------------------------------------------------------------
* En un principio utilizaba la funcisn de HASH del COMRESS de GNU en
* UNIX, pero por motivos de eficiencia he tenido que cambiarla. La forma
* actual se inspira en el algoritmo de Rabin & Karp ( En el libro :
* "Algorithms" de Sedgewick de Addison-Wesley p.252 )
*
**/
#define BestMatch( scan , matchpos , bestlen ) \
{ \
if( (xparinbuf + matchpos) <= scan ) \
{ \
ioaux = 0; \
bestlen = MIN_MATCH - 1; \
scanend = scan[ bestlen ]; \
strend = scan + MAX_MATCH; \
current = matchpos; \
lastmatch= matchpos; \
while( current != NIL && lastmatch >= current ) \
{ \
match = xparinbuf + current; \
if( match[ bestlen ] != scanend || \
*match != *scan || \
*++match != scan[1] ) \
{ \
lastmatch = current; \
current = prev[ current ]; \
ioaux++; \
if( ioaux > MAX_HASH_COL ) \
break; \
continue; \
} \
scan+=2; /* do not try to put in the if condition */ \
match++; \
do \
{ \
}while( *++scan == *++match && *++scan == *++match && \
*++scan == *++match && *++scan == *++match && \
*++scan == *++match && *++scan == *++match && \
*++scan == *++match && *++scan == *++match && \
scan < strend ); /* Estraqo pero mejor codigo */ \
conta = MAX_MATCH - (UBYTE)(strend - scan); /* len para ahorrar */\
scan = strend - MAX_MATCH; \
if( conta > bestlen ) \
{ \
bestlen = conta; \
matchpos = current; \
if( conta >= MAX_MATCH ) \
break; \
scanend = scan[ bestlen ]; \
} \
lastmatch = current; \
current = prev[ current ]; \
} \
} \
}
/**-----------------------------------------------------------------------
* En pocas lineas se adentrara al nucleo de todo el sistema de
* compresisn de datos, aunque parezca mentira intentare que el
* sistema mantenga el coste ideal mmnimo, coste LINEAL??.
* Esto son las mejores intenciones, ya veremos en que se nos queda.
*
**/
long __saveds __asm XpksPackChunk( REG __a0 XPARAMS *xpar )
{
/* variables para input - output */
register UBYTE outmask;
register CHARS *inpb;
CHARS *endinp;
register CHARS *outb;
CHARS *endout;
ULONG ioaux; /* tambien se usa en BestMach */
UBYTE endoffile;
/* varialbles utilizadas en BestMach */
CHARS scanend;
CHARS *strend;
register CHARS *match;
UWORD current;
UWORD lastmatch;
/* bloque general de compres */
UBYTE lookahead; /* siempre RAW_LOOKAHEAD < 255 */
UBYTE matchlen; /* siempre RAW_LOOKAHEAD < 255 */
UBYTE replace; /* cuanto se ha de ampliar "lookahead" */
UBYTE conta; /* tambien se usa en BestMach */
long bitcount; /* es un LONG para compatibilidad */
CHARS *bumpcode;
long temp;
CHARS *xparinbuf; /* todo el mundo la utiliza */
UWORD hash_key; /* actual hash value */
UWORD matchpos; /* position of matchlen */
register CHARS *actp; /* posicion en wwindow fich */
register UWORD *head; /* dictionary */
register UWORD *prev; /* previous in the hash line */
/**
* Bloque de inicializacsn + reserva de memoria para las tablas
*
**/
if( !xpar->Sub[0] )
{
if( !(head = malloc( sizeof( UWORD ) * HASH_SIZE )) )
return( XPKERR_NOMEM );
if( !(prev = malloc( sizeof( UWORD ) * (WIND_SIZE+MAX_MATCH) ) ) )
{
free( head );
return( XPKERR_NOMEM );
}
xpar->Sub[0]=(long)prev;
xpar->Sub[1]=(long)head;
}
else
{
prev= (UWORD *)xpar->Sub[0];
head= (UWORD *)xpar->Sub[1];
}
/* previous y wwindow se autoinilizalizan */
memset( head , NIL , HASH_SIZE*sizeof( UWORD ) ); /* head */
InitOutput();
InitInput();
endoffile = 0;
temp = xpar->InLen;
OutputBits( temp , 16 ); /* NEED store the long of this block */
xparinbuf = xpar->InBuf;
bitcount = INIT_BIT_BUMP;
bumpcode = xparinbuf+(1<<INIT_BIT_BUMP);
matchpos = 0; /* No hace falta pero evita un WARNING */
matchlen = 0;
actp = xparinbuf;
hash_key = 0;
/**
* Bloque de la precarga necesaria para poder empezar el bucle
*
**/
for( conta = 1 ; conta <= MAX_MATCH && !EndOfFile() ; conta++ )
InputByte( );
lookahead = conta-2;
if( conta > 3 )
{
REHASH( hash_key , actp[1] );
REHASH( hash_key , actp[2] );
}
/**
* Comienzo del bucle principal para la compresisn de datos
*
**/
while( lookahead > 0 )
{
if( matchlen > lookahead )
matchlen = lookahead;
if( matchlen < MIN_MATCH ) /* Sale a cuenta 2 bloque ? */
{
replace=1;
OutputBit( 1 );
temp=(long)*actp;
OutputBits( temp , BITS_CHARS );
}
else
{
replace=matchlen;
if( actp > bumpcode )
{
bitcount++;
bumpcode = xparinbuf + (1<<bitcount);
}
OutputBit( 0 );
temp = (long)matchpos;
OutputBits( temp , bitcount );
temp= (long)(matchlen - MIN_MATCH );
OutputBits( temp , BITS_LOOKAHEAD );
}
for( conta = 0 ; conta < replace ; conta++ )
{
if( EndOfFile() )
lookahead--;
else
InputByte( );
actp++;
REHASH( hash_key , actp[ MIN_MATCH -1 ] );
temp = (long)(actp - xparinbuf);
prev[ temp ] = matchpos = head [ hash_key ];
head[ hash_key ] = ( UWORD )temp;
}
BestMatch( actp , matchpos , matchlen ); /* potente macro eh !! */
}
/**
* No hace falta indicador de final de fichero pues se siempre
* la longitud, tampoco libero los recursos, de esto se encarga
* XpkPackFree
*
**/
xpar->OutLen = (long)outb - (long)xpar->OutBuf + 1; /* CUrIosO */
return( 0 );
}
/************************** End of ILZR.C *************************/