compress.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 996 行 · 第 1/3 页
C
996 行
if( offset > 0 ) {
if( fwrite( buf, 1, n_bits, stdout ) != n_bits )
writeerr();
bytes_out += n_bits;
}
offset = 0;
if( clear_flg ) {
maxcode = MAXCODE (n_bits = INIT_BITS);
clear_flg = 0;
}
else {
n_bits++;
if ( n_bits == maxbits )
maxcode = maxmaxcode;
else
maxcode = MAXCODE(n_bits);
}
}
} else {
/* At EOF, write the rest of the buffer */
if( offset > 0 )
fwrite( buf, 1, (offset + 7) / 8, stdout );
bytes_out += (offset + 7) / 8;
offset = 0;
fflush( stdout );
if( ferror( stdout ) )
writeerr();
}
}
static void cl_hash( count_int hsize ) /* reset code table */
/************************************/
{
memset( htab, -1, hsize * sizeof( count_int ) );
}
static void cl_block( void ) /* table clear for block compress */
/**************************/
{
long int rat;
checkpoint = in_count + CHECK_GAP;
if( in_count > 0x007fffff ) { /* shift will overflow */
rat = bytes_out >> 8;
if( rat == 0 ) { /* Don't divide by zero */
rat = 0x7fffffff;
} else {
rat = in_count / rat;
}
} else {
rat = (in_count << 8) / bytes_out; /* 8 fractional bits */
}
if( rat > ratio ) {
ratio = rat;
} else {
ratio = 0;
cl_hash( (count_int)hsize );
free_ent = FIRST;
clear_flg = 1;
output( (code_int)CLEAR );
}
}
/*
* compress stdin to stdout
*
* 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 do block compression with
* an adaptive reset, whereby the code table is cleared when the compression
* ratio decreases, but after the table fills. The variable-length output
* codes are re-sized at this point, and a special CLEAR code is generated
* for the decompressor. Late addition: construct the table according to
* file size for noticeable speed improvement on small files.
*/
static void compress( void )
/**************************/
{
long fcode;
code_int i = 0;
int c;
code_int ent;
int disp;
code_int hsize_reg;
int hshift;
if( nomagic == 0 ) {
putchar( magic_header[0] );
putchar( magic_header[1] );
putchar( (char)(maxbits | block_compress) );
if( ferror( stdout ) )
writeerr();
}
offset = 0;
bytes_out = 3; /* includes 3-byte header mojo */
out_count = 0;
clear_flg = 0;
ratio = 0;
in_count = 1;
checkpoint = CHECK_GAP;
maxcode = MAXCODE(n_bits = INIT_BITS);
free_ent = ((block_compress) ? FIRST : 256 );
ent = getchar();
hshift = 0;
for( fcode = (long)hsize; fcode < 65536L; fcode *= 2L )
hshift++;
hshift = 8 - hshift; /* set hash code range bound */
hsize_reg = hsize;
cl_hash( (count_int) hsize_reg); /* clear hash table */
while( (c = getchar()) != EOF ) {
in_count++;
fcode = ((long)c << maxbits) + ent;
i = (c << hshift) ^ ent; /* xor hashing */
if( htabof (i) == fcode ) {
ent = codetabof (i);
continue;
} else if( (long)htabof (i) < 0 ) /* empty slot */
goto nomatch;
disp = hsize_reg - i; /* secondary hash (after G. Knott) */
if( i == 0 )
disp = 1;
probe:
if( (i -= disp) < 0 )
i += hsize_reg;
if( htabof (i) == fcode ) {
ent = codetabof (i);
continue;
}
if( (long)htabof (i) > 0 )
goto probe;
nomatch:
output ( (code_int) ent );
out_count++;
ent = c;
if( free_ent < maxmaxcode ) {
codetabof( i ) = free_ent++; /* code -> hashtable */
htabof( i ) = fcode;
} else if( (count_int)in_count >= checkpoint && block_compress )
cl_block ();
}
/* Output the final code */
output( (code_int)ent );
out_count++;
output( (code_int)-1 );
/* Print out stats on stderr */
if( zcat_flg == 0 && !quiet ) {
fprintf( stderr, "Compression: " );
print_ratio( stderr, in_count-bytes_out, in_count );
}
if( bytes_out > in_count ) /* exit(2) if no savings */
exit_stat = 2;
}
/*****************************************************************
* Read one code from the standard input. If EOF, return -1.
* Inputs:
* stdin
* Outputs:
* code or -1 is returned.
*/
static code_int getcode( void )
/*****************************/
{
code_int code;
static int offset = 0, size = 0;
static char_type buf[BITS];
int r_off, bits;
char_type *bp = buf;
if( clear_flg > 0 || offset >= size || free_ent > 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( free_ent > maxcode ) {
n_bits++;
if( n_bits == maxbits )
maxcode = maxmaxcode; /* won't get any bigger now */
else
maxcode = MAXCODE(n_bits);
}
if( clear_flg > 0) {
maxcode = MAXCODE(n_bits = INIT_BITS);
clear_flg = 0;
}
size = fread( buf, 1, n_bits, stdin );
if( size <= 0 )
return -1; /* end of file */
offset = 0;
/* Round size down to integral number of codes */
size = (size << 3) - (n_bits - 1);
}
r_off = offset;
bits = 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++ & 0xff) << r_off;
r_off += 8;
bits -= 8;
}
/* high order bits. */
code |= (*bp & rmask[bits]) << r_off;
offset += n_bits;
return( code );
}
/*
* Decompress stdin to stdout. 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. See the definitions above.
*/
static void decompress( void )
/****************************/
{
char_type *stackp;
int finchar;
code_int code, oldcode, incode;
/* As above, initialize the first 256 entries in the table. */
maxcode = MAXCODE(n_bits = INIT_BITS);
for( code = 255; code >= 0; code-- ) {
tab_prefixof(code) = 0;
tab_suffixof(code) = (char_type)code;
}
free_ent = ((block_compress) ? FIRST : 256 );
finchar = oldcode = getcode();
if( oldcode == -1 ) /* EOF already? */
return; /* Get out of here */
putchar( (char)finchar ); /* first code must be 8 bits = char */
if( ferror( stdout ) ) /* Crash if can't write */
writeerr();
stackp = de_stack;
while( (code = getcode()) > -1 ) {
if( (code == CLEAR) && block_compress ) {
for ( code = 255; code >= 0; code-- )
tab_prefixof(code) = 0;
clear_flg = 1;
free_ent = FIRST - 1;
if( (code = getcode()) == -1 ) /* O, untimely death! */
break;
}
incode = code;
/* Special case for KwKwK string */
if ( code >= free_ent ) {
*stackp++ = finchar;
code = oldcode;
}
/* Generate output characters in reverse order */
while( code >= 256 ) {
*stackp++ = tab_suffixof(code);
code = tab_prefixof(code);
}
*stackp++ = finchar = tab_suffixof(code);
/* And put them out in forward order */
do {
putchar ( *--stackp );
} while( stackp > de_stack );
/* Generate the new entry */
if ( (code=free_ent) < maxmaxcode ) {
tab_prefixof(code) = (unsigned short)oldcode;
tab_suffixof(code) = finchar;
free_ent = code + 1;
}
/* Remember previous code */
oldcode = incode;
}
fflush( stdout );
if( ferror( stdout ) )
writeerr();
}
static void copystat( char *ifname, char *ofname )
/************************************************/
{
int mode;
struct utimbuf times;
fclose( stdin );
fclose( stdout );
if( exit_stat == 2 && (!force) ) { /* No compression: remove file.Z */
if( !quiet )
fprintf( stderr, "No compression -- %s unchanged", ifname );
} else { /* ***** Successful Compression ***** */
exit_stat = 0;
mode = insbuf.st_mode & 07777;
if( chmod( ofname, mode ) ) /* Copy modes */
perror( ofname );
#ifdef __UNIX__
chown( ofname, insbuf.st_uid, insbuf.st_gid ); /* Copy ownership */
#endif
times.actime = insbuf.st_atime;
times.modtime = insbuf.st_mtime;
utime( ofname, × ); /* Update last accessed and modified times */
valid = 0; /* prevent latent ofname removal */
if( unlink( ifname ) ) /* Remove input file */
perror( ifname );
if( !quiet )
fprintf( stderr, " -- replaced with %s", ofname );
return; /* Successful return */
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?