home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FM Towns: Free Software Collection 3
/
FREEWARE.BIN
/
towns_os
/
whisper
/
source
/
lzss.c
< prev
next >
Wrap
Text File
|
1980-01-02
|
11KB
|
417 lines
/********************************************************
LZSS法による圧縮
88.8.15 Original 奥村晴彦(Turbo-C MS-DOS)
89.2.27 OS9/6809 MW-C Convert Nanno-NET Ken
89.2.27 Bug Fix ? Apend insnode(r,len) "len" by ken
90.1.27 Modefal By Ken
*********************************************************/
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define ERR (-1)
#define unlink remove
#define N 2048 /* バッファサイズ Max 4096 */
#define F 18 /* 先読みバッファサイズ Max 18 */
#define NIL N /* 木の末端 */
char *mak_work(char *file);
unsigned short int t_crc=0;
static unsigned int mask;
static char *bas,*ptr;
static char dmy_buf[18];
static int now,new,len;
static int status,adr;
static int pos,mat_len;
static char *md_ptr;
static char text_buf[N+F-1];
static int lson[N+1];
static int rson[N+257];
static int dad[N+1];
static unsigned short int crctbl[] = {
0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040 };
void calcrc(unsigned char ch)
{
t_crc = (t_crc >> 8 ^ crctbl[(t_crc ^ ch) & 0xff]);
}
void insnode(r,len)
int r,len;
{
int i,cmp;
unsigned char *key;
register int p;
cmp = 1;
key = (unsigned char *)&text_buf[r];
p = N + 1 + key[0];
rson[r] = lson[r] = NIL; mat_len = 0;
for ( ; ; ) {
if ( cmp >= 0 ) {
if ( rson[p] != NIL )
p = rson[p];
else {
rson[p] = r; dad[r] = p;
return;
}
} else {
if ( lson[p] != NIL )
p = lson[p];
else {
lson[p] = r; dad[r] = p;
return;
}
}
for ( i = 1 ; i < len ; i++ ) {
if ( (cmp = key[i] - (unsigned char)text_buf[p + i]) != 0 )
break;
}
if ( i > mat_len ) {
pos = p;
if ( (mat_len = i) >= len )
break;
}
}
dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p];
dad[lson[p]] = r; dad[rson[p]] = r;
if ( rson[dad[p]] == p )
rson[dad[p]] = r;
else
lson[dad[p]] = r;
dad[p] = NIL;
}
void delnode(p)
int p;
{
int q;
register int dad_p;
if ( (dad_p = dad[p]) == NIL )
return;
if ( rson[p] == NIL ) {
if ( rson[dad_p] == p )
rson[dad_p] = lson[p];
else
lson[dad_p] = lson[p];
dad[lson[p]] = dad_p;
} else if ( lson[p] == NIL ) {
if ( rson[dad_p] == p )
rson[dad_p] = rson[p];
else
lson[dad_p] = rson[p];
dad[rson[p]] = dad_p;
} else {
q = lson[p];
if ( rson[q] != NIL ) {
do {
q = rson[q];
} while ( rson[q] != NIL );
rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q];
lson[q] = lson[p]; dad[lson[p]] = q;
rson[q] = rson[p]; dad[rson[p]] = q;
} else {
rson[q] = rson[p]; dad[rson[p]] = q;
}
dad[q] = dad_p;
if ( rson[dad_p] == p )
rson[dad_p] = q;
else
lson[dad_p] = q;
}
dad[p] = NIL;
}
void Enc_init(fp)
FILE *fp;
{
int i,c;
for ( i = N + 1 ; i <= (N + 256) ; i++ )
rson[i] = NIL;
for ( i = 0 ; i < N ; i++ )
dad[i] = NIL;
for ( i = 0 ; i < (N - F) ; i++ )
text_buf[i] = ' ';
bas = dmy_buf;
ptr = dmy_buf + 1;
dmy_buf[0] = 0;
mask = 1;
now = N- F;
new = 0;
t_crc = 0;
for ( len = 0 ; len < F && (c = getc(fp)) != EOF ; len++ ) {
text_buf[now + len] = c;
calcrc(c);
}
for ( i = 1 ; i <= F ; i++ )
insnode(now - i,len);
insnode(now,len);
}
int Enc_char(fp)
FILE *fp;
{
int i,n,c;
for ( ; ; ) {
if ( mask >= 0x100 ) {
if ( bas < ptr )
return *(bas++) & 0xFF;
dmy_buf[0] = 0;
mask = 1;
bas = dmy_buf;
ptr = dmy_buf + 1;
}
if ( len <= 0 )
return EOF;
if ( mat_len <= 2 ) {
mat_len = 1;
dmy_buf[0] |= mask;
*(ptr++) = text_buf[now];
} else {
if ( mat_len > len ) mat_len = len;
*(ptr++) = pos;
*(ptr++) = (((pos >> 4) & 0xf0) | (mat_len -3));
}
n = mat_len;
for ( i = 0 ; i < n &&
(c = getc(fp)) != EOF ; i++ ) {
delnode(new);
text_buf[new] = c;
if ( new < (F - 1) )
text_buf[new + N] = c;
new = (new + 1) & (N - 1);
now = (now + 1) & (N - 1);
insnode(now,len);
calcrc(c);
}
while ( i++ < n ) {
delnode(new);
new = (new + 1) & (N - 1);
now = (now + 1) & (N - 1);
if ( --len > 0 )
insnode(now,len);
}
if ( len <= 0 )
mask = 0x100;
else
mask <<= 1;
}
}
#define D_Get_Mask 0
#define D_Get_Char 1
#define D_Get_HiAd 2
void Dec_init()
{
int i;
for ( i = 0 ; i < (N - F) ; i++ )
text_buf[i] = ' ';
now = N - F;
mask = 0;
status = D_Get_Char;
t_crc = 0;
}
void Dec_char(ch,fp)
unsigned int ch;
FILE *fp;
{
int n;
ch &= 0xFF;
switch(status) {
case D_Get_Char:
if ( (mask & 0x100) == 0 ) {
mask = 0xFF00 | ch;
} else {
if ( mask & 1 ) {
putc(ch,fp);
text_buf[now++] = ch;
now &= (N - 1);
calcrc(ch);
} else {
adr = ch;
status = D_Get_HiAd;
}
mask >>= 1;
}
break;
case D_Get_HiAd:
adr |= ((ch & 0xf0) << 4);
n = (ch & 0x0f) + 3;
while ( n-- > 0 ) {
ch = text_buf[adr++];
adr &= (N - 1);
putc(ch,fp);
text_buf[now++] = ch;
now &= (N - 1);
calcrc(ch);
}
status = D_Get_Char;
break;
}
}
void MDec_char(int ch)
{
int n;
ch &= 0xFF;
switch(status) {
case D_Get_Char:
if ( (mask & 0x100) == 0 ) {
mask = 0xFF00 | ch;
} else {
if ( mask & 1 ) {
*(md_ptr++) = ch;
text_buf[now++] = ch;
now &= (N - 1);
} else {
adr = ch;
status = D_Get_HiAd;
}
mask >>= 1;
}
break;
case D_Get_HiAd:
adr |= ((ch & 0xf0) << 4);
n = (ch & 0x0f) + 3;
while ( n-- > 0 ) {
ch = text_buf[adr++];
adr &= (N - 1);
*(md_ptr++) = ch;
text_buf[now++] = ch;
now &= (N - 1);
}
status = D_Get_Char;
break;
}
}
char *MEM_lzss(FILE *fp)
{
int n,ch;
char *p;
char tmp[8];
fread(tmp,1,5,fp);
if ( strncmp(tmp,"LZSS\x1A",5) != 0 ) {
rewind(fp);
return NULL;
}
for ( n = 0 ; n < (N - F) ; n++ )
text_buf[n] = ' ';
now = N - F;
mask = 0;
status = D_Get_Char;
fread(&n,sizeof(int),1,fp);
if ( (p = md_ptr = malloc(n)) == NULL )
return NULL;
while ( (ch = getc(fp)) != EOF && md_ptr < (p + n) )
MDec_char(ch);
return p;
}
int COMP_lzss(char *file)
{
FILE *ifp,*ofp;
int ch,fg,sw=FALSE;
long fsz;
char *work;
char tmp[8];
if ( (ifp = fopen(file,"rb")) == NULL )
return ERR;
work = mak_work(file);
if ( (ofp = fopen(work,"wb")) == NULL ) {
fclose(ifp);
return ERR;
}
fread(tmp,1,5,ifp);
if ( strncmp(tmp,"LZSS\x1A",5) != 0 )
sw = TRUE;
if ( sw == FALSE ) {
fseek(ifp,0L,SEEK_END);
fsz = ftell(ifp);
rewind(ifp);
fwrite("LZSS\x1A",1,5,ofp);
fwrite(&fsz,sizeof(long),1,ofp);
Enc_init(ifp);
while ( (ch = Enc_char(ifp)) != EOF )
putc(ch,ofp);
} else {
fread(&fsz,sizeof(long),1,ifp);
Dec_init();
while ( (ch = getc(ifp)) != EOF )
Dec_char(ch,ofp);
}
fg = (ferror(ifp) || ferror(ofp)) ? ERR:FALSE;
fclose(ifp);
fclose(ofp);
if ( fg != FALSE )
unlink(work);
else {
unlink(file);
rename(work,file);
}
return fg;
}