home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 2001 January
/
VPR0101A.BIN
/
OLS
/
TAR32053
/
tar32053.exe
/
SRC
/
COMPAPI.C
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-23
|
18KB
|
552 lines
#ifndef __DEFCONF_H
#include "defconf.h"
#endif
/*
This file was hacked for kmtar for WIN32
at 1996-05-06.
by tantan SGL00213@niftyserve.or.jp
*/
/*@H************************ < COMPRESS API > ****************************
* $@(#) compapi.c,v 4.3d 90/01/18 03:00:00 don Release ^ *
* *
* compress : compapi.c <current version of compress algorithm> *
* *
* port by : Donald J. Gloistein *
* *
* Source, Documentation, Object Code: *
* released to Public Domain. This code is based on code as documented *
* below in release notes. *
* *
*--------------------------- Module Description --------------------------*
* Contains source code for modified Lempel-Ziv method (LZW) compression *
* and decompression. *
* *
* This code module can be maintained to keep current on releases on the *
* Unix system. The command shell and dos modules can remain the same. *
* *
*--------------------------- Implementation Notes --------------------------*
* *
* compiled with : compress.h compress.fns compress.c *
* linked with : compress.obj compusi.obj *
* *
* problems: *
* *
* *
* CAUTION: Uses a number of defines for access and speed. If you change *
* anything, make sure about side effects. *
* *
* Compression: *
* Algorithm: use open addressing double hashing (no chaining) on the *
* prefix code / next character combination. We do a variant of Knuth's *
* algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime *
* secondary probe. Here, the modular division first probe is gives way *
* to a faster exclusive-or manipulation. *
* Also block compression with an adaptive reset was used in original code, *
* whereby the code table is cleared when the compression ration decreases *
* but after the table fills. This was removed from this edition. The table *
* is re-sized at this point when it is filled , and a special CLEAR code is *
* generated for the decompressor. This results in some size difference from *
* straight version 4.0 joe Release. But it is fully compatible in both v4.0 *
* and v4.01 *
* *
* Decompression: *
* 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. The *
* tables used herein are shared with those of the compress() routine. *
* *
* Initials ---- Name --------------------------------- *
* DjG Donald J. Gloistein, current port to MsDos 16 bit *
* Plus many others, see rev.hst file for full list *
* LvR Lyle V. Rains, many thanks for improved implementation *
* of the compression and decompression routines. *
*************************************************************************@H*/
#include <stdio.h>
#include <io.h>
#include "compress.h" /* contains the rest of the include file declarations */
static int offset;
static long int in_count ; /* length of input */
static long int bytes_out; /* length of compressed output */
static INTCODE prefxcode, nextfree;
static INTCODE highcode;
static INTCODE maxcode;
static HASH hashsize;
static int bits;
#include "defs.h"
/*
* The following two parameter tables are the hash table sizes and
* maximum code values for various code bit-lengths. The requirements
* are that Hashsize[n] must be a prime number and Maxcode[n] must be less
* than Maxhash[n]. Table occupancy factor is (Maxcode - 256)/Maxhash.
* Note: I am using a lower Maxcode for 16-bit codes in order to
* keep the hash table size less than 64k entries.
*/
CONST HASH hs[] = {
0x13FF, /* 12-bit codes, 75% occupancy */
0x26C3, /* 13-bit codes, 80% occupancy */
0x4A1D, /* 14-bit codes, 85% occupancy */
0x8D0D, /* 15-bit codes, 90% occupancy */
0xFFD9 /* 16-bit codes, 94% occupancy, 6% of code values unused */
};
#define Hashsize(maxb) (hs[(maxb) -MINBITS])
CONST INTCODE mc[] = {
0x0FFF, /* 12-bit codes */
0x1FFF, /* 13-bit codes */
0x3FFF, /* 14-bit codes */
0x7FFF, /* 15-bit codes */
0xEFFF /* 16-bit codes, 6% of code values unused */
};
#define Maxcode(maxb) (mc[(maxb) -MINBITS])
#ifdef __STDC__
#ifdef DEBUG
#define allocx(type, ptr, size) \
(((ptr) = (type FAR *) emalloc((unsigned int)(size),sizeof(type))) == NULLPTR(type) \
? (fprintf(stderr,"%s: "#ptr" -- ", prog_name), NOMEM) : OK \
)
#else
#define allocx(type,ptr,size) \
(((ptr) = (type FAR *) emalloc((unsigned int)(size),sizeof(type))) == NULLPTR(type) \
? NOMEM : OK \
)
#endif
#else
#define allocx(type,ptr,size) \
(((ptr) = (type FAR *) emalloc((unsigned int)(size),sizeof(type))) == NULLPTR(type) \
? NOMEM : OK \
)
#endif
#define free_array(type,ptr,offset) \
if (ptr != NULLPTR(type)) { \
efree((ALLOCTYPE FAR *)((ptr) + (offset))); \
(ptr) = NULLPTR(type); \
}
/*
* Macro to allocate new memory to a pointer with an offset value.
*/
#define alloc_array(type, ptr, size, offset) \
( allocx(type, ptr, (size) - (offset)) != OK \
? NOMEM \
: (((ptr) -= (offset)), OK) \
)
static char FAR *sfx = NULLPTR(char) ;
#define suffix(code) sfx[code]
#if (SPLIT_PFX)
static CODE FAR *pfx[2] = {NULLPTR(CODE), NULLPTR(CODE)};
#else
static CODE FAR *pfx = NULLPTR(CODE);
#endif
#if (SPLIT_HT)
static CODE FAR *ht[2] = {NULLPTR(CODE),NULLPTR(CODE)};
#else
static CODE FAR *ht = NULLPTR(CODE);
#endif
static INTCODE alloc_tables_oldmaxcode = 0;
static HASH alloc_tables_oldhashsize = 0;
int alloc_tables(maxcode, hashsize)
INTCODE maxcode;
HASH hashsize;
{
//static INTCODE oldmaxcode = 0;
//static HASH oldhashsize = 0;
if (hashsize > alloc_tables_oldhashsize) {
#if (SPLIT_HT)
free_array(CODE,ht[1], 0);
free_array(CODE,ht[0], 0);
#else
free_array(CODE,ht, 0);
#endif
alloc_tables_oldhashsize = 0;
}
if (maxcode > alloc_tables_oldmaxcode) {
#if (SPLIT_PFX)
free_array(CODE,pfx[1], 128);
free_array(CODE,pfx[0], 128);
#else
free_array(CODE,pfx, 256);
#endif
free_array(char,sfx, 256);
if ( alloc_array(char, sfx, maxcode + 1, 256)
#if (SPLIT_PFX)
|| alloc_array(CODE, pfx[0], (maxcode + 1) / 2, 128)
|| alloc_array(CODE, pfx[1], (maxcode + 1) / 2, 128)
#else
|| alloc_array(CODE, pfx, (maxcode + 1), 256)
#endif
) {
alloc_tables_oldmaxcode = 0;
exit_stat = NOMEM;
return(NOMEM);
}
alloc_tables_oldmaxcode = maxcode;
}
if (hashsize > alloc_tables_oldhashsize) {
if (
#if (SPLIT_HT)
alloc_array(CODE, ht[0], (hashsize / 2) + 1, 0)
|| alloc_array(CODE, ht[1], hashsize / 2, 0)
#else
alloc_array(CODE, ht, hashsize, 0)
#endif
) {
alloc_tables_oldhashsize = 0;
exit_stat = NOMEM;
return(NOMEM);
}
alloc_tables_oldhashsize = hashsize;
}
return (OK);
}
# if (SPLIT_PFX)
/*
* We have to split pfx[] table in half,
* because it's potentially larger than 64k bytes.
*/
# define prefix(code) (pfx[(code) & 1][(code) >> 1])
# else
/*
* Then pfx[] can't be larger than 64k bytes,
* or we don't care if it is, so we don't split.
*/
# define prefix(code) (pfx[code])
# endif
/* The initializing of the tables can be done quicker with memset() */
/* but this way is portable through out the memory models. */
/* If you use Microsoft halloc() to allocate the arrays, then */
/* include the pragma #pragma function(memset) and make sure that */
/* the length of the memory block is not greater than 64K. */
/* This also means that you MUST compile in a model that makes the */
/* default pointers to be far pointers (compact or large models). */
/* See the file COMPUSI.DOS to modify function emalloc(). */
# if (SPLIT_HT)
/*
* We have to split ht[] hash table in half,
* because it's potentially larger than 64k bytes.
*/
# define probe(hash) (ht[(hash) & 1][(hash) >> 1])
# define init_tables() \
{ \
hash = hashsize >> 1; \
ht[0][hash] = 0; \
while (hash--) ht[0][hash] = ht[1][hash] = 0; \
highcode = ~(~(INTCODE)0 << (bits = INITBITS)); \
nextfree = (block_compress ? FIRSTFREE : 256); \
}
# else
/*
* Then ht[] can't be larger than 64k bytes,
* or we don't care if it is, so we don't split.
*/
# define probe(hash) (ht[hash])
# define init_tables() \
{ \
hash = hashsize; \
while (hash--) ht[hash] = 0; \
highcode = ~(~(INTCODE)0 << (bits = INITBITS)); \
nextfree = (block_compress ? FIRSTFREE : 256); \
}
# endif
/* ------------------------------------------*/
static int prevbits = 0;
static int no_res_flag=NO;
void fatal(char *s,char *mes);
/* nextcode()の内部変数*/
static int nextcode_size;
static UCHAR nextcode_inbuf[MAXBITS];
int nextcode(codeptr)
INTCODE *codeptr;
/* Get the next code from input and put it in *codeptr.
* Return (TRUE) on success, or return (FALSE) on end-of-file.
* Adapted from COMPRESS V4.0.
*/
{
//static int size;
//static UCHAR inbuf[MAXBITS];
register INTCODE code;
register int shift;
UCHAR *bp;
/* If the next entry is a different bit-size than the preceeding one
* then we must adjust the size and scrap the old buffer.
*/
if (prevbits != bits) {
prevbits = bits;
nextcode_size = 0;
}
/* If we can't read another code from the buffer, then refill it.
*/
if (nextcode_size - (shift = offset) < bits) {
/* Read more input and convert size from # of bytes to # of bits */
if ((nextcode_size = v_read(nextcode_inbuf, bits)) <= 0)
return NO;
nextcode_size <<= 3;
offset = shift = 0;
}
/* Get to the first byte. */
bp = nextcode_inbuf + (shift >> 3);
/* Get first part (low order bits) */
code = (*bp++ >> (shift &= 7));
/* high order bits. */
code |= *bp++ << (shift = 8 - shift);
if ((shift += 8) < bits) code |= *bp << shift;
*codeptr = code & highcode;
offset += bits;
return (TRUE);
}
/*--------------------- decompress ----------------*/
static INTCODE _code,savecode;
FLAG fulltable, cleartable;
static char sufxchar,*token= NULL; /* String buffer to build token */
static int maxtoklen = MAXTOKLEN;
static first_chk=0;
/*#define _putc(a) *Zbuf=(char)(a);Zbuf++;(*len)++*/
/*#define _putc(a) putc((a),stdout);(*len)++*/
# define INBUFSIZE 10000
/* _putcの内部変数*/
static char *_putc_p=NULL;
void _putc(int c)
{
extern void flush_window(void);
#ifdef DYN_ALLOC
extern unsigned char *window;
#else
extern unsigned char window[];
#endif
//static char *p=NULL;
extern unsigned int outcnt;
if (_putc_p == NULL){
#ifdef DYN_ALLOC
if ((window = malloc(INBUFSIZE)) == NULL)
fatal("compapi","out of memory");
#endif
_putc_p = window;
outcnt=0;
}
if (outcnt < INBUFSIZE)
_putc_p[outcnt++] = c;
if (outcnt == INBUFSIZE){
flush_window();
_putc_p = window;
}
}
int de_comp(void)
{
static int i;
ss:
if (first_chk){
if (!nextcode(&savecode))
return EOF;
}else
first_chk=1;
if ((_code = savecode) == CLEAR && cleartable) {
highcode = ~(~(INTCODE)0 << (bits = INITBITS));
fulltable = FALSE;
nextfree = (cleartable = block_compress) == FALSE ? 256 : FIRSTFREE;
if (!nextcode(&prefxcode))
return OK;
/* putc((sufxchar = (char)prefxcode), write_out);*/
_putc((sufxchar = (char)prefxcode));
goto ss; /* sorry for "goto" */
}
i = 0;
if (_code >= nextfree && !fulltable) {
if (_code != nextfree){
exit_stat = CODEBAD;
return OK; /* Non-existant code */
}
/* Special case for sequence KwKwK (see text of article) */
_code = prefxcode;
token[i++] = sufxchar;
}
/* Build the token string in reverse order by chasing down through
* successive prefix tokens of the current token. Then output it.
*/
while (_code >= 256) {
# ifdef DEBUG
/* These are checks to ease paranoia. Prefix codes must decrease
* monotonically, otherwise we must have corrupt tables. We can
* also check that we haven't overrun the token buffer.
*/
if (_code <= (INTCODE)prefix(_code)){
exit_stat= TABLEBAD;
return OK;
}
# endif
if (i >= maxtoklen) {
maxtoklen *= 2; /* double the size of the token buffer */
if ((token =realloc(token,(unsigned int)maxtoklen)) == NULLPTR(char)) {
exit_stat = TOKTOOBIG;
return OK;
}
}
token[i++] = suffix(_code);
_code = (INTCODE)prefix(_code);
}
_putc(sufxchar = (char)_code);
while (--i >= 0){
_putc(token[i]);
}
/* If table isn't full, add new token code to the table with
* codeprefix and codesuffix, and remember current code.
*/
if (!fulltable) {
_code = nextfree;
assert(256 <= _code && _code <= maxcode);
prefix(_code) = (CODE)prefxcode;
suffix(_code) = sufxchar;
prefxcode = savecode;
if (_code++ == highcode) {
if (highcode >= maxcode) {
fulltable = TRUE;
--_code;
}
else {
++bits;
highcode += _code; /* nextfree == highcode + 1 */
}
}
nextfree = _code;
}
return OK;
}
void de_comp_init2(void)
{
exit_stat = OK;
/* Initialze the token buffer. */
if (token == NULL && (token = (char *)malloc((unsigned int)maxtoklen)) == NULL) {
exit_stat = NOMEM;
return;
}
if (alloc_tables(maxcode = ~(~(INTCODE)0 << maxbits),0)) /* exit_stat already set */
return;
cleartable = TRUE;
savecode = CLEAR;
offset = 0;
prevbits = 0;
no_res_flag=NO;
first_chk=0;
}
#ifdef DLL
void compapi_end(void)
{
#if (SPLIT_HT)
free_array(CODE,ht[1], 0);
free_array(CODE,ht[0], 0);
#else
free_array(CODE,ht, 0);
#endif
alloc_tables_oldhashsize = 0;
#if (SPLIT_PFX)
free_array(CODE,pfx[1], 128);
free_array(CODE,pfx[0], 128);
#else
free_array(CODE,pfx, 256);
#endif
free_array(char,sfx, 256);
}
void compapi_static_init(void)
{
offset=0;
in_count=0 ; /* length of input */
bytes_out=0; /* length of compressed output */
prefxcode=0, nextfree=0;
highcode=0;
maxcode=0;
hashsize=0;
bits=0;
sfx = NULLPTR(char) ;
//#define suffix(code) sfx[code]
#if (SPLIT_PFX)
//static CODE FAR *pfx[2] = {NULLPTR(CODE), NULLPTR(CODE)};
pfx[0]=NULLPTR(CODE);
pfx[1]=NULLPTR(CODE);
#else
//static CODE FAR *pfx = NULLPTR(CODE);
pfx=NULLPTR(CODE);
#endif
#if (SPLIT_HT)
//static CODE FAR *ht[2] = {NULLPTR(CODE),NULLPTR(CODE)};
ht[0]=NULLPTR(CODE);
ht[1]=NULLPTR(CODE);
#else
//static CODE FAR *ht = NULLPTR(CODE);
ht=NULLPTR(CODE);
#endif
alloc_tables_oldmaxcode = 0;
alloc_tables_oldhashsize = 0;
prevbits = 0;
no_res_flag=NO;
/* nextcode()の内部変数*/
nextcode_size=0;
memset(nextcode_inbuf,0,sizeof(UCHAR)*MAXBITS);
_code=0,savecode=0;
fulltable=0, cleartable=0;
sufxchar=0,token= NULL; /* String buffer to build token */
maxtoklen = MAXTOKLEN;
first_chk=0;
/* _putcの内部変数*/
_putc_p=NULL;
}
#endif /* DLL */