|
void Encode (void)
{
int i, c, len, r, s, last_match_length, code_buf_ptr;
unsigned char code_buf [17], mask;
InitTree (); / * initialize trees * /
code_buf [0] = 0; / * code_buf [1..16] saves eight units of code, and
code_buf [0] works as eight flags, "1" representing that the
unit
is an unencoded letter (1 byte), "0" a position-and-length p
air
(2 bytes). Thus, eight units require at most 16 bytes of co
de.
/
code_buf_ptr = mask = 1;
s = 0; r = N-F;
for (i = s; i <r; i ++) text_buf [i] = ''; / * Clear the buffer with
any character that will appear often. * /
for (len = 0; len <F&&(c = getc (infile))! = EOF; len ++)
text_buf [r + len] = c; / * Read F bytes into the last F byte
s of
the buffer * /
if ((textsize = len) == 0) return; / * text of size zero * /
for (i = 1; i <= F; i ++) InsertNode (r-i); / * Insert the F strings
,
each of which begins with one or more 'space' characters. N
ote
the order in which these strings are inserted. This way,
degenerate trees will be less likely to occur. * /
InsertNode (r); / * Finally, insert the whole string just read. The
global variables match_length and match_position are set. * /
do {
if (match_length> len) match_length = len; / * match_length
may be spuriously long near the end of text. * /
if (match_length <= THRESHOLD) {
match_length = 1; / * Not long enough match. Send o
ne b
te. * /
code_buf [0] | = mask; / * 'send one byte' flag * /
code_buf [code_buf_ptr ++] = text_buf [r]; / * Send unc
oded
* /
} else {
code_buf [code_buf_ptr ++] = (unsigned char) match_pos
itio
;
code_buf [code_buf_ptr ++] = (unsigned char)
(((match_position >> 4)&0xf0)
| (match_length-(THRESHOLD + 1))); / * Send posi
tion
and
length pair. Note match_length> THR
ESHO
D. * /
}
if ((mask << = 1) == 0) {/ * Shift mask left one bit. * /
for (i = 0; i <code_buf_ptr; i ++) / * Send at most
8 un
ts of * /
putc (code_buf [i], outfile); / * code toge
ther
* /
codesize + = code_buf_ptr;
code_buf [0] = 0; code_buf_ptr = mask = 1;
}
last_match_length = match_length;
for (i = 0; i <last_match_length&&
(c = getc (infile))! = EOF; i ++) {
DeleteNode (s); / * Delete old strings and * /
text_buf [s] = c; / * read new bytes * /
if (s <F-1) text_buf [s + N] = c; / * If the posit
ion
s
near the end of buffer, extend the buffer to
mak
string comparison easier. * /
s = (s + 1)&(N-1); r = (r + 1)&(N-1);
/ * Since this is a ring buffer, increment th
e po
ition
modulo N. * /
InsertNode (r); / * Register the string in text_buf [r
..r +
-1] */
}
if ((textsize + = i)> printcount) {
printf ("% 12ld\r", textsize); printcount + = 1024;
/ * Reports progress each time the textsize e
xcee
s
multiples of 1024. * /
}
while (i ++ <last_match_length) {/ * After the end of
text
* /
DeleteNode (s); / * n
o ne
d to read, but * /
s = (s + 1)&(N-1); r = (r + 1)&(N-1);
if (--len) InsertNode (r); / * buffer ma
y no
be empty. * /
}
} while (len> 0); / * until length of string to be processed is
zer
* /
if (code_buf_ptr> 1) {/ * Send remaining code. * /
for (i = 0; i <code_buf_ptr; i ++) putc (code_buf [i], outfile
);
codesize + = code_buf_ptr;
}
printf ("In:% ld bytes\n", textsize); / * Encoding is done. * /
printf ("Out:% ld bytes\n", codesize);
printf ("Out / In:% .3f\n", (double) codesize / textsize);
}
void Decode (void) / * Just the reverse of Encode (). * /
{
int i, j, k, r, c;
unsigned int flags;
for (i = 0; i <N-F; i ++) text_buf [i] = '';
r = N-F; flags = 0;
for (;;) {
if (((flags >> = 1)&256) == 0) {
if ((c = getc (infile)) == EOF) break;
flags = c | 0xff00; / * uses higher byte
clev
rly * /
} / * t
o co
nt eight * /
if (flags&1) {
if ((c = getc (infile)) == EOF) break;
putc (c, outfile); text_buf [r ++] = c; r&= (N-1);
} else {
if ((i = getc (infile)) == EOF) break;
if ((j = getc (infile)) == EOF) break;
i | = ((j&0xf0) << 4); j = (j&0x0f) + THRESHOLD;
for (k = 0; k <= j; k ++) {
c = text_buf [(i + k)&(N-1)];
putc (c, outfile); text_buf [r ++] = c; r&=
(N-
1);
}
}
}
}
int main (int argc, char * argv [])
{
char * s;
if (argc! = 4) {
printf ("'lzss e file1 file2' encodes file1 into file2.\n"
"'lzss d file2 file1' decodes file2 into file1.\n
");
return EXIT_FAILURE;
}
if ((s = argv [1], s [1] || strpbrk (s, "DEde") == NULL)
|| (s = argv [2], (infile = fopen (s, "rb")) == NULL)
|| (s = argv [3], (outfile = fopen (s, "wb")) == NULL)) {
printf ("???% s\n", s); return EXIT_FAILURE;
}
if (toupper (* argv [1]) == 'E') Encode (); else Decode ();
fclose (infile); fclose (outfile);
return EXIT_SUCCESS;
} |
|