home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ANews 1
/
AnewsCD01.iso
/
Indispensables
/
Compression
/
xfd
/
Developer
/
Sources
/
C
/
UNIX-Compress.c
< prev
Wrap
C/C++ Source or Header
|
1999-08-03
|
9KB
|
320 lines
unsigned char version[] = "$VER: UNIX-Compress 1.2 (04.08.1998) by SDI";
/* Objectheader
Name: UNIX-Compress.c
Description: xfd external decruncher for UNIX compress files
Author: SDI (stoecker@amigaworld.com)
Distribution: PD
1.0 22.12.97 : first version
1.1 23.12.97 : added memory expansion
1.2 04.08.98 : bug fix for block compress, added internal SysBase
*/
/* Because there is no way to find out the size of uncrunched file, this
routine uses a destination buffer, which is 4 times as large as the
source file. When there is not enough memory, the largest memory block
is used.
This does surely not cover all Compress files! So there may be some
which cannot be decrunched. XPKERR_CORRUPTEDDATA should be reported for
these. In this case the program tries to allocate the largest available
memory block and restarts decrunching.
Has anyone a better idea how to find out destination length?
*/
#include <libraries/xfdmaster.h>
#include <proto/exec.h>
#include <exec/memory.h>
#ifdef __MAXON__
#define __asm
#endif
#define MAXCODE(n) (((ULONG) 1 << (n)) - 1)
#define BITS 16
#define STACKSIZE 8000
#define FIRST 257 /* first free entry */
#define CLEAR 256 /* table clear output code */
#define INIT_BITS 9 /* initial number of bits/code */
/* Defines for third byte of header */
#define BIT_MASK 0x1f
#define BLOCK_MASK 0x80
#define LZW_RESERVED 0x60
/* Masks 0x40 and 0x20 are free. I think 0x20 should mean that
there is a fourth header byte (for expansion). */
UBYTE rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
LONG decomp(struct CompressData *, STRPTR, ULONG, STRPTR, ULONG);
LONG getcode(struct CompressData *);
struct CompressData {
UWORD block_compress;
WORD clear_flg;
UWORD n_bits; /* number of bits/code */
UWORD maxbits; /* user settable max # bits/code */
ULONG maxcode; /* maximum code, given n_bits */
ULONG maxmaxcode;
LONG free_ent;
LONG offset;
LONG size;
STRPTR inptr; /* current input pointer */
STRPTR inendptr; /* end of input buffer */
UWORD * tab_prefixof;
STRPTR tab_suffixof;
STRPTR stack;
UBYTE buf[BITS];
};
/************** Here starts xfd stuff - the xfdSlave structure **********/
#define MASTER_VERS 36
typedef BOOL (*xfdFunc) ();
LONG __asm RecogCompress(register __a0 STRPTR buf, register __d0 ULONG length);
BOOL __asm DecrunchCompress(register __a0 struct xfdBufferInfo * xbi,
register __a6 struct xfdMasterBase *xfdMasterBase);
struct xfdSlave FirstSlave = {
0, XFDS_VERSION, MASTER_VERS, "UNIX Compress", XFDPFF_DATA, 0,
(xfdFunc) RecogCompress, (xfdFunc) DecrunchCompress, 0, 0, 0, 0, 4};
LONG __asm RecogCompress(register __a0 STRPTR buf, register __d0 ULONG length)
{
if(*((UWORD *)buf) == 0x1F9D)
{
UBYTE mb = buf[2];
if(mb & LZW_RESERVED) /* Unknown format */
return 0;
if((mb & BIT_MASK) > BITS) /* Too much bits */
return 0;
return 1; /* Now should be a correct file */
}
return 0;
}
BOOL __asm DecrunchCompress(register __a0 struct xfdBufferInfo * xbi,
register __a6 struct xfdMasterBase *xfdmasterBase)
{
struct CompressData cd;
LONG ret = -XFDERR_NOMEMORY;
ULONG maxmaxcode = 1<<((((STRPTR)xbi->xfdbi_SourceBuffer)[2])&BIT_MASK);
struct ExecBase *SysBase;
SysBase = xfdmasterBase->xfdm_ExecBase;
if((cd.tab_prefixof = (UWORD *) AllocMem(sizeof(UWORD)*maxmaxcode, MEMF_ANY)))
{
if((cd.stack = (STRPTR) AllocMem(STACKSIZE, MEMF_ANY)))
{
if((cd.tab_suffixof = (STRPTR) AllocMem(maxmaxcode, MEMF_ANY)))
{
ULONG bufsize;
bufsize = AvailMem(MEMF_LARGEST|xbi->xfdbi_TargetBufMemType);
if((xbi->xfdbi_TargetBufLen = xbi->xfdbi_SourceBufLen<<2) > bufsize)
xbi->xfdbi_TargetBufLen = bufsize;
if((xbi->xfdbi_TargetBuffer = AllocMem(xbi->xfdbi_TargetBufLen,
xbi->xfdbi_TargetBufMemType)))
{
if((ret = decomp(&cd, (STRPTR) xbi->xfdbi_SourceBuffer,
xbi->xfdbi_SourceBufLen, (STRPTR) xbi->xfdbi_TargetBuffer,
xbi->xfdbi_TargetBufLen)) > 0)
xbi->xfdbi_TargetBufSaveLen = ret;
else
{
FreeMem(xbi->xfdbi_TargetBuffer, xbi->xfdbi_TargetBufLen);
if(bufsize != xbi->xfdbi_TargetBufLen)
{
/* expand memory to full available and retry */
xbi->xfdbi_TargetBufLen = AvailMem(MEMF_LARGEST|xbi->xfdbi_TargetBufMemType);
if((xbi->xfdbi_TargetBuffer = AllocMem(xbi->xfdbi_TargetBufLen,
xbi->xfdbi_TargetBufMemType)))
{
if((ret = decomp(&cd, (STRPTR) xbi->xfdbi_SourceBuffer,
xbi->xfdbi_SourceBufLen, (STRPTR) xbi->xfdbi_TargetBuffer,
xbi->xfdbi_TargetBufLen)) > 0)
xbi->xfdbi_TargetBufSaveLen = ret;
else
FreeMem(xbi->xfdbi_TargetBuffer, xbi->xfdbi_TargetBufLen);
}
}
}
}
FreeMem(cd.tab_suffixof, maxmaxcode);
}
FreeMem(cd.stack, STACKSIZE);
}
FreeMem(cd.tab_prefixof, sizeof(UWORD)*maxmaxcode);
}
if(ret <= 0)
{
xbi->xfdbi_TargetBufLen = xbi->xfdbi_TargetBufSaveLen = 0;
xbi->xfdbi_TargetBuffer = 0;
xbi->xfdbi_Error = -ret;
return 0;
}
return (BOOL) ret;
}
/* Decompress. This routine adapts to the codes in the file building the
* "string" table on-the-fly; requiring no table to be stored in the
* compressed file.
*/
/* negative values are error codes, positive value is resulting size */
LONG decomp(struct CompressData *cd, STRPTR inbuf, ULONG insize,
STRPTR outbuf, ULONG outsize)
{
LONG finchar, code, oldcode, incode, blockcomp;
STRPTR outptr = outbuf, stackp = cd->stack,
stack = cd->stack, outend = outbuf+outsize;
cd->maxbits = inbuf[2];
blockcomp = cd->block_compress = cd->maxbits & BLOCK_MASK;
cd->maxbits &= BIT_MASK;
cd->maxmaxcode = 1 << cd->maxbits;
cd->maxcode = MAXCODE(cd->n_bits = INIT_BITS);
cd->free_ent = ((cd->block_compress) ? FIRST : 256);
cd->clear_flg = cd->offset = cd->size = 0;
cd->inptr = inbuf+3;
cd->inendptr = inbuf+insize;
/* Initialize the first 256 entries in the table. */
for(code = 255; code >= 0; code--)
{
cd->tab_prefixof[code] = 0;
cd->tab_suffixof[code] = (UBYTE) code;
}
if((finchar = oldcode = getcode(cd)) == -1) /* EOF already ? */
return -XFDERR_CORRUPTEDDATA; /* Get out of here */
*(outptr++) = (UBYTE) finchar; /* first code must be 8 bits = UBYTE */
while((code = getcode(cd)) > -1)
{
if((code == CLEAR) && blockcomp)
{
for(code = 255; code >= 0; code--)
cd->tab_prefixof[code] = 0;
cd->clear_flg = 1;
cd->free_ent = FIRST - 1;
if((code = getcode(cd)) == -1)
break; /* O, untimely death! */
}
incode = code;
/* Special case for KwKwK string. */
if(code >= cd->free_ent)
{
*stackp++ = finchar;
code = oldcode;
}
/* Generate output characters in reverse order */
while(code >= 256)
{
*stackp++ = cd->tab_suffixof[code];
code = cd->tab_prefixof[code];
}
*stackp++ = finchar = cd->tab_suffixof[code];
if(stackp - stack > outend - outptr) /* buffer was to short :-( */
return -XFDERR_CORRUPTEDDATA;
/* And put them out in forward order */
do
{
*(outptr++) = *(--stackp);
} while(stackp > stack);
/* Generate the new entry. */
if((code = cd->free_ent) < cd->maxmaxcode)
{
cd->tab_prefixof[code] = (UWORD) oldcode;
cd->tab_suffixof[code] = finchar;
cd->free_ent = code+1;
}
/* Remember previous code. */
oldcode = incode;
}
return (outptr-outbuf);
}
/* Read one code from input. If EOF, return -1. */
LONG getcode(struct CompressData *cd)
{
LONG code, r_off, bits;
UBYTE *bp = cd->buf;
if(cd->clear_flg > 0 || cd->offset >= cd->size || cd->free_ent > cd->maxcode)
{
/*
* If the next entry will be too big for the current code
* size, then we must increase the size. This implies reading
* a new buffer full, too.
*/
if(cd->free_ent > cd->maxcode)
{
if(++cd->n_bits == cd->maxbits)
cd->maxcode = cd->maxmaxcode; /* won't get any bigger now */
else
cd->maxcode = MAXCODE(cd->n_bits);
}
if(cd->clear_flg > 0)
{
cd->maxcode = MAXCODE(cd->n_bits = INIT_BITS);
cd->clear_flg = 0;
}
if(cd->inendptr <= cd->inptr)
return -1; /* end of file */
/* This reads maximum n_bits characters into buf */
cd->size = 0;
while(cd->size < cd->n_bits && cd->inptr < cd->inendptr)
cd->buf[cd->size++] = *(cd->inptr++);
cd->offset = 0;
/* Round size down to integral number of codes */
cd->size = (cd->size << 3) - (cd->n_bits - 1);
}
r_off = cd->offset;
bits = cd->n_bits;
/* Get to the first byte. */
bp += (r_off >> 3);
r_off &= 7;
/* Get first part (low order bits) */
code = (*bp++ >> r_off);
bits -= (8 - r_off);
r_off = 8 - r_off; /* now, offset into code word */
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
if(bits >= 8)
{
code |= *bp++ << r_off;
r_off += 8;
bits -= 8;
}
/* high order bits. */
code |= (*bp & rmask[bits]) << r_off;
cd->offset += cd->n_bits;
return code;
}