home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 1997 December
/
VPR9712A.ISO
/
OLS
/
OS2
/
LHA2P205
/
LHA2P205.LZH
/
lha2-2.05pre
/
source.lzh
/
src
/
slide.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-10-13
|
10KB
|
520 lines
/*
* slide.c --- sliding dictionary with percolating update
* Copyright (C) 1988-1992, Haruyasu YOSHIZAKI
*
* $Log$
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include "typedef.h"
#include "port2.h"
#include "lh.h"
#include "header.h"
#include "slidehuf.h"
#include "intrface.h"
#include "errmes.h"
#define PERCOLATE 1
#define NIL 0
#define HASH(p, c) ((p) + ((c) << hash1) + hash2)
node *next = NULL;
int unpackable;
ulong origsize, compsize;
ushort dicbit;
ushort maxmatch;
ulong count;
uchar *use_ptr;
ushort loc;
uchar text[TEXT_SIZE];
static struct encode_option encode_define[2] =
{
/* lh1 */
{output_dyn, encode_start_fix, encode_end_dyn},
/* lh4, 5 */
{output_st1, encode_start_st1, encode_end_st1}
};
static struct decode_option decode_define[7] =
{
/* lh1 */
{decode_c_dyn, decode_p_st0, decode_start_fix},
/* lh2 */
{decode_c_dyn, decode_p_dyn, decode_start_dyn},
/* lh3 */
{decode_c_st0, decode_p_st0, decode_start_st0},
/* lh4 */
{decode_c_st1, decode_p_st1, decode_start_st1},
/* lh5 */
{decode_c_st1, decode_p_st1, decode_start_st1},
/* lzs */
{decode_c_lzs, decode_p_lzs, decode_start_lzs},
/* lz5 */
{decode_c_lz5, decode_p_lz5, decode_start_lz5}
};
static struct encode_option encode_set;
static struct decode_option decode_set;
static node pos, matchpos, avail, *position, *parent, *prev;
static int remainder, matchlen;
static uchar *level, *childcount;
static ushort dicsiz, max_hash_val, hash1, hash2;
int
encode_alloc(int method)
{
if(method == 1)
{
encode_set = encode_define[0];
maxmatch = 60;
dicbit = 12;
}
else
{
encode_set = encode_define[1];
maxmatch = MAXMATCH;
dicbit = method + 8;
}
while(1)
{
dicsiz = 1U << dicbit;
max_hash_val = 3 * dicsiz + (dicsiz / 512 + 1) * UCHAR_MAX;
level = malloc((dicsiz + UCHAR_MAX + 1) * sizeof(*level));
childcount = malloc((dicsiz + UCHAR_MAX + 1) * sizeof(*childcount));
#if PERCOLATE
position = (node *)malloc((dicsiz + UCHAR_MAX + 1) * sizeof(*position));
#else
position = (node *)malloc(dicsiz * sizeof(*position));
#endif
parent = (node *)malloc(dicsiz * 2 * sizeof(*parent));
prev = (node *)malloc(dicsiz * 2 * sizeof(*prev));
next = (node *)malloc((max_hash_val + 1) * sizeof(*next));
if(next == NULL || method > 1 && alloc_buf() == NULL)
{
if(next)
free(next);
if(prev)
free(prev);
if(parent)
free(parent);
if(position)
free(position);
if(childcount)
free(childcount);
if(level)
free(level);
}
else
break;
if(--dicbit < 12 )
error(MEMOVRERR, NULL);
}
memset(level, 0, (dicsiz + UCHAR_MAX + 1) * sizeof(*level));
memset(childcount , 0, (dicsiz + UCHAR_MAX + 1) * sizeof(*childcount));
#if PERCOLATE
memset(position, 0, (dicsiz + UCHAR_MAX + 1) * sizeof(*position));
#else
memset(position, 0, dicsiz * sizeof(*position));
#endif
memset(parent, 0, dicsiz * 2 * sizeof(*parent));
memset(prev, 0, dicsiz * 2 * sizeof(*prev));
memset(next, 0, (max_hash_val + 1) * sizeof(*next));
if(method == 5)
method = dicbit - 8;
return method;
}
static void
init_slide(void)
{
node i;
for(i = dicsiz; i <= dicsiz + UCHAR_MAX; i++)
{
level[i] = 1;
#if PERCOLATE
position[i] = NIL; /* sentinel */
#endif
}
for(i = dicsiz; i < dicsiz * 2; i++)
parent[i] = NIL;
avail = 1;
for(i = 1; i < dicsiz - 1; i++)
next[i] = i + 1;
next[dicsiz - 1] = NIL;
for(i = dicsiz * 2; i <= max_hash_val; i++)
next[i] = NIL;
hash1 = dicbit - 9;
hash2 = dicsiz * 2;
}
static node
child(node q, uchar c)
/* q's child for character c (NIL if not found) */
{
node r;
r = next[HASH(q, c)];
parent[NIL] = q; /* sentinel */
while(parent[r] != q)
r = next[r];
return r;
}
static void
makechild(node q, uchar c, node r)
/* Let r be q's child for character c. */
{
node h, t;
h = HASH(q, c);
t = next[h];
next[h] = r;
next[r] = t;
prev[t] = r;
prev[r] = h;
parent[r] = q;
childcount[q]++;
}
static void
split(node old)
{
node new, t;
new = avail;
avail = next[new];
childcount[new] = 0;
t = prev[old];
prev[new] = t;
next[t] = new;
t = next[old];
next[new] = t;
prev[t] = new;
parent[new] = parent[old];
level[new] = matchlen;
position[new] = pos;
makechild(new, text[matchpos + matchlen], old);
makechild(new, text[pos + matchlen], pos);
}
static void
insert_node(void)
{
node q, r, j, t;
uchar c, *t1, *t2;
if(matchlen >= 4)
{
matchlen--;
r = (uint)(matchpos + 1) | (uint)dicsiz;
while((q = parent[r]) == NIL)
r = next[r];
while(level[q] >= matchlen)
{
r = q;
q = parent[q];
}
#if PERCOLATE
t = q;
while(position[t] < 0)
{
position[t] = pos;
t = parent[t];
}
if(t < dicsiz)
position[t] = (uint)pos | 0x8000;
#else
t = q;
while(t < dicsiz)
{
position[t] = pos;
t = parent[t];
}
#endif
}
else
{
q = text[pos] + dicsiz;
c = text[pos + 1];
if((r = child(q, c)) == NIL)
{
makechild(q, c, pos);
matchlen = 1;
return;
}
matchlen = 2;
}
for(;;)
{
if(r >= dicsiz)
{
j = maxmatch;
matchpos = r;
}
else
{
j = level[r];
matchpos = (uint)position[r] & 0x7fff;
}
if(matchpos >= pos)
matchpos -= dicsiz;
t1 = &text[pos + matchlen];
t2 = &text[matchpos + matchlen];
while(matchlen < j)
{
if(*t1 != *t2)
{
split(r);
return;
}
matchlen++;
t1++;
t2++;
}
if(matchlen == maxmatch)
break;
position[r] = pos;
q = r;
if((r = child(q, *t1)) == NIL)
{
makechild(q, *t1, pos);
return;
}
matchlen++;
}
t = prev[r];
prev[pos] = t;
next[t] = pos;
t = next[r];
next[pos] = t;
prev[t] = pos;
parent[pos] = q;
parent[r] = NIL;
next[r] = pos; /* special use of next[] */
}
#ifdef __API16__
#pragma optimize("awgelzc", off)
#endif
static void
delete_node(void)
{
#if PERCOLATE
node q, r, s, t, u;
#else
node r, s, t, u;
#endif
if(parent[pos] == NIL)
return;
r = prev[pos];
s = next[pos];
next[r] = s;
prev[s] = r;
r = parent[pos];
parent[pos] = NIL;
if(r >= dicsiz || --childcount[r] > 1)
return;
#if PERCOLATE
t = (uint)position[r] & 0x7fff;
#else
t = position[r];
#endif
if(t >= pos)
t -= dicsiz;
#if PERCOLATE
s = t;
q = parent[r];
while((u = position[q]) < 0)
{
u = (uint)u & 0x7fff;
if(u >= pos)
u -= dicsiz;
if(u > s)
s = u;
position[q] = ((uint)s | (uint)dicsiz);
q = parent[q];
}
if(q < dicsiz)
{
if(u >= pos)
u -= dicsiz;
if(u > s)
s = u;
position[q] = ((uint)s | (uint)dicsiz) | 0x8000;
}
#endif
s = child(r, text[t + level[r]]);
t = prev[s];
u = next[s];
next[t] = u;
prev[u] = t;
t = prev[r];
next[t] = s;
prev[s] = t;
t = next[r];
prev[t] = s;
next[s] = t;
parent[s] = parent[r];
parent[r] = NIL;
next[r] = avail;
avail = r;
}
#ifdef __API16__
#pragma optimize("awgelzc", on)
#endif
void
get_next_match(hword *crc)
{
int n;
remainder--;
if(++pos == dicsiz * 2)
{
memmove(&text[0], &text[dicsiz], dicsiz + maxmatch);
n = fread_crc(&text[dicsiz + maxmatch], dicsiz, infile, crc);
remainder += n;
pos = dicsiz;
}
delete_node();
insert_node();
}
hword
encode(struct interfacing *interface)
{
int lastmatchlen, dicsiz1;
node lastmatchpos;
hword crc = 0;
infile = interface -> infile;
outfile = interface -> outfile;
origsize = interface -> original;
compsize = count = 0;
unpackable = 0;
init_slide();
encode_set.encode_start();
dicsiz1 = dicsiz - 1;
pos = dicsiz + maxmatch;
memset(&text[pos], ' ', dicsiz);
remainder = fread_crc(&text[pos], dicsiz, infile, &crc);
matchlen = 0;
insert_node();
if(matchlen > remainder)
matchlen = remainder;
while(remainder > 0 && ! unpackable)
{
lastmatchlen = matchlen;
lastmatchpos = matchpos;
get_next_match(&crc);
if(matchlen > remainder)
matchlen = remainder;
if(matchlen > lastmatchlen || lastmatchlen < THRESHOLD)
{
encode_set.output(text[pos - 1], 0);
}
else
{
encode_set.output(lastmatchlen + (UCHAR_MAX + 1 - THRESHOLD),
(uint)(pos - lastmatchpos - 2) & (uint)dicsiz1);
while(--lastmatchlen > 0)
{
get_next_match(&crc);
}
if(matchlen > remainder)
matchlen = remainder;
}
}
encode_set.encode_end();
interface -> packed = compsize;
return crc;
}
hword
decode(struct interfacing *interface)
{
int i, j, k, c, dicsiz1, offset;
hword crc = 0;
infile = interface -> infile;
outfile = interface -> outfile;
dicbit = interface -> dicbit;
origsize = interface -> original;
compsize = interface -> packed;
use_ptr = interface -> internal; /* for display usage */
decode_set = decode_define[interface -> method - 1];
dicsiz = 1U << dicbit;
if(text == NULL)
error(MEMOVRERR, NULL);
memset(text, ' ', dicsiz);
decode_set.decode_start();
dicsiz1 = dicsiz - 1;
offset = (interface -> method == 6) ? 0x100 - 2 : 0x100 - 3;
count = 0;
loc = 0;
while(count < origsize)
{
c = decode_set.decode_c();
if(c <= UCHAR_MAX)
{
text[loc++] = c;
if(loc == dicsiz)
{
fwrite_crc(text, dicsiz, outfile, &crc);
loc = 0;
}
count++;
}
else
{
j = c - offset;
i = (uint)(loc - decode_set.decode_p() - 1) & (uint)dicsiz1;
count += j;
for(k = 0; k < j; k++)
{
c = text[(uint)(i + k) & (uint)dicsiz1];
text[loc++] = c;
if(loc == dicsiz)
{
fwrite_crc(text, dicsiz, outfile, &crc);
loc = 0;
}
}
}
}
if(loc != 0)
fwrite_crc(text, loc, outfile, &crc);
return crc;
}