home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / packer / arc / arctool / dearclzw.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-09-29  |  12.3 KB  |  631 lines

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