version 1.4, 1997/01/19 17:25:14 |
version 1.5, 1997/07/06 20:23:00 |
|
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
|
#include <fcntl.h> |
|
#include "compress.h" |
|
|
#define BITS 16 /* Default bits. */ |
#define BITS 16 /* Default bits. */ |
#define HSIZE 69001 /* 95% occupancy */ |
#define HSIZE 69001 /* 95% occupancy */ |
|
|
typedef long code_int; |
typedef long code_int; |
typedef long count_int; |
typedef long count_int; |
|
|
typedef u_char char_type; |
static u_char z_magic[] = |
static char_type magic_header[] = |
|
{'\037', '\235'}; /* 1F 9D */ |
{'\037', '\235'}; /* 1F 9D */ |
|
|
#define BIT_MASK 0x1f /* Defines for third byte of header. */ |
#define BIT_MASK 0x1f /* Defines for third byte of header. */ |
|
|
#define MAXCODE(n_bits) ((1 << (n_bits)) - 1) |
#define MAXCODE(n_bits) ((1 << (n_bits)) - 1) |
|
|
struct s_zstate { |
struct s_zstate { |
FILE *zs_fp; /* File stream for I/O */ |
int zs_fd; /* File stream for I/O */ |
char zs_mode; /* r or w */ |
char zs_mode; /* r or w */ |
enum { |
enum { |
S_START, S_MIDDLE, S_EOF |
S_START, S_MIDDLE, S_EOF |
|
|
int zs_offset; |
int zs_offset; |
long zs_in_count; /* Length of input. */ |
long zs_in_count; /* Length of input. */ |
long zs_bytes_out; /* Length of compressed output. */ |
long zs_bytes_out; /* Length of compressed output. */ |
long zs_out_count; /* # of codes output (for debugging). */ |
long zs_out_count; /* # of codes output (for debugging).*/ |
char_type zs_buf[BITS]; |
u_char zs_buf[BITS]; |
union { |
union { |
struct { |
struct { |
long zs_fcode; |
long zs_fcode; |
|
|
int zs_hshift; |
int zs_hshift; |
} w; /* Write paramenters */ |
} w; /* Write paramenters */ |
struct { |
struct { |
char_type *zs_stackp; |
u_char *zs_stackp; |
int zs_finchar; |
int zs_finchar; |
code_int zs_code, zs_oldcode, zs_incode; |
code_int zs_code, zs_oldcode, zs_incode; |
int zs_roffset, zs_size; |
int zs_roffset, zs_size; |
char_type zs_gbuf[BITS]; |
|
} r; /* Read parameters */ |
} r; /* Read parameters */ |
} u; |
} u; |
}; |
}; |
|
|
/* Definitions to retain old variable names */ |
/* Definitions to retain old variable names */ |
#define fp zs->zs_fp |
#define zs_fcode u.w.zs_fcode |
#define zmode zs->zs_mode |
#define zs_ent u.w.zs_ent |
#define state zs->zs_state |
#define zs_hsize_reg u.w.zs_hsize_reg |
#define n_bits zs->zs_n_bits |
#define zs_hshift u.w.zs_hshift |
#define maxbits zs->zs_maxbits |
#define zs_stackp u.r.zs_stackp |
#define maxcode zs->zs_maxcode |
#define zs_finchar u.r.zs_finchar |
#define maxmaxcode zs->zs_maxmaxcode |
#define zs_code u.r.zs_code |
#define htab zs->zs_htab |
#define zs_oldcode u.r.zs_oldcode |
#define codetab zs->zs_codetab |
#define zs_incode u.r.zs_incode |
#define hsize zs->zs_hsize |
#define zs_roffset u.r.zs_roffset |
#define free_ent zs->zs_free_ent |
#define zs_size u.r.zs_size |
#define block_compress zs->zs_block_compress |
|
#define clear_flg zs->zs_clear_flg |
|
#define ratio zs->zs_ratio |
|
#define checkpoint zs->zs_checkpoint |
|
#define offset zs->zs_offset |
|
#define in_count zs->zs_in_count |
|
#define bytes_out zs->zs_bytes_out |
|
#define out_count zs->zs_out_count |
|
#define buf zs->zs_buf |
|
#define fcode zs->u.w.zs_fcode |
|
#define hsize_reg zs->u.w.zs_hsize_reg |
|
#define ent zs->u.w.zs_ent |
|
#define hshift zs->u.w.zs_hshift |
|
#define stackp zs->u.r.zs_stackp |
|
#define finchar zs->u.r.zs_finchar |
|
#define code zs->u.r.zs_code |
|
#define oldcode zs->u.r.zs_oldcode |
|
#define incode zs->u.r.zs_incode |
|
#define roffset zs->u.r.zs_roffset |
|
#define size zs->u.r.zs_size |
|
#define gbuf zs->u.r.zs_gbuf |
|
|
|
/* |
/* |
* To save much memory, we overlay the table used by compress() with those |
* To save much memory, we overlay the table used by compress() with those |
|
|
* (stack used to be 8000 characters). |
* (stack used to be 8000 characters). |
*/ |
*/ |
|
|
#define htabof(i) htab[i] |
#define htabof(i) zs->zs_htab[i] |
#define codetabof(i) codetab[i] |
#define codetabof(i) zs->zs_codetab[i] |
|
|
#define tab_prefixof(i) codetabof(i) |
#define tab_prefixof(i) codetabof(i) |
#define tab_suffixof(i) ((char_type *)(htab))[i] |
#define tab_suffixof(i) ((u_char *)(zs->zs_htab))[i] |
#define de_stack ((char_type *)&tab_suffixof(1 << BITS)) |
#define de_stack ((u_char *)&tab_suffixof(1 << BITS)) |
|
|
#define CHECK_GAP 10000 /* Ratio check interval. */ |
#define CHECK_GAP 10000 /* Ratio check interval. */ |
|
|
|
|
#define FIRST 257 /* First free entry. */ |
#define FIRST 257 /* First free entry. */ |
#define CLEAR 256 /* Table clear output code. */ |
#define CLEAR 256 /* Table clear output code. */ |
|
|
static int cl_block __P((struct s_zstate *)); |
static int cl_block __P((register struct s_zstate *)); |
static void cl_hash __P((struct s_zstate *, count_int)); |
static void cl_hash __P((register struct s_zstate *, register count_int)); |
static code_int getcode __P((struct s_zstate *)); |
static code_int getcode __P((register struct s_zstate *)); |
static int output __P((struct s_zstate *, code_int)); |
static int output __P((register struct s_zstate *, code_int)); |
static int zclose __P((void *)); |
|
static int zread __P((void *, char *, int)); |
|
static int zwrite __P((void *, const char *, int)); |
|
|
|
/*- |
/*- |
* Algorithm from "A Technique for High Performance Data Compression", |
* Algorithm from "A Technique for High Performance Data Compression", |
|
|
* file size for noticeable speed improvement on small files. Please direct |
* file size for noticeable speed improvement on small files. Please direct |
* questions about this implementation to ames!jaw. |
* questions about this implementation to ames!jaw. |
*/ |
*/ |
static int |
int |
zwrite(cookie, wbp, num) |
zwrite(cookie, wbp, num) |
void *cookie; |
void *cookie; |
const char *wbp; |
const char *wbp; |
|
|
zs = cookie; |
zs = cookie; |
count = num; |
count = num; |
bp = (u_char *)wbp; |
bp = (u_char *)wbp; |
if (state == S_MIDDLE) |
if (zs->zs_state == S_MIDDLE) |
goto middle; |
goto middle; |
state = S_MIDDLE; |
zs->zs_state = S_MIDDLE; |
|
|
maxmaxcode = 1L << maxbits; |
zs->zs_maxmaxcode = 1L << zs->zs_maxbits; |
if (fwrite(magic_header, |
if (write(zs->zs_fd, z_magic, sizeof(z_magic)) != sizeof(z_magic)) |
sizeof(char), sizeof(magic_header), fp) != sizeof(magic_header)) |
|
return (-1); |
return (-1); |
tmp = (u_char)(maxbits | block_compress); |
tmp = (u_char)(zs->zs_maxbits | zs->zs_block_compress); |
if (fwrite(&tmp, sizeof(char), sizeof(tmp), fp) != sizeof(tmp)) |
if (write(zs->zs_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) |
return (-1); |
return (-1); |
|
|
offset = 0; |
zs->zs_offset = 0; |
bytes_out = 3; /* Includes 3-byte header mojo. */ |
zs->zs_bytes_out = 3; /* Includes 3-byte header mojo. */ |
out_count = 0; |
zs->zs_out_count = 0; |
clear_flg = 0; |
zs->zs_clear_flg = 0; |
ratio = 0; |
zs->zs_ratio = 0; |
in_count = 1; |
zs->zs_in_count = 1; |
checkpoint = CHECK_GAP; |
zs->zs_checkpoint = CHECK_GAP; |
maxcode = MAXCODE(n_bits = INIT_BITS); |
zs->zs_maxcode = MAXCODE(zs->zs_n_bits = INIT_BITS); |
free_ent = ((block_compress) ? FIRST : 256); |
zs->zs_free_ent = ((zs->zs_block_compress) ? FIRST : 256); |
|
|
ent = *bp++; |
zs->zs_ent = *bp++; |
--count; |
--count; |
|
|
hshift = 0; |
zs->zs_hshift = 0; |
for (fcode = (long)hsize; fcode < 65536L; fcode *= 2L) |
for (zs->zs_fcode = (long)zs->zs_hsize; zs->zs_fcode < 65536L; |
hshift++; |
zs->zs_fcode *= 2L) |
hshift = 8 - hshift; /* Set hash code range bound. */ |
zs->zs_hshift++; |
|
zs->zs_hshift = 8 - zs->zs_hshift; /* Set hash code range bound. */ |
|
|
hsize_reg = hsize; |
zs->zs_hsize_reg = zs->zs_hsize; |
cl_hash(zs, (count_int)hsize_reg); /* Clear hash table. */ |
cl_hash(zs, (count_int)zs->zs_hsize_reg); /* Clear hash table. */ |
|
|
middle: for (i = 0; count--;) { |
middle: for (i = 0; count--;) { |
c = *bp++; |
c = *bp++; |
in_count++; |
zs->zs_in_count++; |
fcode = (long)(((long)c << maxbits) + ent); |
zs->zs_fcode = (long)(((long)c << zs->zs_maxbits) + |
i = ((c << hshift) ^ ent); /* Xor hashing. */ |
zs->zs_ent); |
|
i = ((c << zs->zs_hshift) ^ zs->zs_ent); /* Xor hashing. */ |
|
|
if (htabof(i) == fcode) { |
if (htabof(i) == zs->zs_fcode) { |
ent = codetabof(i); |
zs->zs_ent = codetabof(i); |
continue; |
continue; |
} else if ((long)htabof(i) < 0) /* Empty slot. */ |
} else if ((long)htabof(i) < 0) /* Empty slot. */ |
goto nomatch; |
goto nomatch; |
disp = hsize_reg - i; /* Secondary hash (after G. Knott). */ |
/* Secondary hash (after G. Knott). */ |
|
disp = zs->zs_hsize_reg - i; |
if (i == 0) |
if (i == 0) |
disp = 1; |
disp = 1; |
probe: if ((i -= disp) < 0) |
probe: if ((i -= disp) < 0) |
i += hsize_reg; |
i += zs->zs_hsize_reg; |
|
|
if (htabof(i) == fcode) { |
if (htabof(i) == zs->zs_fcode) { |
ent = codetabof(i); |
zs->zs_ent = codetabof(i); |
continue; |
continue; |
} |
} |
if ((long)htabof(i) >= 0) |
if ((long)htabof(i) >= 0) |
goto probe; |
goto probe; |
nomatch: if (output(zs, (code_int) ent) == -1) |
nomatch: if (output(zs, (code_int) zs->zs_ent) == -1) |
return (-1); |
return (-1); |
out_count++; |
zs->zs_out_count++; |
ent = c; |
zs->zs_ent = c; |
if (free_ent < maxmaxcode) { |
if (zs->zs_free_ent < zs->zs_maxmaxcode) { |
codetabof(i) = free_ent++; /* code -> hashtable */ |
/* code -> hashtable */ |
htabof(i) = fcode; |
codetabof(i) = zs->zs_free_ent++; |
} else if ((count_int)in_count >= |
htabof(i) = zs->zs_fcode; |
checkpoint && block_compress) { |
} else if ((count_int)zs->zs_in_count >= |
|
zs->zs_checkpoint && zs->zs_block_compress) { |
if (cl_block(zs) == -1) |
if (cl_block(zs) == -1) |
return (-1); |
return (-1); |
} |
} |
|
|
return (num); |
return (num); |
} |
} |
|
|
static int |
int |
zclose(cookie) |
zclose(cookie) |
void *cookie; |
void *cookie; |
{ |
{ |
|
|
int rval; |
int rval; |
|
|
zs = cookie; |
zs = cookie; |
if (zmode == 'w') { /* Put out the final code. */ |
if (zs->zs_mode == 'w') { /* Put out the final code. */ |
if (output(zs, (code_int) ent) == -1) { |
if (output(zs, (code_int) zs->zs_ent) == -1) { |
(void)fclose(fp); |
(void)close(zs->zs_fd); |
free(zs); |
free(zs); |
return (-1); |
return (-1); |
} |
} |
out_count++; |
zs->zs_out_count++; |
if (output(zs, (code_int) - 1) == -1) { |
if (output(zs, (code_int) - 1) == -1) { |
(void)fclose(fp); |
(void)close(zs->zs_fd); |
free(zs); |
free(zs); |
return (-1); |
return (-1); |
} |
} |
} |
} |
rval = fclose(fp) == EOF ? -1 : 0; |
rval = close(zs->zs_fd); |
free(zs); |
free(zs); |
return (rval); |
return (rval); |
} |
} |
|
|
* code in turn. When the buffer fills up empty it and start over. |
* code in turn. When the buffer fills up empty it and start over. |
*/ |
*/ |
|
|
static char_type lmask[9] = |
static u_char lmask[9] = |
{0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00}; |
{0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00}; |
static char_type rmask[9] = |
static u_char rmask[9] = |
{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; |
{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; |
|
|
static int |
static int |
output(zs, ocode) |
output(zs, ocode) |
struct s_zstate *zs; |
register struct s_zstate *zs; |
code_int ocode; |
code_int ocode; |
{ |
{ |
register int bits, r_off; |
register int bits, r_off; |
register char_type *bp; |
register u_char *bp; |
|
|
r_off = offset; |
r_off = zs->zs_offset; |
bits = n_bits; |
bits = zs->zs_n_bits; |
bp = buf; |
bp = zs->zs_buf; |
if (ocode >= 0) { |
if (ocode >= 0) { |
/* Get to the first byte. */ |
/* Get to the first byte. */ |
bp += (r_off >> 3); |
bp += (r_off >> 3); |
|
|
bp++; |
bp++; |
bits -= (8 - r_off); |
bits -= (8 - r_off); |
ocode >>= 8 - r_off; |
ocode >>= 8 - r_off; |
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ |
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits) */ |
if (bits >= 8) { |
if (bits >= 8) { |
*bp++ = ocode; |
*bp++ = ocode; |
ocode >>= 8; |
ocode >>= 8; |
|
|
/* Last bits. */ |
/* Last bits. */ |
if (bits) |
if (bits) |
*bp = ocode; |
*bp = ocode; |
offset += n_bits; |
zs->zs_offset += zs->zs_n_bits; |
if (offset == (n_bits << 3)) { |
if (zs->zs_offset == (zs->zs_n_bits << 3)) { |
bp = buf; |
bp = zs->zs_buf; |
bits = n_bits; |
bits = zs->zs_n_bits; |
bytes_out += bits; |
zs->zs_bytes_out += bits; |
if (fwrite(bp, sizeof(char), bits, fp) != bits) |
if (write(zs->zs_fd, bp, bits) != bits) |
return (-1); |
return (-1); |
bp += bits; |
bp += bits; |
bits = 0; |
bits = 0; |
offset = 0; |
zs->zs_offset = 0; |
} |
} |
/* |
/* |
* If the next entry is going to be too big for the ocode size, |
* If the next entry is going to be too big for the ocode size, |
* then increase it, if possible. |
* then increase it, if possible. |
*/ |
*/ |
if (free_ent > maxcode || (clear_flg > 0)) { |
if (zs->zs_free_ent > zs->zs_maxcode || |
|
(zs->zs_clear_flg > 0)) { |
/* |
/* |
* Write the whole buffer, because the input side won't |
* Write the whole buffer, because the input side won't |
* discover the size increase until after it has read it. |
* discover the size increase until after it has read it |
*/ |
*/ |
if (offset > 0) { |
if (zs->zs_offset > 0) { |
if (fwrite(buf, 1, n_bits, fp) != n_bits) |
if (write(zs->zs_fd, zs->zs_buf, zs->zs_n_bits) |
|
!= zs->zs_n_bits) |
return (-1); |
return (-1); |
bytes_out += n_bits; |
zs->zs_bytes_out += zs->zs_n_bits; |
} |
} |
offset = 0; |
zs->zs_offset = 0; |
|
|
if (clear_flg) { |
if (zs->zs_clear_flg) { |
maxcode = MAXCODE(n_bits = INIT_BITS); |
zs->zs_maxcode = |
clear_flg = 0; |
MAXCODE(zs->zs_n_bits = INIT_BITS); |
|
zs->zs_clear_flg = 0; |
} else { |
} else { |
n_bits++; |
zs->zs_n_bits++; |
if (n_bits == maxbits) |
if (zs->zs_n_bits == zs->zs_maxbits) |
maxcode = maxmaxcode; |
zs->zs_maxcode = zs->zs_maxmaxcode; |
else |
else |
maxcode = MAXCODE(n_bits); |
zs->zs_maxcode = |
|
MAXCODE(zs->zs_n_bits); |
} |
} |
} |
} |
} else { |
} else { |
/* At EOF, write the rest of the buffer. */ |
/* At EOF, write the rest of the buffer. */ |
if (offset > 0) { |
if (zs->zs_offset > 0) { |
offset = (offset + 7) / 8; |
zs->zs_offset = (zs->zs_offset + 7) / 8; |
if (fwrite(buf, 1, offset, fp) != offset) |
if (write(zs->zs_fd, zs->zs_buf, zs->zs_offset) |
|
!= zs->zs_offset) |
return (-1); |
return (-1); |
bytes_out += offset; |
zs->zs_bytes_out += zs->zs_offset; |
} |
} |
offset = 0; |
zs->zs_offset = 0; |
} |
} |
return (0); |
return (0); |
} |
} |
|
|
* compressed file. The tables used herein are shared with those of the |
* compressed file. The tables used herein are shared with those of the |
* compress() routine. See the definitions above. |
* compress() routine. See the definitions above. |
*/ |
*/ |
static int |
int |
zread(cookie, rbp, num) |
zread(cookie, rbp, num) |
void *cookie; |
void *cookie; |
char *rbp; |
char *rbp; |
|
|
zs = cookie; |
zs = cookie; |
count = num; |
count = num; |
bp = (u_char *)rbp; |
bp = (u_char *)rbp; |
switch (state) { |
switch (zs->zs_state) { |
case S_START: |
case S_START: |
state = S_MIDDLE; |
zs->zs_state = S_MIDDLE; |
break; |
break; |
case S_MIDDLE: |
case S_MIDDLE: |
goto middle; |
goto middle; |
|
|
} |
} |
|
|
/* Check the magic number */ |
/* Check the magic number */ |
if (fread(header, |
if (read(zs->zs_fd, header, sizeof(header)) != sizeof(header) || |
sizeof(char), sizeof(header), fp) != sizeof(header) || |
memcmp(header, z_magic, sizeof(z_magic)) != 0) { |
memcmp(header, magic_header, sizeof(magic_header)) != 0) { |
|
errno = EFTYPE; |
errno = EFTYPE; |
return (-1); |
return (-1); |
} |
} |
maxbits = header[2]; /* Set -b from file. */ |
zs->zs_maxbits = header[2]; /* Set -b from file. */ |
block_compress = maxbits & BLOCK_MASK; |
zs->zs_block_compress = zs->zs_maxbits & BLOCK_MASK; |
maxbits &= BIT_MASK; |
zs->zs_maxbits &= BIT_MASK; |
maxmaxcode = 1L << maxbits; |
zs->zs_maxmaxcode = 1L << zs->zs_maxbits; |
if (maxbits > BITS) { |
if (zs->zs_maxbits > BITS) { |
errno = EFTYPE; |
errno = EFTYPE; |
return (-1); |
return (-1); |
} |
} |
/* As above, initialize the first 256 entries in the table. */ |
/* As above, initialize the first 256 entries in the table. */ |
maxcode = MAXCODE(n_bits = INIT_BITS); |
zs->zs_maxcode = MAXCODE(zs->zs_n_bits = INIT_BITS); |
for (code = 255; code >= 0; code--) { |
for (zs->zs_code = 255; zs->zs_code >= 0; zs->zs_code--) { |
tab_prefixof(code) = 0; |
tab_prefixof(zs->zs_code) = 0; |
tab_suffixof(code) = (char_type) code; |
tab_suffixof(zs->zs_code) = (u_char) zs->zs_code; |
} |
} |
free_ent = block_compress ? FIRST : 256; |
zs->zs_free_ent = zs->zs_block_compress ? FIRST : 256; |
|
|
finchar = oldcode = getcode(zs); |
zs->zs_finchar = zs->zs_oldcode = getcode(zs); |
if (oldcode == -1) /* EOF already? */ |
if (zs->zs_oldcode == -1) /* EOF already? */ |
return (0); /* Get out of here */ |
return (0); /* Get out of here */ |
|
|
/* First code must be 8 bits = char. */ |
/* First code must be 8 bits = char. */ |
*bp++ = (u_char)finchar; |
*bp++ = (u_char)zs->zs_finchar; |
count--; |
count--; |
stackp = de_stack; |
zs->zs_stackp = de_stack; |
|
|
while ((code = getcode(zs)) > -1) { |
while ((zs->zs_code = getcode(zs)) > -1) { |
|
|
if ((code == CLEAR) && block_compress) { |
if ((zs->zs_code == CLEAR) && zs->zs_block_compress) { |
for (code = 255; code >= 0; code--) |
for (zs->zs_code = 255; zs->zs_code >= 0; |
tab_prefixof(code) = 0; |
zs->zs_code--) |
clear_flg = 1; |
tab_prefixof(zs->zs_code) = 0; |
free_ent = FIRST - 1; |
zs->zs_clear_flg = 1; |
if ((code = getcode(zs)) == -1) /* O, untimely death! */ |
zs->zs_free_ent = FIRST - 1; |
|
if ((zs->zs_code = getcode(zs)) == -1) /* O, untimely death! */ |
break; |
break; |
} |
} |
incode = code; |
zs->zs_incode = zs->zs_code; |
|
|
/* Special case for KwKwK string. */ |
/* Special case for KwKwK string. */ |
if (code >= free_ent) { |
if (zs->zs_code >= zs->zs_free_ent) { |
*stackp++ = finchar; |
*zs->zs_stackp++ = zs->zs_finchar; |
code = oldcode; |
zs->zs_code = zs->zs_oldcode; |
} |
} |
|
|
/* Generate output characters in reverse order. */ |
/* Generate output characters in reverse order. */ |
while (code >= 256) { |
while (zs->zs_code >= 256) { |
*stackp++ = tab_suffixof(code); |
*zs->zs_stackp++ = tab_suffixof(zs->zs_code); |
code = tab_prefixof(code); |
zs->zs_code = tab_prefixof(zs->zs_code); |
} |
} |
*stackp++ = finchar = tab_suffixof(code); |
*zs->zs_stackp++ = zs->zs_finchar = tab_suffixof(zs->zs_code); |
|
|
/* And put them out in forward order. */ |
/* And put them out in forward order. */ |
middle: do { |
middle: do { |
if (count-- == 0) |
if (count-- == 0) |
return (num); |
return (num); |
*bp++ = *--stackp; |
*bp++ = *--zs->zs_stackp; |
} while (stackp > de_stack); |
} while (zs->zs_stackp > de_stack); |
|
|
/* Generate the new entry. */ |
/* Generate the new entry. */ |
if ((code = free_ent) < maxmaxcode) { |
if ((zs->zs_code = zs->zs_free_ent) < zs->zs_maxmaxcode) { |
tab_prefixof(code) = (u_short) oldcode; |
tab_prefixof(zs->zs_code) = (u_short) zs->zs_oldcode; |
tab_suffixof(code) = finchar; |
tab_suffixof(zs->zs_code) = zs->zs_finchar; |
free_ent = code + 1; |
zs->zs_free_ent = zs->zs_code + 1; |
} |
} |
|
|
/* Remember previous code. */ |
/* Remember previous code. */ |
oldcode = incode; |
zs->zs_oldcode = zs->zs_incode; |
} |
} |
state = S_EOF; |
zs->zs_state = S_EOF; |
eof: return (num - count); |
eof: return (num - count); |
} |
} |
|
|
|
|
*/ |
*/ |
static code_int |
static code_int |
getcode(zs) |
getcode(zs) |
struct s_zstate *zs; |
register struct s_zstate *zs; |
{ |
{ |
register code_int gcode; |
register code_int gcode; |
register int r_off, bits; |
register int r_off, bits; |
register char_type *bp; |
register u_char *bp; |
|
|
bp = gbuf; |
bp = zs->zs_buf; |
if (clear_flg > 0 || roffset >= size || free_ent > maxcode) { |
if (zs->zs_clear_flg > 0 || zs->zs_roffset >= zs->zs_size || |
|
zs->zs_free_ent > zs->zs_maxcode) { |
/* |
/* |
* If the next entry will be too big for the current gcode |
* If the next entry will be too big for the current gcode |
* size, then we must increase the size. This implies reading |
* size, then we must increase the size. This implies reading |
* a new buffer full, too. |
* a new buffer full, too. |
*/ |
*/ |
if (free_ent > maxcode) { |
if (zs->zs_free_ent > zs->zs_maxcode) { |
n_bits++; |
zs->zs_n_bits++; |
if (n_bits == maxbits) /* Won't get any bigger now. */ |
if (zs->zs_n_bits == zs->zs_maxbits) /* Won't get any bigger now. */ |
maxcode = maxmaxcode; |
zs->zs_maxcode = zs->zs_maxmaxcode; |
else |
else |
maxcode = MAXCODE(n_bits); |
zs->zs_maxcode = MAXCODE(zs->zs_n_bits); |
} |
} |
if (clear_flg > 0) { |
if (zs->zs_clear_flg > 0) { |
maxcode = MAXCODE(n_bits = INIT_BITS); |
zs->zs_maxcode = MAXCODE(zs->zs_n_bits = INIT_BITS); |
clear_flg = 0; |
zs->zs_clear_flg = 0; |
} |
} |
size = fread(gbuf, 1, n_bits, fp); |
zs->zs_size = read(zs->zs_fd, zs->zs_buf, zs->zs_n_bits); |
if (size <= 0) /* End of file. */ |
if (zs->zs_size <= 0) /* End of file. */ |
return (-1); |
return (-1); |
roffset = 0; |
zs->zs_roffset = 0; |
/* Round size down to integral number of codes. */ |
/* Round size down to integral number of codes. */ |
size = (size << 3) - (n_bits - 1); |
zs->zs_size = (zs->zs_size << 3) - (zs->zs_n_bits - 1); |
} |
} |
r_off = roffset; |
r_off = zs->zs_roffset; |
bits = n_bits; |
bits = zs->zs_n_bits; |
|
|
/* Get to the first byte. */ |
/* Get to the first byte. */ |
bp += (r_off >> 3); |
bp += (r_off >> 3); |
|
|
|
|
/* High order bits. */ |
/* High order bits. */ |
gcode |= (*bp & rmask[bits]) << r_off; |
gcode |= (*bp & rmask[bits]) << r_off; |
roffset += n_bits; |
zs->zs_roffset += zs->zs_n_bits; |
|
|
return (gcode); |
return (gcode); |
} |
} |
|
|
static int |
static int |
cl_block(zs) /* Table clear for block compress. */ |
cl_block(zs) /* Table clear for block compress. */ |
struct s_zstate *zs; |
register struct s_zstate *zs; |
{ |
{ |
register long rat; |
register long rat; |
|
|
checkpoint = in_count + CHECK_GAP; |
zs->zs_checkpoint = zs->zs_in_count + CHECK_GAP; |
|
|
if (in_count > 0x007fffff) { /* Shift will overflow. */ |
if (zs->zs_in_count > 0x007fffff) { /* Shift will overflow. */ |
rat = bytes_out >> 8; |
rat = zs->zs_bytes_out >> 8; |
if (rat == 0) /* Don't divide by zero. */ |
if (rat == 0) /* Don't divide by zero. */ |
rat = 0x7fffffff; |
rat = 0x7fffffff; |
else |
else |
rat = in_count / rat; |
rat = zs->zs_in_count / rat; |
} else |
} else |
rat = (in_count << 8) / bytes_out; /* 8 fractional bits. */ |
rat = (zs->zs_in_count << 8) / zs->zs_bytes_out; /* 8 fractional bits. */ |
if (rat > ratio) |
if (rat > zs->zs_ratio) |
ratio = rat; |
zs->zs_ratio = rat; |
else { |
else { |
ratio = 0; |
zs->zs_ratio = 0; |
cl_hash(zs, (count_int) hsize); |
cl_hash(zs, (count_int) zs->zs_hsize); |
free_ent = FIRST; |
zs->zs_free_ent = FIRST; |
clear_flg = 1; |
zs->zs_clear_flg = 1; |
if (output(zs, (code_int) CLEAR) == -1) |
if (output(zs, (code_int) CLEAR) == -1) |
return (-1); |
return (-1); |
} |
} |
|
|
|
|
static void |
static void |
cl_hash(zs, cl_hsize) /* Reset code table. */ |
cl_hash(zs, cl_hsize) /* Reset code table. */ |
struct s_zstate *zs; |
register struct s_zstate *zs; |
register count_int cl_hsize; |
register count_int cl_hsize; |
{ |
{ |
register count_int *htab_p; |
register count_int *htab_p; |
register long i, m1; |
register long i, m1; |
|
|
m1 = -1; |
m1 = -1; |
htab_p = htab + cl_hsize; |
htab_p = zs->zs_htab + cl_hsize; |
i = cl_hsize - 16; |
i = cl_hsize - 16; |
do { /* Might use Sys V memset(3) here. */ |
do { /* Might use Sys V memset(3) here. */ |
*(htab_p - 16) = m1; |
*(htab_p - 16) = m1; |
|
|
} |
} |
|
|
FILE * |
FILE * |
zdopen(fd, mode, bits) |
zopen(name, mode, bits) |
|
const char *name; |
|
const char *mode; |
|
int bits; |
|
{ |
int fd; |
int fd; |
|
void *cookie; |
|
if ((fd = open(name, (*mode=='r'? O_RDONLY:O_WRONLY|O_CREAT), |
|
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) |
|
return NULL; |
|
if ((cookie = z_open(fd, mode, bits)) == NULL) { |
|
close(fd); |
|
return NULL; |
|
} |
|
return funopen(cookie, (*mode == 'r'?zread:NULL), |
|
(*mode == 'w'?zwrite:NULL), NULL, zclose); |
|
} |
|
|
|
void * |
|
z_open(fd, mode, bits) |
|
int fd; |
const char *mode; |
const char *mode; |
int bits; |
int bits; |
{ |
{ |
struct s_zstate *zs; |
register struct s_zstate *zs; |
|
|
if ((mode[0] != 'r' && mode[0] != 'w') || mode[1] != '\0' || |
if ((mode[0] != 'r' && mode[0] != 'w') || mode[1] != '\0' || |
bits < 0 || bits > BITS) { |
bits < 0 || bits > BITS) { |
|
|
if ((zs = calloc(1, sizeof(struct s_zstate))) == NULL) |
if ((zs = calloc(1, sizeof(struct s_zstate))) == NULL) |
return (NULL); |
return (NULL); |
|
|
maxbits = bits ? bits : BITS; /* User settable max # bits/code. */ |
/* User settable max # bits/code. */ |
maxmaxcode = 1 << maxbits; /* Should NEVER generate this code. */ |
zs->zs_maxbits = bits ? bits : BITS; |
hsize = HSIZE; /* For dynamic table sizing. */ |
/* Should NEVER generate this code. */ |
free_ent = 0; /* First unused entry. */ |
zs->zs_maxmaxcode = 1 << zs->zs_maxbits; |
block_compress = BLOCK_MASK; |
zs->zs_hsize = HSIZE; /* For dynamic table sizing. */ |
clear_flg = 0; |
zs->zs_free_ent = 0; /* First unused entry. */ |
ratio = 0; |
zs->zs_block_compress = BLOCK_MASK; |
checkpoint = CHECK_GAP; |
zs->zs_clear_flg = 0; |
in_count = 1; /* Length of input. */ |
zs->zs_ratio = 0; |
out_count = 0; /* # of codes output (for debugging). */ |
zs->zs_checkpoint = CHECK_GAP; |
state = S_START; |
zs->zs_in_count = 1; /* Length of input. */ |
roffset = 0; |
zs->zs_out_count = 0; /* # of codes output (for debugging).*/ |
size = 0; |
zs->zs_state = S_START; |
|
zs->zs_roffset = 0; |
|
zs->zs_size = 0; |
|
zs->zs_mode = mode[0]; |
|
|
/* |
zs->zs_fd = fd; |
* Layering compress on top of stdio in order to provide buffering, |
return zs; |
* and ensure that reads and write work with the data specified. |
|
*/ |
|
if ((fp = fdopen(fd, mode)) == NULL) { |
|
free(zs); |
|
return (NULL); |
|
} |
|
switch (*mode) { |
|
case 'r': |
|
zmode = 'r'; |
|
return (funopen(zs, zread, NULL, NULL, zclose)); |
|
case 'w': |
|
zmode = 'w'; |
|
return (funopen(zs, NULL, zwrite, NULL, zclose)); |
|
} |
|
/* NOTREACHED */ |
|
} |
} |
|
|
FILE * |
int |
zopen(fname, mode, bits) |
z_check_header(fd, sb, ofn) |
const char *fname, *mode; |
int fd; |
int bits; |
struct stat *sb; |
|
const char *ofn; |
{ |
{ |
struct s_zstate *zs; |
int f; |
|
u_char buf[sizeof(z_magic)]; |
|
off_t off = lseek(fd, 0, SEEK_CUR); |
|
|
if ((mode[0] != 'r' && mode[0] != 'w') || mode[1] != '\0' || |
f = (read(fd, buf, sizeof(buf)) == sizeof(buf) && |
bits < 0 || bits > BITS) { |
!memcmp(buf, z_magic, sizeof(buf))); |
errno = EINVAL; |
|
return (NULL); |
|
} |
|
|
|
if ((zs = calloc(1, sizeof(struct s_zstate))) == NULL) |
lseek (fd, off, SEEK_SET); |
return (NULL); |
|
|
|
maxbits = bits ? bits : BITS; /* User settable max # bits/code. */ |
return f; |
maxmaxcode = 1 << maxbits; /* Should NEVER generate this code. */ |
|
hsize = HSIZE; /* For dynamic table sizing. */ |
|
free_ent = 0; /* First unused entry. */ |
|
block_compress = BLOCK_MASK; |
|
clear_flg = 0; |
|
ratio = 0; |
|
checkpoint = CHECK_GAP; |
|
in_count = 1; /* Length of input. */ |
|
out_count = 0; /* # of codes output (for debugging). */ |
|
state = S_START; |
|
roffset = 0; |
|
size = 0; |
|
|
|
/* |
|
* Layering compress on top of stdio in order to provide buffering, |
|
* and ensure that reads and write work with the data specified. |
|
*/ |
|
if ((fp = fopen(fname, mode)) == NULL) { |
|
free(zs); |
|
return (NULL); |
|
} |
|
switch (*mode) { |
|
case 'r': |
|
zmode = 'r'; |
|
return (funopen(zs, zread, NULL, NULL, zclose)); |
|
case 'w': |
|
zmode = 'w'; |
|
return (funopen(zs, NULL, zwrite, NULL, zclose)); |
|
} |
|
/* NOTREACHED */ |
|
} |
} |