home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FM Towns: Free Software Collection 3
/
FREEWARE.BIN
/
towns_os
/
look
/
source
/
lzw.c
< prev
next >
Wrap
Text File
|
1980-01-02
|
4KB
|
185 lines
/*----------------------------------------------------------------------*/
/* Copyright (c) 1987 */
/* by CompuServe Inc., Columbus, Ohio. All Rights Reserved */
/* 89.6.8 FM-TOWNS Model Convert By Ken */
/*----------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#define largest_code 4095
struct code_entry {
short prefix; /* prefix code */
char suffix; /* suffix character */
char stack;
};
static short code_size;
static short clear_code;
static short eof_code;
static short first_free;
static short bit_offset;
static short byte_offset, bits_left;
static short max_code;
static short free_code;
static short old_code;
static short input_code;
static short code;
static short suffix_char;
static short final_char;
static short bytes_unread;
static short min_code_size;
static unsigned char code_buffer[64];
static struct code_entry *code_table;
static char *dmy_buf=NULL;
static short dmy_size,dmy_ptr,dmy_read;
static short mask[12] =
{0x001, 0x003, 0x007, 0x00F,
0x01F, 0x03F, 0x07F, 0x0FF,
0x1FF, 0x3FF, 0x7FF, 0xFFF};
static void dmy_putc(short ch)
{
dmy_buf[dmy_ptr++] = ch;
dmy_ptr &= 4095;
dmy_size++;
}
static void init_table(short min_code_size)
{
code_size = min_code_size + 1;
clear_code = 1 << min_code_size;
eof_code = clear_code + 1;
first_free = clear_code + 2;
free_code = first_free;
max_code = 1 << code_size;
}
static long read_code(FILE *fp)
{
short bytes_to_move, i, ch;
long temp;
byte_offset = bit_offset >> 3;
bits_left = bit_offset & 7;
if (byte_offset >= 61) {
bytes_to_move = 64 - byte_offset;
for (i = 0; i < bytes_to_move; i++)
code_buffer[i] = code_buffer[byte_offset + i];
while (i < 64) {
if (bytes_unread == 0) {
if ( (bytes_unread = getc(fp)) == EOF )
return EOF;
if ( bytes_unread == 0 ) /* end of data */
break;
}
if ( (ch = getc(fp)) == EOF )
return EOF;
code_buffer[i++] = ch;
bytes_unread--;
}
bit_offset = bits_left;
byte_offset = 0;
}
bit_offset += code_size;
temp = (long) code_buffer[byte_offset]
| (long) code_buffer[byte_offset + 1] << 8
| (long) code_buffer[byte_offset + 2] << 16;
if (bits_left > 0)
temp >>= bits_left;
return temp & mask[code_size - 1];
}
static short Expand_init(FILE *fp)
{
if ( (code_table = (struct code_entry *)
malloc(sizeof(struct code_entry)*(largest_code + 1))) == NULL )
return EOF;
if ( (min_code_size = getc(fp)) < 0 )
return EOF;
else if ( min_code_size < 2 || min_code_size > 9 )
return EOF;
init_table(min_code_size);
bit_offset = 64*8; /* force "read_code" to start a new */
bytes_unread = 0; /* record */
return 0;
}
static short Expand_Data(FILE *fp)
{
short sp = 0;
if ( (code = read_code(fp)) == eof_code )
return EOF;
if ( code == clear_code ) {
init_table(min_code_size);
code = read_code(fp);
old_code = code;
suffix_char = code;
final_char = code;
dmy_putc(suffix_char);
return 0;
}
input_code = code;
if ( code >= free_code ) {
code = old_code;
code_table[sp++].stack = final_char;
}
while (code >= first_free) {
code_table[sp++].stack = code_table[code].suffix;
code = code_table[code].prefix;
}
final_char = code;
suffix_char = code;
code_table[sp++].stack = final_char;
while (sp > 0)
dmy_putc(code_table[--sp].stack);
code_table[free_code].suffix = suffix_char;
code_table[free_code].prefix = old_code;
free_code++;
old_code = input_code;
if ( free_code >= max_code && code_size < 12 ) {
code_size++;
max_code <<= 1;
}
return 0;
}
void dmy_close(void)
{
if ( dmy_buf != NULL ) { free(dmy_buf); dmy_buf = NULL; }
if ( code_table != NULL ) { free(code_table); code_table = NULL; }
}
int dmy_getc(FILE *fp)
{
int ch;
if ( dmy_buf == NULL ) {
if ( Expand_init(fp) != 0 )
goto ERROR;
if ( (dmy_buf = malloc(4096)) == NULL )
goto ERROR;
dmy_size = dmy_ptr = dmy_read = 0;
}
if ( dmy_size <= 0 && Expand_Data(fp) != 0 )
goto ERROR;
ch = (unsigned char)dmy_buf[dmy_read++];
dmy_read &= 4095;
dmy_size--;
return ch;
ERROR:
dmy_close();
return EOF;
}