home *** CD-ROM | disk | FTP | other *** search
-
- (* --------------------------------------------------------------
- * DEHUF.PAS
- *
- * Based on decode section of lzhuf.c
- * Written by Haruyasu Yoshizaki 11/20/1988
- * Some minor changes 4/6/1989
- * Comments translated by Haruhiko Okumura 4/7/1989
- * Translated to turbo pascal by Samuel H. Smith 4/20/1989
- *
- *)
-
- uses mdosio;
-
- procedure Error(message: string);
- begin
- writeln;
- writeln(message);
- halt(1);
- end;
-
-
- (********** LZSS compression **********)
-
- var
- infile: dos_handle;
- outfile: dos_handle;
-
- const
- textsize: longint = 0;
- printcount: longint = 0;
-
- N = 4096; (* buffer size *)
- F = 60; (* lookahead buffer size *)
- THRESHOLD = 2;
-
- type
- uchar = byte;
-
- var
- text_buf: array[0..N+F-1] of uchar;
- lson: array[0..N+1] of integer;
- rson: array[0..N+257] of integer;
- dad: array[0..N+1] of integer;
-
-
- (* Huffman coding *)
-
- const
- N_CHAR = (256-THRESHOLD+F); (* kinds of characters (code = 0..N_CHAR-1) *)
- T = (N_CHAR * 2 - 1); (* size of table *)
- R = (T - 1); (* position of root *)
- MAX_FREQ = $8000; (* updates tree when the *)
- (* root frequency comes to this value. *)
-
- var
- freq: array[0..T+1] of word; (* frequency table *)
- parent: array[0..T+N_CHAR] of word;
- (* pointers to parent nodes, except for the *)
- (* elements[T..T + N_CHAR - 1] which are used to get *)
- (* the positions of leaves corresponding to the codes. *)
-
- son: array[0..T] of integer;
- (* pointers to child nodes (son[], son[] + 1) *)
-
- const
- getbuf: word = 0;
- getlen: uchar = 0;
-
- function GetBit: integer; (* get one bit *)
- var
- i: byte;
-
- begin
-
- while (getlen <= 8) do
- begin
- ReadByte(i);
- getbuf := getbuf or (i shl (8 - getlen));
- inc(getlen, 8);
- end;
-
- if (getbuf and $8000) <> 0 then
- GetBit := 1
- else
- GetBit := 0;
-
- getbuf := getbuf shl 1;
- dec(getlen);
- end;
-
- function GetByte: integer; (* get one byte *)
- var
- i: byte;
-
- begin
-
- while (getlen <= 8) do
- begin
- ReadByte(i);
- getbuf := getbuf or (word(i) shl (8 - getlen));
- inc(getlen, 8);
- end;
-
- GetByte := getbuf shr 8;
- getbuf := getbuf shl 8;
- dec(getlen, 8);
- end;
-
-
- (* table for encoding and decoding the upper 6 bits of position *)
-
- (* for decoding *)
- d_code: array[0..255] of uchar = (
- $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
- $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
- $00, $00, $00, $00, $00, $00, $01, $01, $01, $01, $01, $01, $01,
- $01, $01, $01, $01, $01, $01, $01, $01, $01, $02, $02, $02, $02,
- $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $03,
- $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03,
- $03, $03, $04, $04, $04, $04, $04, $04, $04, $04, $05, $05, $05,
- $05, $05, $05, $05, $05, $06, $06, $06, $06, $06, $06, $06, $06,
- $07, $07, $07, $07, $07, $07, $07, $07, $08, $08, $08, $08, $08,
- $08, $08, $08, $09, $09, $09, $09, $09, $09, $09, $09, $0A, $0A,
- $0A, $0A, $0A, $0A, $0A, $0A, $0B, $0B, $0B, $0B, $0B, $0B, $0B,
- $0B, $0C, $0C, $0C, $0C, $0D, $0D, $0D, $0D, $0E, $0E, $0E, $0E,
- $0F, $0F, $0F, $0F, $10, $10, $10, $10, $11, $11, $11, $11, $12,
- $12, $12, $12, $13, $13, $13, $13, $14, $14, $14, $14, $15, $15,
- $15, $15, $16, $16, $16, $16, $17, $17, $17, $17, $18, $18, $19,
- $19, $1A, $1A, $1B, $1B, $1C, $1C, $1D, $1D, $1E, $1E, $1F, $1F,
- $20, $20, $21, $21, $22, $22, $23, $23, $24, $24, $25, $25, $26,
- $26, $27, $27, $28, $28, $29, $29, $2A, $2A, $2B, $2B, $2C, $2C,
- $2D, $2D, $2E, $2E, $2F, $2F, $30, $31, $32, $33, $34, $35, $36,
- $37, $38, $39, $3A, $3B, $3C, $3D, $3E, $3F);
-
- d_len: array[0..255] of uchar = (
- $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03,
- $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03,
- $03, $03, $03, $03, $03, $03, $04, $04, $04, $04, $04, $04, $04,
- $04, $04, $04, $04, $04, $04, $04, $04, $04, $04, $04, $04, $04,
- $04, $04, $04, $04, $04, $04, $04, $04, $04, $04, $04, $04, $04,
- $04, $04, $04, $04, $04, $04, $04, $04, $04, $04, $04, $04, $04,
- $04, $04, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05,
- $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05,
- $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05,
- $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05,
- $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05,
- $05, $06, $06, $06, $06, $06, $06, $06, $06, $06, $06, $06, $06,
- $06, $06, $06, $06, $06, $06, $06, $06, $06, $06, $06, $06, $06,
- $06, $06, $06, $06, $06, $06, $06, $06, $06, $06, $06, $06, $06,
- $06, $06, $06, $06, $06, $06, $06, $06, $06, $06, $07, $07, $07,
- $07, $07, $07, $07, $07, $07, $07, $07, $07, $07, $07, $07, $07,
- $07, $07, $07, $07, $07, $07, $07, $07, $07, $07, $07, $07, $07,
- $07, $07, $07, $07, $07, $07, $07, $07, $07, $07, $07, $07, $07,
- $07, $07, $07, $07, $07, $07, $08, $08, $08, $08, $08, $08, $08,
- $08, $08, $08, $08, $08, $08, $08, $08, $08);
-
-
- (* initialization of tree *)
-
- procedure StartHuff;
- var
- i: integer;
- j: integer;
-
- begin
-
- for i := 0 to N_CHAR - 1 do
- begin
- freq[i] := 1;
- son[i] := i + T;
- parent[i + T] := i;
- end;
-
- i := 0;
- j := N_CHAR;
- while (j <= R) do
- begin
- freq[j] := freq[i] + freq[i + 1];
- son[j] := i;
- parent[i] := j;
- parent[i + 1] := j;
- inc(i, 2);
- inc(j);
- end;
-
- freq[T] := $ffff;
- parent[R] := 0;
- end;
-
-
- (* reconstruction of tree *)
-
- procedure reconst;
- var
- i,j,k: integer;
- f,l: word;
-
- begin
-
- (* collect leaf nodes in the first half of the table *)
- (* and replace the freq by (freq + 1) / 2. *)
- j := 0;
- for i := 0 to T - 1 do
- begin
-
- if (son[i] >= T) then
- begin
- freq[j] := (freq[i] + 1) div 2;
- son[j] := son[i];
- inc(j);
- end;
- end;
-
-
- (* begin constructing tree by connecting sons *)
-
- i := 0;
- for j := N_CHAR to T - 1 do
- begin
- k := i + 1;
- f := freq[i] + freq[k];
- freq[j] := f;
-
- k := j - 1;
- while (f < freq[k]) do
- dec(k);
-
- inc(k);
- l := (j - k) * 2;
-
- move(freq[k], freq[k+1], l);
- freq[k] := f;
-
- move(son[k], son[k+1], l);
- son[k] := i;
-
- inc(i, 2);
- end;
-
-
- (* connect parent *)
-
- for i := 0 to T - 1 do
- begin
- k := son[i];
- if k >= T then
- parent[k] := i
- else
- begin
- parent[k] := i;
- parent[k + 1] := i;
- end;
- end;
- end;
-
-
- (* increment frequency of given code by one, and update tree *)
-
- procedure update (c: integer);
- var
- i,j,k,l: integer;
-
- begin
-
- if (freq[R] = MAX_FREQ) then
- reconst;
-
- c := parent[c + T];
-
- repeat
- inc(freq[c]);
- k := freq[c];
-
- (* if the order is disturbed, exchange nodes *)
-
- l := c+1;
- if (k > freq[l]) then
- begin
- repeat
- inc(l);
- until k <= freq[l];
-
- dec(l);
- freq[c] := freq[l];
- freq[l] := k;
-
- i := son[c];
-
- parent[i] := l;
- if (i < T) then
- parent[i + 1] := l;
-
- j := son[l];
- son[l] := i;
-
- parent[j] := c;
- if (j < T) then
- parent[j + 1] := c;
-
- son[c] := j;
- c := l;
- end;
-
- c := parent[c];
-
- until c = 0; (* repeat up to root *)
- end;
-
- function DecodeChar: integer;
- var
- c: word;
- b: word;
- begin
- c := son[R];
-
- (* travel from root to leaf, *)
- (* choosing the smaller child node (son[]) if the read bit is 0, *)
- (* the bigger (son[] +1end; if 1 *)
-
- while (c < T) do
- begin
- b := GetBit;
- inc(c,b);
- c := son[c];
- end;
-
- dec(c, T);
- update(c);
- DecodeChar := c;
- end;
-
- function DecodePosition: integer;
- var
- i,j,c: word;
-
- begin
-
- (* recover upper 6 bits from table *)
- i := GetByte;
- c := d_code[i] shl 6;
- j := d_len[i];
-
- (* read lower 6 bits verbatim *)
- dec(j, 2);
- while j <> 0 do
- begin
- dec(j);
- i := (i shl 1) + GetBit;
- end;
-
- DecodePosition := c or (i and $3f);
- end;
-
- procedure Decode; (* recover *)
- var
- i,j,k,r,c: integer;
- count: longint;
-
- begin
-
- (* read size of text *)
- if dos_read(infile, textsize, sizeof(textsize)) <> sizeof(textsize) then
- Error('Can''t read');
-
- if (textsize = 0) then
- exit;
-
- StartHuff;
-
- for i := 0 to N - F - 1 do
- text_buf[i] := ord(' ');
-
- r := N - F;
- count := 0;
- while count < textsize do
- begin
- c := DecodeChar;
- if (c < 256) then
- begin
- dos_write(outfile, c, 1);
- text_buf[r] := c;
- inc(r);
- r := r and (N - 1);
- inc(count);
- end
- else
-
- begin
- i := (r - DecodePosition - 1) and (N - 1);
- j := c - 255 + THRESHOLD;
-
- for k := 0 to j - 1 do
- begin
- c := text_buf[(i+k) and (N-1)];
- dos_write(outfile, c, 1);
- text_buf[r] := c;
- inc(r);
- r := r and (N - 1);
- inc(count);
- end;
- end;
-
- if (count > printcount) then
- begin
- write(count : 12, #13);
- inc(printcount, 1024);
- end;
- end;
-
- writeln(count:12);
- end;
-
-
- (* main block *)
-
- begin
- if paramcount <> 2 then
- begin
- writeln('Decodes files encoded with Haruyasu Yoshizaki's lzhuf.');
- writeln('Usage: dehuf infile outfile');
- halt(1);
- end;
-
- infile := dos_open(paramstr(1), open_read);
-
- if infile = dos_error then
- error('Can''t open: ' + paramstr(1));
-
- outfile := dos_create(paramstr(2));
-
- if outfile = dos_error then
- error('Can''t create: ' + paramstr(2));
-
- Decode;
-
- dos_close(infile);
- dos_close(outfile);
- halt(0);
- end.
-
-