home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / tug__002 / dearclzw.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-08-08  |  13.9 KB  |  669 lines

  1. {TUG PDS CERT 1.01 (Pascal)
  2.  
  3. ==========================================================================
  4.  
  5.                   TUG PUBLIC DOMAIN SOFTWARE CERTIFICATION
  6.  
  7. The Turbo User Group (TUG) is recognized by Borland International as the
  8. official support organization for Turbo languages.  This file has been
  9. compiled and verified by the TUG library staff.  We are reasonably certain
  10. that the information contained in this file is public domain material, but
  11. it is also subject to any restrictions applied by its author.
  12.  
  13. This diskette contains PROGRAMS and/or DATA determined to be in the PUBLIC
  14. DOMAIN, provided as a service of TUG for the use of its members.  The
  15. Turbo User Group will not be liable for any damages, including any lost
  16. profits, lost savings or other incidental or consequential damages arising
  17. out of the use of or inability to use the contents, even if TUG has been
  18. advised of the possibility of such damages, or for any claim by any
  19. other party.
  20.  
  21. To the best of our knowledge, the routines in this file compile and function
  22. properly in accordance with the information described below.
  23.  
  24. If you discover an error in this file, we would appreciate it if you would
  25. report it to us.  To report bugs, or to request information on membership
  26. in TUG, please contact us at:
  27.  
  28.              Turbo User Group
  29.              PO Box 1510
  30.              Poulsbo, Washington USA  98370
  31.  
  32. --------------------------------------------------------------------------
  33.                        F i l e    I n f o r m a t i o n
  34.  
  35. * DESCRIPTION
  36. Turbo Pascal V4.0 DEARC Lempel-Ziv-Welch decompression routines (that is,
  37. unsquashing and uncrunching).
  38.  
  39. * ASSOCIATED FILES
  40. DEARC.PAS
  41. DEARCABT.PAS
  42. DEARCGLB.PAS
  43. DEARCIO.PAS
  44. DEARCLZW.PAS
  45. DEARCUNP.PAS
  46. DEARCUSQ.PAS
  47. DEARC.TXT
  48.  
  49. * CHECKED BY
  50. DRM 08/08/88
  51.  
  52. * KEYWORDS
  53. TURBO PASCAL V4.0
  54.  
  55. ==========================================================================
  56. }
  57. (**
  58.  *
  59.  *  Module:       dearclzw.pas
  60.  *  Description:  DEARC Lempel-Ziv-Welch decompression routines
  61.  *                (that is,  unsquashing and uncrunching)
  62.  *
  63.  *  Revision History:
  64.  *    7-26-88: unitized for Turbo v4.0
  65.  *
  66. **)
  67.  
  68.  
  69. unit dearclzw;
  70.  
  71. interface
  72. uses
  73.   dearcabt,
  74.   dearcglb,
  75.   dearcio,
  76.   dearcunp;
  77.  
  78. procedure init_ucr ( i : integer );
  79. function getc_ucr : integer;
  80. procedure decomp ( SquashFlag : integer );
  81.  
  82. implementation
  83.  
  84. (*
  85.  *  definitions for uncrunch / unsquash
  86.  *)
  87. Const
  88.    TABSIZE   = 4096;
  89.    TABSIZEM1 = 4095;
  90.    NO_PRED : word  = $FFFF;
  91.    EMPTY   : word  = $FFFF;
  92.  
  93. Type
  94.    entry = record
  95.               used         : boolean;
  96.               next         : integer;
  97.               predecessor  : integer;
  98.               follower     : byte
  99.            end;
  100.  
  101. Var
  102.    stack       : array [0..TABSIZEM1] of byte;
  103.    sp          : integer;
  104.    string_tab  : array [0..TABSIZEM1] of entry;
  105.  
  106. Var
  107.    code_count : integer;
  108.    code       : integer;
  109.    firstc     : boolean;
  110.    oldcode    : integer;
  111.    finchar    : integer;
  112.    inbuf      : integer;
  113.    outbuf     : integer;
  114.    newhash    : boolean;
  115.  
  116. (*
  117.  *  definitions for dynamic uncrunch
  118.  *)
  119. Const
  120.   Crunch_BITS = 12;
  121.   Squash_BITS = 13;
  122.   HSIZE = 8192;
  123.   INIT_BITS = 9;
  124.   FIRST = 257;
  125.   CLEAR = 256;
  126.   HSIZEM1 = 8191;
  127.   BITSM1 = 12;
  128.  
  129.   RMASK : array[0..8] of byte = ($00, $01, $03, $07, $0f, $1f, $3f, $7f, $ff);
  130.  
  131. Var
  132.   bits,
  133.   n_bits,
  134.   maxcode    : integer;
  135.   prefix     : array[0..HSIZEM1] of integer;
  136.   suffix     : array[0..HSIZEM1] of byte;
  137.   buf        : array[0..BITSM1]  of byte;
  138.   clear_flg  : integer;
  139.   stack1     : array[0..HSIZEM1] of byte;
  140.   free_ent   : integer;
  141.   maxcodemax : integer;
  142.   offset,
  143.   sizex      : integer;
  144.  
  145.  
  146. (**
  147.  *
  148.  *  Name:         function h
  149.  *  Description:  calculate hash value for LZW compression
  150.  *                thanks to Bela Lubkin
  151.  *  Parameters:   value -
  152.  *                  pred, foll : integer - pred and follower bytes
  153.  *  Returns:      new hash value
  154.  *
  155. **)
  156. function h(pred, foll : integer) : integer;
  157. { pbr - removed messy real-to-int stuff - not necessary in TP4 }
  158. var
  159.   Local : longint;
  160.   V     : word;
  161. begin
  162.   if not newhash then
  163.     Local := (pred + foll) or $0800
  164.   else
  165.     Local := (pred + foll) * 15073;
  166.  
  167.   h := integer(local and $0FFF);
  168. end;
  169.  
  170.  
  171. (**
  172.  *
  173.  *  Name:         function eolist
  174.  *  Description:  find end of an LZW chain
  175.  *  Parameters:   value -
  176.  *                  index : integer - start of chain
  177.  *  Returns:      last entry in chain
  178.  *
  179. **)
  180. function eolist(index : integer) : integer;
  181. var temp : integer;
  182. begin
  183.   temp := string_tab[index].next;
  184.  
  185.   while temp <> 0 do
  186.     begin
  187.       index := temp;
  188.       temp := string_tab[index].next
  189.     end;
  190.  
  191.   eolist := index
  192. end; (* func eolist *)
  193.  
  194.  
  195. (**
  196.  *
  197.  *  Name:         function hash
  198.  *  Description:  add pred/foll pair to LZW hash table
  199.  *  Parameters:   value -
  200.  *                  pred, foll : integer - pair to add
  201.  *  Returns:      new pred val
  202.  *
  203. **)
  204. function hash(pred, foll : integer) : integer;
  205. var
  206.   local     : integer;
  207.     tempnext  : integer;
  208. begin
  209.   local := h(pred, foll);
  210.  
  211.   if not string_tab[local].used then
  212.     hash := local
  213.   else
  214.     begin
  215.       local := eolist(local);
  216.       tempnext := (local + 101) and $0FFF;
  217.  
  218.       while string_tab[tempnext].used do
  219.         begin
  220.           tempnext := tempnext + 1;
  221.           if tempnext = TABSIZE then
  222.             tempnext := 0
  223.         end;
  224.  
  225.       string_tab[local].next := tempnext;
  226.       hash := tempnext
  227.     end
  228. end; (* func hash *)
  229.  
  230.  
  231. (**
  232.  *
  233.  *  Name:         procedure upd_tab
  234.  *  Description:  update LZW hash table entry
  235.  *  Parameters:   value -
  236.  *                  pred, foll : integer - pair to update
  237.  *
  238. **)
  239. procedure upd_tab(pred, foll : integer);
  240. begin
  241.   with string_tab[hash(pred, foll)] do
  242.     begin
  243.       used := TRUE;
  244.       next := 0;
  245.       predecessor := pred;
  246.       follower := foll
  247.     end
  248. end; (* proc upd_tab *)
  249.  
  250.  
  251. (**
  252.  *
  253.  *  Name:         function gocode : integer
  254.  *
  255. **)
  256. function gocode : integer;
  257. label
  258.   exit;
  259. var
  260.   localbuf  : integer;
  261.   returnval : integer;
  262. begin
  263.   if inbuf = EMPTY then
  264.     begin
  265.       localbuf := getc_unp;
  266.  
  267.       if localbuf = -1 then
  268.         begin
  269.           gocode := -1;
  270.           goto exit                       (******** was "exit" ************)
  271.         end;
  272.  
  273.       localbuf := localbuf and $00FF;
  274.       inbuf := getc_unp;
  275.       if inbuf = -1 then
  276.         begin
  277.           gocode := -1;
  278.           goto exit                       (******** was "exit" ************)
  279.         end;
  280.  
  281.       inbuf := inbuf and $00FF;
  282.       returnval := ((localbuf shl 4) and $0FF0) + ((inbuf shr 4) and $000F);
  283.       inbuf := inbuf and $000F
  284.     end
  285.   else
  286.     begin
  287.       localbuf := getc_unp;
  288.       if localbuf = -1 then
  289.         begin
  290.           gocode := -1;
  291.           goto exit                       (******** was "exit" ************)
  292.         end;
  293.  
  294.       localbuf := localbuf and $00FF;
  295.       returnval := localbuf + ((inbuf shl 8) and $0F00);
  296.       inbuf := EMPTY
  297.     end;
  298.   gocode := returnval;
  299.  
  300. exit:
  301.  
  302. end; (* func gocode *)
  303.  
  304.  
  305. (**
  306.  *
  307.  *  Name:         procedure push
  308.  *  Description:  push a char onto LZW 'pending' stack
  309.  *  Parameters:   value -
  310.  *                  c : integer - value to push
  311.  *
  312. **)
  313. procedure push(c : integer);
  314. begin
  315.   stack[sp] := c;
  316.   sp := sp + 1;
  317.  
  318.   if sp >= TABSIZE then
  319.     abort('Stack overflow')
  320. end; (* proc push *)
  321.  
  322.  
  323. (**
  324.  *
  325.  *  Name:         function pop : integer
  326.  *  Description:  pop a character from LZW 'pending' stack
  327.  *  Parameters:   none
  328.  *  Returns:      character popped or EMPTY
  329.  *
  330. **)
  331. function pop : integer;
  332. begin
  333.   if sp > 0 then
  334.     begin
  335.       sp := sp - 1;
  336.       pop := stack[sp]
  337.     end
  338.   else
  339.     pop := EMPTY
  340. end; (* func pop *)
  341.  
  342.  
  343. (**
  344.  *
  345.  *  Name:         procedure init_tab
  346.  *  Description:  initialize LZW string table
  347.  *  Parameters:   none
  348.  *
  349. **)
  350. procedure init_tab;
  351. var
  352.   i : integer;
  353. begin
  354.   FillChar(string_tab, sizeof(string_tab), 0);
  355.  
  356.   for i := 0 to 255 do
  357.     upd_tab(NO_PRED, i);
  358.  
  359.   inbuf := EMPTY;
  360. end; (* proc init_tab *)
  361.  
  362.  
  363. (**
  364.  *
  365.  *  Name:         procedure init_ucr
  366.  *  Description:  init LZW routines
  367.  *  Parameters:   value -
  368.  *                  i : integer - hash seed
  369.  *
  370. **)
  371. procedure init_ucr(i:integer);
  372. begin
  373.   newhash := i = 1;
  374.   sp := 0;
  375.   init_tab;
  376.   code_count := TABSIZE - 256;
  377.   firstc := TRUE
  378. end; (* proc init_ucr *)
  379.  
  380.  
  381. (**
  382.  *
  383.  *  Name:         function getc_ucr : integer
  384.  *  Description:  get next (uncompressed) LZW character
  385.  *  Parameters:   none
  386.  *  Returns:      next character
  387.  *
  388. **)
  389. function getc_ucr : integer;
  390. label exit;
  391. var c       : integer;
  392.     code    : integer;
  393.     newcode : integer;
  394. begin
  395.   if firstc then
  396.     begin
  397.       firstc := FALSE;
  398.       oldcode := gocode;
  399.       finchar := string_tab[oldcode].follower;
  400.       getc_ucr := finchar;
  401.       goto exit                         (******** was "exit" ************)
  402.     end;
  403.  
  404.   if sp = 0 then
  405.     begin
  406.       newcode := gocode;
  407.       code := newcode;
  408.       if code = -1 then
  409.         begin
  410.           getc_ucr := -1;
  411.           goto exit                     (******** was "exit" ************)
  412.         end;
  413.  
  414.       if not string_tab[code].used then
  415.         begin
  416.           code := oldcode;
  417.           push(finchar)
  418.         end;
  419.  
  420.       while string_tab[code].predecessor <> NO_PRED do
  421.         with string_tab[code] do
  422.           begin
  423.             push(follower);
  424.             code := predecessor
  425.           end;
  426.  
  427.       finchar := string_tab[code].follower;
  428.       push(finchar);
  429.  
  430.       if code_count <> 0 then
  431.         begin
  432.           upd_tab(oldcode, finchar);
  433.           code_count := code_count - 1
  434.         end;
  435.  
  436.       oldcode := newcode
  437.     end;
  438.  
  439.   getc_ucr := pop;
  440.  
  441. exit:
  442.  
  443. end; (* func getc_ucr *)
  444.  
  445.  
  446. (**
  447.  *
  448.  *  Name:         function getcode : integer
  449.  *  Description:
  450.  *  Parameters:   var -
  451.  *
  452.  *                value -
  453.  *
  454.  *  Returns:
  455.  *
  456. **)
  457. function getcode : integer;
  458. label
  459.   next, exit;
  460. var
  461.   code, r_off, bitsx : integer;
  462.   bp : byte;
  463. begin
  464.   if firstch then
  465.     begin
  466.       offset := 0;
  467.       sizex := 0;
  468.       firstch := false;
  469.     end;
  470.  
  471.   bp := 0;
  472.  
  473.   if (clear_flg > 0) or (offset >= sizex) or (free_ent > maxcode) then
  474.     begin
  475.       if free_ent > maxcode then
  476.         begin
  477.           n_bits := n_bits + 1;
  478.           if n_bits = BITS then
  479.             maxcode := maxcodemax
  480.           else
  481.             maxcode := (1 shl n_bits) - 1;
  482.         end;
  483.  
  484.       if clear_flg > 0 then
  485.         begin
  486.           n_bits := INIT_BITS;
  487.           maxcode := (1 shl n_bits) - 1;
  488.           clear_flg := 0;
  489.         end;
  490.  
  491.       for sizex := 0 to n_bits-1 do
  492.         begin
  493.           code := getc_unp;
  494.           if code = -1 then
  495.             goto next
  496.           else
  497.             buf[sizex] := code;
  498.         end;
  499.  
  500.       sizex := sizex + 1;
  501.  
  502. next:
  503.  
  504.       if sizex <= 0 then
  505.         begin
  506.           getcode := -1;
  507.           goto exit;
  508.         end;
  509.  
  510.       offset := 0;
  511.       sizex := (sizex shl 3) - (n_bits - 1);
  512.     end;
  513.  
  514.   r_off := offset;
  515.   bitsx := n_bits;
  516.  
  517.   (*
  518.    *  get first byte
  519.    *)
  520.   bp := bp + (r_off shr 3);
  521.   r_off := r_off and 7;
  522.  
  523.   (*
  524.    *  get first part (low order bits)
  525.    *)
  526.   code := buf[bp] shr r_off;
  527.   bp := bp + 1;
  528.   bitsx := bitsx - (8 - r_off);
  529.   r_off := 8 - r_off;
  530.  
  531.   if bitsx >= 8 then
  532.     begin
  533.       code := code or (buf[bp] shl r_off);
  534.       bp := bp + 1;
  535.       r_off := r_off + 8;
  536.       bitsx := bitsx - 8;
  537.     end;
  538.  
  539.   code := code or ((buf[bp] and rmask[bitsx]) shl r_off);
  540.   offset := offset + n_bits;
  541.   getcode := code;
  542.  
  543. exit:
  544.  
  545. end;
  546.  
  547.  
  548. (**
  549.  *
  550.  *  Name:         procedure decomp
  551.  *  Description:  decompress a file with LZW
  552.  *  Parameters:   value -
  553.  *                  SquashFlag : integer - true if Squashing in effect
  554.  *
  555. **)
  556. procedure decomp(SquashFlag : Integer);
  557. label
  558.   next,
  559.   exit;
  560. var
  561.   stackp,
  562.   finchar : integer;
  563.   code,
  564.   oldcode,
  565.   incode : integer;
  566. begin
  567.   if SquashFlag = 0 then
  568.     Bits := crunch_BITS
  569.   else
  570.     Bits := squash_BITS;
  571.  
  572.   if firstch then
  573.     maxcodemax := 1 shl bits;
  574.  
  575.   if SquashFlag = 0 then
  576.     begin
  577.       code := getc_unp;
  578.       if code <> BITS then
  579.         begin
  580.            Writeln( 'File packed with ', Code,
  581.                     ' bits, I can only handle ', Bits);
  582.            Halt(1);
  583.         end;
  584.     end;
  585.  
  586.   clear_flg := 0;
  587.   n_bits := INIT_BITS;
  588.   maxcode := (1 shl n_bits ) - 1;
  589.  
  590.   for code := 255 downto 0 do
  591.     begin
  592.       prefix[code] := 0;
  593.       suffix[code] := code;
  594.     end;
  595.  
  596.   free_ent := FIRST;
  597.   oldcode := getcode;
  598.   finchar := oldcode;
  599.  
  600.   if oldcode = -1 then
  601.     goto exit;
  602.  
  603.   if SquashFlag = 0 then
  604.     putc_ncr(finchar)
  605.   else
  606.     putc_unp(finchar);
  607.  
  608.   stackp := 0;
  609.  
  610.   code := getcode;
  611.   while (code  > -1) do
  612.     begin
  613.       if code = CLEAR then
  614.         begin
  615.           for code := 255 downto 0 do
  616.             prefix[code] := 0;
  617.           clear_flg := 1;
  618.           free_ent := FIRST - 1;
  619.           code := getcode;
  620.           if code = -1 then
  621.             goto next;
  622.         end;
  623. next:
  624.       incode := code;
  625.       if code >= free_ent then
  626.         begin
  627.           stack1[stackp] := finchar;
  628.           stackp := stackp + 1;
  629.           code := oldcode;
  630.         end;
  631.  
  632.       while (code >= 256) do
  633.         begin
  634.           stack1[stackp] := suffix[code];
  635.           stackp := stackp + 1;
  636.           code := prefix[code];
  637.         end;
  638.  
  639.       finchar := suffix[code];
  640.       stack1[stackp] := finchar;
  641.       stackp := stackp + 1;
  642.       repeat
  643.         stackp := stackp - 1;
  644.         If SquashFlag = 0 then
  645.           putc_ncr(stack1[stackp])
  646.         else
  647.           putc_unp(stack1[stackp]);
  648.       until stackp <= 0;
  649.  
  650.       code := free_ent;
  651.  
  652.       if code < maxcodemax then
  653.         begin
  654.           prefix[code] := oldcode;
  655.           suffix[code] := finchar;
  656.           free_ent := code + 1;
  657.         end;
  658.  
  659.       oldcode := incode;
  660.       code := getcode;
  661.     end;
  662.  
  663. exit:
  664.  
  665. end;
  666.  
  667. end.
  668.  
  669.