home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / crosscom / tptc / unsq.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-03-25  |  23.0 KB  |  965 lines

  1.  
  2. (*
  3.  DEARC.PAS - Program to extract all files from an archive created by version
  4.              5.12 or earlier of the ARC utility.
  5.  
  6.    *** ORIGINAL AUTHOR UNKNOWN ***
  7. *)
  8.  
  9. Program DearcSQ;
  10.  
  11. {$R-}
  12. {$U-}
  13. {$C-}
  14. {$K-}
  15.  
  16. const 
  17.       BLOCKSIZE = 128;
  18.       arcmarc   = 26;              { special archive marker }
  19.       arcver    = 9;               { max archive header version code }
  20.       strlen    = 100;             { standard string length }
  21.       fnlen     = 12;              { file name length - 1 }
  22.  
  23. const 
  24.   crctab : array [0..255] of integer =
  25.   ( $0000, $C0C1, $C181, $0140, $C301, $03C0, $0280, $C241,
  26.     $C601, $06C0, $0780, $C741, $0500, $C5C1, $C481, $0440,
  27.     $CC01, $0CC0, $0D80, $CD41, $0F00, $CFC1, $CE81, $0E40,
  28.     $0A00, $CAC1, $CB81, $0B40, $C901, $09C0, $0880, $C841,
  29.     $D801, $18C0, $1980, $D941, $1B00, $DBC1, $DA81, $1A40,
  30.     $1E00, $DEC1, $DF81, $1F40, $DD01, $1DC0, $1C80, $DC41,
  31.     $1400, $D4C1, $D581, $1540, $D701, $17C0, $1680, $D641,
  32.     $D201, $12C0, $1380, $D341, $1100, $D1C1, $D081, $1040,
  33.     $F001, $30C0, $3180, $F141, $3300, $F3C1, $F281, $3240,
  34.     $3600, $F6C1, $F781, $3740, $F501, $35C0, $3480, $F441,
  35.     $3C00, $FCC1, $FD81, $3D40, $FF01, $3FC0, $3E80, $FE41,
  36.     $FA01, $3AC0, $3B80, $FB41, $3900, $F9C1, $F881, $3840,
  37.     $2800, $E8C1, $E981, $2940, $EB01, $2BC0, $2A80, $EA41,
  38.     $EE01, $2EC0, $2F80, $EF41, $2D00, $EDC1, $EC81, $2C40,
  39.     $E401, $24C0, $2580, $E541, $2700, $E7C1, $E681, $2640,
  40.     $2200, $E2C1, $E381, $2340, $E101, $21C0, $2080, $E041,
  41.     $A001, $60C0, $6180, $A141, $6300, $A3C1, $A281, $6240,
  42.     $6600, $A6C1, $A781, $6740, $A501, $65C0, $6480, $A441,
  43.     $6C00, $ACC1, $AD81, $6D40, $AF01, $6FC0, $6E80, $AE41,
  44.     $AA01, $6AC0, $6B80, $AB41, $6900, $A9C1, $A881, $6840,
  45.     $7800, $B8C1, $B981, $7940, $BB01, $7BC0, $7A80, $BA41,
  46.     $BE01, $7EC0, $7F80, $BF41, $7D00, $BDC1, $BC81, $7C40,
  47.     $B401, $74C0, $7580, $B541, $7700, $B7C1, $B681, $7640,
  48.     $7200, $B2C1, $B381, $7340, $B101, $71C0, $7080, $B041,
  49.     $5000, $90C1, $9181, $5140, $9301, $53C0, $5280, $9241,
  50.     $9601, $56C0, $5780, $9741, $5500, $95C1, $9481, $5440,
  51.     $9C01, $5CC0, $5D80, $9D41, $5F00, $9FC1, $9E81, $5E40,
  52.     $5A00, $9AC1, $9B81, $5B40, $9901, $59C0, $5880, $9841,
  53.     $8801, $48C0, $4980, $8941, $4B00, $8BC1, $8A81, $4A40,
  54.     $4E00, $8EC1, $8F81, $4F40, $8D01, $4DC0, $4C80, $8C41,
  55.     $4400, $84C1, $8581, $4540, $8701, $47C0, $4680, $8641,
  56.     $8201, $42C0, $4380, $8341, $4100, $81C1, $8081, $4040 );
  57.  
  58. type 
  59.      longtype    = record           { used to simulate long (4 byte) integers }
  60.                  l, h : integer
  61.                end;
  62.  
  63.      strtype = string[strlen];
  64.      fntype  = array [0..fnlen] of char;
  65.      buftype = array [1..BLOCKSIZE] of byte;
  66.      heads   = record
  67.                  name   : fntype;
  68.                  size   : longtype;
  69.                  date   : integer;
  70.                  time   : integer;
  71.                  crc    : integer;
  72.                  length : longtype
  73.                end;
  74.  
  75. var 
  76.     hdrver   : byte;
  77.     arcfile  : file;
  78.     arcbuf   : buftype;
  79.     arcptr   : integer;
  80.     arcname  : strtype;
  81.     endfile  : boolean;
  82.     extfile  : file;
  83.     extbuf   : buftype;
  84.     extptr   : integer;
  85.     extname  : strtype;
  86.  
  87. { definitions for unpack }
  88.  
  89. Const
  90.    DLE = $90;
  91.  
  92. Var
  93.    state  : (NOHIST, INREP);
  94.    crcval : integer;
  95.    size   : real;
  96.    lastc  : integer;
  97.  
  98. { definitions for unsqueeze }
  99.  
  100. Const
  101.    ERROR   = -1;
  102.    SPEOF   = 256;
  103.    NUMVALS = 256;               { 1 less than the number of values }
  104.  
  105. Type
  106.    nd = record
  107.            child : array [0..1] of integer
  108.         end;
  109.  
  110. Var
  111.    node     : array [0..NUMVALS] of nd;
  112.    bpos     : integer;
  113.    curin    : integer;
  114.    numnodes : integer;
  115.  
  116. { definitions for uncrunch }
  117.  
  118. Const
  119.    TABSIZE   = 4096;
  120.    TABSIZEM1 = 4095;
  121.    NO_PRED   = $FFFF;
  122.    EMPTY     = $FFFF;
  123.  
  124. Type
  125.    entry = record
  126.               used         : boolean;
  127.               next         : integer;
  128.               predecessor  : integer;
  129.               follower     : byte
  130.            end;
  131.  
  132. Var
  133.    stack       : array [0..TABSIZEM1] of byte;
  134.    sp          : integer;
  135.    string_tab  : array [0..TABSIZEM1] of entry;
  136.  
  137. Var
  138.    code_count : integer;
  139.    code       : integer;
  140.    firstc     : boolean;
  141.    oldcode    : integer;
  142.    finchar    : integer;
  143.    inbuf      : integer;
  144.    outbuf     : integer;
  145.    newhash    : boolean;
  146.  
  147. { definitions for dynamic uncrunch }
  148.  
  149. Const
  150.   Crunch_BITS = 12;
  151.   Squash_BITS = 13;
  152.   HSIZE = 8192;
  153.   INIT_BITS = 9;
  154.   FIRST = 257;
  155.   CLEAR = 256;
  156.   HSIZEM1 = 8191;
  157.   BITSM1 = 12;
  158.  
  159.   RMASK : array[0..8] of byte =
  160.   ($00, $01, $03, $07, $0f, $1f, $3f, $7f, $ff);
  161.  
  162. Var
  163.   bits,
  164.   n_bits,
  165.   maxcode    : integer;
  166.   prefix     : array[0..HSIZEM1] of integer;
  167.   suffix     : array[0..HSIZEM1] of byte;
  168.   buf        : array[0..BITSM1]  of byte;
  169.   clear_flg  : integer;
  170.   stack1     : array[0..HSIZEM1] of byte;
  171.   free_ent   : integer;
  172.   maxcodemax : integer;
  173.   offset,
  174.   sizex      : integer;
  175.   firstch    : boolean;
  176.  
  177. procedure abortme(s : strtype);
  178. { terminate the program with an error message }
  179. begin
  180.   writeln('ABORT: ', s);
  181.   halt;
  182. end; (* proc abortme *)
  183.  
  184. function fn_to_str(var fn : fntype) : strtype;
  185. { convert strings from C format (trailing 0) to Turbo Pascal format (leading
  186.     length byte). }
  187. var s : strtype;
  188.     i : integer;
  189. begin
  190.   s := '';
  191.   i := 0;
  192.   while fn[i] <> #0 do begin
  193.     s := s + fn[i];
  194.     i := i + 1
  195.     end;
  196.   fn_to_str := s
  197. end; (* func fn_to_str *)
  198.  
  199. function unsigned_to_real(u : integer) : real;
  200. { convert unsigned integer to real }
  201. { note: INT is a function that returns a REAL!!!}
  202. begin
  203.   if u >= 0 then
  204.     unsigned_to_real := Int(u)
  205.   else
  206.   if u = $8000 then
  207.     unsigned_to_real := 32768.0
  208.   else
  209.     unsigned_to_real := 65536.0 + u
  210. end; (* func unsigned_to_real *)
  211.  
  212. function long_to_real(l : longtype) : real;
  213. { convert longtype integer to a real }
  214. { note: INT is a function that returns a REAL!!! }
  215. var r : real;
  216.     s : (posit, NEG);
  217. const rcon = 65536.0;
  218. begin
  219.   if l.h >= 0 then begin
  220.     r := Int(l.h) * rcon;
  221.     s := posit          {notice: no ";" here}
  222.     end
  223.   else begin
  224.     s := NEG;
  225.     if l.h = $8000 then
  226.       r := rcon * rcon
  227.     else
  228.       r := Int(-l.h) * rcon
  229.     end;
  230.   r := r + unsigned_to_real(l.l);
  231.   if s = NEG then
  232.     long_to_real := -r
  233.   else
  234.     long_to_real := r
  235. end; (* func long_to_real *)
  236.  
  237. procedure Read_Block;
  238. { read a block from the archive file }
  239. begin
  240.   if EOF(arcfile) then
  241.     endfile := TRUE
  242.   else
  243.     BlockRead(arcfile, arcbuf, 1);
  244.   arcptr := 1
  245. end; (* proc read_block *)
  246.  
  247. procedure Write_Block;
  248. { write a block to the extracted file }
  249. begin
  250.   BlockWrite(extfile, extbuf, 1);
  251.   extptr := 1
  252. end; (* proc write_block *)
  253.  
  254. procedure open_arc;
  255. { open the archive file for input processing }
  256. begin
  257.   {$I-} assign(arcfile, arcname); {$I+}
  258.   if ioresult <> 0 then
  259.     abortme('Cannot open archive file.');
  260.   {$I-} reset(arcfile); {$I+}
  261.   if ioresult <> 0 then
  262.     abortme('Cannot open archive file.');
  263.   endfile := FALSE;
  264.   Read_Block
  265. end; (* proc open_arc *)
  266.  
  267. procedure open_ext;
  268. { open the extracted file for writing }
  269. begin
  270.   {$I-} assign(extfile, extname); {$I+}
  271.   if ioresult <> 0 then
  272.     abortme('Cannot open extract file.');
  273.   {$I-} rewrite(extfile); {$I+}
  274.   if ioresult <> 0 then
  275.     abortme('Cannot open extract file.');
  276.   extptr := 1;
  277. end; (* proc open_ext *)
  278.  
  279. function get_arc : byte;
  280. { read 1 character from the archive file }
  281. begin
  282.   if endfile then
  283.     get_arc := 0
  284.   else begin
  285.     get_arc := arcbuf[arcptr];
  286.     if arcptr = BLOCKSIZE then
  287.       Read_Block
  288.     else
  289.       arcptr := arcptr + 1
  290.     end
  291. end; (* func get_arc *)
  292.  
  293. procedure put_ext(c : byte);
  294. { write 1 character to the extracted file }
  295. begin
  296.   extbuf[extptr] := c;
  297.   if extptr = BLOCKSIZE then
  298.     Write_Block
  299.   else
  300.     extptr := extptr + 1
  301. end; (* proc put_ext *)
  302.  
  303. procedure close_arc;
  304. { close the archive file }
  305. begin
  306.   close(arcfile)
  307. end; (* proc close_arc *)
  308.  
  309. procedure close_ext;
  310. { close the extracted file }
  311. begin
  312.   while extptr <> 1 do
  313.     put_ext(Ord(^Z));          { pad last block w/ Ctrl-Z (EOF) }
  314.   close(extfile)
  315. end; (* proc close_ext *)
  316.  
  317. procedure fseek(offset : real; base : integer);
  318. { re-position the current pointer in the archive file }
  319. var b           : real;
  320.     i, ofs, rec : integer;
  321.     c           : byte;
  322. begin
  323.   case base of
  324.     0 : b := offset;
  325.     1 : b := offset + (unsigned_to_real(FilePos(arcfile)) - 1.0) * BLOCKSIZE
  326.               + arcptr - 1.0;
  327.     2 : b := offset + unsigned_to_real(FileSize(arcfile)) * BLOCKSIZE - 1.0
  328.     else
  329.       abortme('Invalid parameters to fseek')
  330.     end;
  331.   rec := Trunc(b / BLOCKSIZE);
  332.   ofs := Trunc(b - (Int(rec) * BLOCKSIZE));  { Int converts to Real }
  333.   seek(arcfile, rec);
  334.   Read_Block;
  335.   for i := 1 to ofs do
  336.     c := get_arc
  337. end; (* proc fseek *)
  338.  
  339. procedure fread(var buf; reclen : integer);
  340. { read a record from the archive file }
  341. var i : integer;
  342.     b : array [1..MaxInt] of byte absolute buf;
  343. begin
  344.   for i := 1 to reclen do
  345.     b[i] := get_arc
  346. end; (* proc fread *)
  347.  
  348. procedure GetArcName;
  349. { get the name of the archive file }
  350. var i : integer;
  351. begin
  352.   if ParamCount > 1 then
  353.     abortme('Too many parameters');
  354.   if ParamCount = 1 then
  355.     arcname := ParamStr(1)
  356.   else begin
  357.     write('Enter archive filename: ');
  358.     readln(arcname);
  359.     if arcname = '' then
  360.       abortme('No file name entered');
  361.     writeln;
  362.     writeln;
  363.     end;
  364.   for i := 1 to length(arcname) do
  365.     arcname[i] := UpCase(arcname[i]);
  366.   if pos('.', arcname) = 0 then
  367.     arcname := arcname + '.ARC'
  368. end; (* proc GetArcName *)
  369.  
  370. function readhdr(var hdr : heads) : boolean;
  371. { read a file header from the archive file }
  372. { FALSE = eof found; TRUE = header found }
  373. var name : fntype;
  374.     try  : integer;
  375. begin
  376.   try := 10;
  377.   if endfile then begin
  378.     readhdr := FALSE;
  379.     exit;
  380.     end;
  381.   while get_arc <> arcmarc do begin
  382.     if try = 0 then
  383.       abortme(arcname + ' is not an archive');
  384.     try := try - 1;
  385.     writeln(arcname, ' is not an archive, or is out of sync');
  386.     if endfile then
  387.       abortme('Archive length error')
  388.     end; (* while *)
  389.   hdrver := get_arc;
  390.   if hdrver < 0 then
  391.     abortme('Invalid header in archive ' + arcname);
  392.   if hdrver = 0 then begin   { special end of file marker }
  393.     readhdr := FALSE;
  394.     exit;
  395.     end;
  396.   if hdrver > arcver then begin
  397.     fread(name, fnlen);
  398.     writeln('I dont know how to handle file ', fn_to_str(name),
  399.             ' in archive ', arcname);
  400.     writeln('I think you need a newer version of DEARC.');
  401.     halt;
  402.     end;
  403.   if hdrver = 1 then begin
  404.     fread(hdr, sizeof(heads) - sizeof(longtype));
  405.     hdrver := 2;
  406.     hdr.length := hdr.size
  407.     end
  408.   else
  409.     fread(hdr, sizeof(heads));
  410.   readhdr := TRUE;
  411. end; (* func readhdr *)
  412.  
  413. procedure putc_unp(c : integer);
  414. begin
  415.   crcval := ((crcval shr 8) and $00FF) xor crctab[(crcval xor c) and $00FF];
  416.   put_ext(c)
  417. end; (* proc putc_unp *)
  418.  
  419. procedure putc_ncr(c : integer);
  420. begin
  421.   case state of
  422.     NOHIST : if c = DLE then
  423.                state := INREP
  424.              else begin
  425.                lastc := c;
  426.                putc_unp(c)
  427.                end;
  428.     INREP  : begin
  429.              if c = 0 then
  430.                putc_unp(DLE)
  431.              else begin
  432.                c := c - 1;
  433.                while (c <> 0) do begin
  434.                  putc_unp(lastc);
  435.                  c := c - 1
  436.                  end
  437.                end;
  438.              state := NOHIST
  439.              end;
  440.     end; (* case *)
  441. end; (* proc putc_ncr *)
  442.  
  443. function getc_unp : integer;
  444. begin
  445.   if size = 0.0 then
  446.     getc_unp := -1
  447.   else begin
  448.     size := size - 1.0;
  449.     getc_unp := get_arc
  450.     end;
  451. end; (* func getc_unp *)
  452.  
  453. procedure init_usq;
  454. { initialize for unsqueeze }
  455. var i : integer;
  456. begin
  457.   bpos := 99;
  458.   fread(numnodes, sizeof(numnodes));
  459.   if (numnodes < 0) or (numnodes > NUMVALS) then
  460.     abortme('File has an invalid decode tree');
  461.   node[0].child[0] := -(SPEOF + 1);
  462.   node[0].child[1] := -(SPEOF + 1);
  463.   for i := 0 to numnodes-1 do begin
  464.     fread(node[i].child[0], sizeof(integer));
  465.     fread(node[i].child[1], sizeof(integer))
  466.     end;
  467. end; (* proc init_usq; *)
  468.  
  469. function getc_usq : integer;
  470. { unsqueeze }
  471. var i : integer;
  472. begin
  473.   i := 0;
  474.   while i >= 0 do begin
  475.     bpos := bpos + 1;
  476.     if bpos > 7 then begin
  477.       curin := getc_unp;
  478.       if curin = ERROR then begin
  479.         getc_usq := ERROR;
  480.         exit;
  481.         end;
  482.       bpos := 0;
  483.       i := node[i].child[1 and curin]
  484.       end
  485.     else begin
  486.       curin := curin shr 1;
  487.       i := node[i].child[1 and curin]
  488.       end
  489.     end; (* while *)
  490.   i := - (i + 1);
  491.   if i = SPEOF then
  492.     getc_usq := -1
  493.   else
  494.     getc_usq := i;
  495. end; (* func getc_usq *)
  496.  
  497. function h(pred, foll : integer) : integer;
  498. { calculate hash value }
  499. { thanks to Bela Lubkin }
  500. var Local : Real;
  501.     S     : String[20];
  502.     I, V  : integer;
  503.     C     : char;
  504. begin
  505. if not newhash then
  506. begin
  507.   Local := (pred + foll) or $0800;
  508.   if Local < 0.0 then
  509.     Local := Local + 65536.0;
  510.   Local := (Local * Local) / 64.0;
  511. { convert Local to an integer, truncating high order bits. }
  512. { there ***MUST*** be a better way to do this!!! }
  513.   Str(Local:15:5, S);
  514.   V := 0;
  515.   I := 1;
  516.   C := S[1];
  517.   while C <> '.' do begin
  518.     if (C >= '0') and (C <= '9') then
  519.       V := V * 10 + (Ord(C) - Ord('0'));
  520.     I := I + 1;
  521.     C := S[I]
  522.     end;
  523.   h := V and $0FFF
  524. end (* func h *)
  525. else
  526. begin
  527.   Local := (pred + foll) * 15073;
  528. { convert Local to an integer, truncating high order bits. }
  529. { there ***MUST*** be a better way to do this!!! }
  530.   Str(Local:15:5, S);
  531.   V := 0;
  532.   I := 1;
  533.   C := S[1];
  534.   while C <> '.' do begin
  535.     if (C >= '0') and (C <= '9') then
  536.       V := V * 10 + (Ord(C) - Ord('0'));
  537.     I := I + 1;
  538.     C := S[I]
  539.     end;
  540.   h := V and $0FFF
  541. end;
  542. end;
  543.  
  544. function eolist(index : integer) : integer;
  545. var temp : integer;
  546. begin
  547.   temp := string_tab[index].next;
  548.   while temp <> 0 do begin
  549.     index := temp;
  550.     temp := string_tab[index].next
  551.     end;
  552.   eolist := index
  553. end; (* func eolist *)
  554.  
  555. function hash(pred, foll : integer) : integer;
  556. var local     : integer;
  557.     tempnext  : integer;
  558. begin
  559.   local := h(pred, foll);
  560.   if not string_tab[local].used then
  561.     hash := local
  562.   else begin
  563.     local := eolist(local);
  564.     tempnext := (local + 101) and $0FFF;
  565.     while string_tab[tempnext].used do begin
  566.       tempnext := tempnext + 1;
  567.       if tempnext = TABSIZE then
  568.         tempnext := 0
  569.       end;
  570.     string_tab[local].next := tempnext;
  571.     hash := tempnext
  572.     end;
  573. end; (* func hash *)
  574.  
  575. procedure upd_tab(pred, foll : integer);
  576. begin
  577.   with string_tab[hash(pred, foll)] do begin
  578.     used := TRUE;
  579.     next := 0;
  580.     predecessor := pred;
  581.     follower := foll
  582.     end
  583. end; (* proc upd_tab *)
  584.  
  585. function gocode : integer;
  586. var localbuf  : integer;
  587.     returnval : integer;
  588. begin
  589.   if inbuf = EMPTY then begin
  590.     localbuf := getc_unp;
  591.     if localbuf = -1 then begin
  592.       gocode := -1;
  593.       exit;
  594.       end;
  595.     localbuf := localbuf and $00FF;
  596.     inbuf := getc_unp;
  597.     if inbuf = -1 then begin
  598.       gocode := -1;
  599.       exit;
  600.       end;
  601.     inbuf := inbuf and $00FF;
  602.     returnval := ((localbuf shl 4) and $0FF0) + ((inbuf shr 4) and $000F);
  603.     inbuf := inbuf and $000F
  604.     end
  605.   else begin
  606.     localbuf := getc_unp;
  607.     if localbuf = -1 then begin
  608.       gocode := -1;
  609.       exit;
  610.       end;
  611.     localbuf := localbuf and $00FF;
  612.     returnval := localbuf + ((inbuf shl 8) and $0F00);
  613.     inbuf := EMPTY
  614.     end;
  615.   gocode := returnval;
  616. end; (* func gocode *)
  617.  
  618. procedure push(c : integer);
  619. begin
  620.   stack[sp] := c;
  621.   sp := sp + 1;
  622.   if sp >= TABSIZE then
  623.     abortme('Stack overflow')
  624. end; (* proc push *)
  625.  
  626. function pop : integer;
  627. begin
  628.   if sp > 0 then begin
  629.     sp := sp - 1;
  630.     pop := stack[sp]
  631.   end else
  632.     pop := EMPTY
  633. end; (* func pop *)
  634.  
  635. procedure init_tab;
  636. var i : integer;
  637. begin
  638.   FillChar(string_tab, sizeof(string_tab), 0);
  639.   for i := 0 to 255 do
  640.     upd_tab(NO_PRED, i);
  641.   inbuf := EMPTY;
  642.   { outbuf := EMPTY }
  643. end; (* proc init_tab *)
  644.  
  645. procedure init_ucr(i:integer);
  646. begin
  647.   newhash := i = 1;
  648.   sp := 0;
  649.   init_tab;
  650.   code_count := TABSIZE - 256;
  651.   firstc := TRUE
  652. end; (* proc init_ucr *)
  653.  
  654. function getc_ucr : integer;
  655. var c       : integer;
  656.     code    : integer;
  657.     newcode : integer;
  658. begin
  659.   if firstc then begin
  660.     firstc := FALSE;
  661.     oldcode := gocode;
  662.     finchar := string_tab[oldcode].follower;
  663.     getc_ucr := finchar;
  664.     exit;
  665.     end;
  666.   if sp = 0 then begin
  667.     newcode := gocode;
  668.     code := newcode;
  669.     if code = -1 then begin
  670.       getc_ucr := -1;
  671.       exit;
  672.       end;
  673.     if not string_tab[code].used then begin
  674.       code := oldcode;
  675.       push(finchar)
  676.       end;
  677.     while string_tab[code].predecessor <> NO_PRED do
  678.       with string_tab[code] do begin
  679.         push(follower);
  680.         code := predecessor
  681.         end;
  682.     finchar := string_tab[code].follower;
  683.     push(finchar);
  684.     if code_count <> 0 then begin
  685.       upd_tab(oldcode, finchar);
  686.       code_count := code_count - 1
  687.       end;
  688.     oldcode := newcode
  689.     end;
  690.   getc_ucr := pop;
  691. end; (* func getc_ucr *)
  692.  
  693. function getcode : integer;
  694. label
  695.   next;
  696. var
  697.   code, r_off, bitsx : integer;
  698.   bp : byte;
  699. begin
  700.   if firstch then
  701.   begin
  702.     offset := 0;
  703.     sizex := 0;
  704.     firstch := false;
  705.   end;
  706.   bp := 0;
  707.   if (clear_flg > 0) or (offset >= sizex) or (free_ent > maxcode) then
  708.   begin
  709.     if free_ent > maxcode then
  710.     begin
  711.       n_bits := n_bits + 1;
  712.       if n_bits = BITS then
  713.         maxcode := maxcodemax
  714.       else
  715.         maxcode := (1 shl n_bits) - 1;
  716.     end;
  717.     if clear_flg > 0 then
  718.     begin
  719.       n_bits := INIT_BITS;
  720.       maxcode := (1 shl n_bits) - 1;
  721.       clear_flg := 0;
  722.     end;
  723.     for sizex := 0 to n_bits-1 do
  724.     begin
  725.       code := getc_unp;
  726.       if code = -1 then
  727.         goto next
  728.       else
  729.         buf[sizex] := code;
  730.     end;
  731.     sizex := sizex + 1;
  732. next:
  733.     if sizex <= 0 then
  734.     begin
  735.       getcode := -1;
  736.       exit;
  737.     end;
  738.     offset := 0;
  739.     sizex := (sizex shl 3) - (n_bits - 1);
  740.   end;
  741.   r_off := offset;
  742.   bitsx := n_bits;
  743.  
  744.   { get first byte }
  745.   bp := bp + (r_off shr 3);
  746.   r_off := r_off and 7;
  747.  
  748.   { get first parft (low order bits) }
  749.   code := buf[bp] shr r_off;
  750.   bp := bp + 1;
  751.   bitsx := bitsx - (8 - r_off);
  752.   r_off := 8 - r_off;
  753.  
  754.   if bitsx >= 8 then
  755.   begin
  756.     code := code or (buf[bp] shl r_off);
  757.     bp := bp + 1;
  758.     r_off := r_off + 8;
  759.     bitsx := bitsx - 8;
  760.   end;
  761.  
  762.   code := code or ((buf[bp] and rmask[bitsx]) shl r_off);
  763.   offset := offset + n_bits;
  764.   getcode := code;
  765. end;
  766.  
  767. procedure decomp(    SquashFlag : Integer);
  768. label
  769.   next;
  770. var
  771.   stackp,
  772.   finchar :integer;
  773.   code, oldcode, incode : integer;
  774.  
  775. begin
  776.   { INIT var }
  777.   if SquashFlag = 0 then
  778.      Bits := crunch_BITS
  779.   else
  780.      Bits := squash_BITS;
  781.  
  782.   if firstch then
  783.     maxcodemax := 1 shl bits;
  784.  
  785.   If SquashFlag = 0 then begin
  786.      code := getc_unp;
  787.      if code <> BITS then
  788.      begin
  789.        Writeln('File packed with ', Code, ' bits, I can only handle ', Bits);
  790.        Halt;
  791.      end;
  792.   end {if};
  793.   clear_flg := 0;
  794.   n_bits := INIT_BITS;
  795.   maxcode := (1 shl n_bits ) - 1;
  796.   for code := 255 downto 0 do
  797.   begin
  798.     prefix[code] := 0;
  799.     suffix[code] := code;
  800.   end;
  801.  
  802.   free_ent := FIRST;
  803.   oldcode := getcode;
  804.   finchar := oldcode;
  805.   if oldcode = -1 then
  806.     exit;
  807.   if SquashFlag = 0 then
  808.      putc_ncr(finchar)
  809.   else
  810.      putc_unp(finchar);
  811.   stackp := 0;
  812.  
  813.   code := getcode;
  814.   while (code  > -1) do begin
  815.     if code = CLEAR then
  816.     begin
  817.       for code := 255 downto 0 do
  818.         prefix[code] := 0;
  819.       clear_flg := 1;
  820.       free_ent := FIRST - 1;
  821.       code := getcode;
  822.       if code = -1 then
  823.         goto next;
  824.     end;
  825. next:
  826.     incode := code;
  827.     if code >= free_ent then
  828.     begin
  829.       stack1[stackp] := finchar;
  830.       stackp := stackp + 1;
  831.       code := oldcode;
  832.     end;
  833.     while (code >= 256) do begin
  834.       stack1[stackp] := suffix[code];
  835.       stackp := stackp + 1;
  836.       code := prefix[code];
  837.     end;
  838.     finchar := suffix[code];
  839.     stack1[stackp] := finchar;
  840.     stackp := stackp + 1;
  841.     repeat
  842.       stackp := stackp - 1;
  843.       If SquashFlag = 0 then
  844.          putc_ncr(stack1[stackp])
  845.       else
  846.          putc_unp(stack1[stackp]);
  847.     until stackp <= 0;
  848.     code := free_ent;
  849.     if code < maxcodemax then
  850.     begin
  851.       prefix[code] := oldcode;
  852.       suffix[code] := finchar;
  853.       free_ent := code + 1;
  854.     end;
  855.     oldcode := incode;
  856.     code := getcode;
  857.   end;
  858. end;
  859.  
  860. procedure unpack(var hdr : heads);
  861. var c : integer;
  862. begin
  863.   crcval  := 0;
  864.   size    := long_to_real(hdr.size);
  865.   state   := NOHIST;
  866.   FirstCh := TRUE;
  867.   case hdrver of
  868.     1, 2 : begin
  869.            c := getc_unp;
  870.            while c <> -1 do begin
  871.              putc_unp(c);
  872.              c := getc_unp
  873.              end
  874.            end;
  875.     3    : begin
  876.            c := getc_unp;
  877.            while c <> -1 do begin
  878.              putc_ncr(c);
  879.              c := getc_unp
  880.              end
  881.            end;
  882.     4    : begin
  883.            init_usq;
  884.            c := getc_usq;
  885.            while c <> -1 do begin
  886.              putc_ncr(c);
  887.              c := getc_usq
  888.              end
  889.            end;
  890.     5    : begin
  891.            init_ucr(0);
  892.            c := getc_ucr;
  893.            while c <> -1 do begin
  894.              putc_unp(c);
  895.              c := getc_ucr
  896.              end
  897.            end;
  898.     6    : begin
  899.            init_ucr(0);
  900.            c := getc_ucr;
  901.            while c <> -1 do begin
  902.              putc_ncr(c);
  903.              c := getc_ucr
  904.              end
  905.            end;
  906.     7    : begin
  907.            init_ucr(1);
  908.            c := getc_ucr;
  909.            while c <> -1 do begin
  910.              putc_ncr(c);
  911.              c := getc_ucr
  912.              end
  913.            end;
  914.     8    : begin
  915.              decomp(0);
  916.            end;
  917.     9    : begin
  918.              decomp(1);
  919.            end;
  920.     else
  921.            writeln('I dont know how to unpack file ', fn_to_str(hdr.name));
  922.            writeln('I think you need a newer version of DEARC');
  923.            fseek(long_to_real(hdr.size), 1);
  924.            exit;
  925.     end; (* case *)
  926.   if crcval <> hdr.crc then
  927.     writeln('WARNING: File ', fn_to_str(hdr.name), ' fails CRC check');
  928. end; (* proc unpack *)
  929.  
  930. procedure extract_file(var hdr : heads);
  931. begin
  932.   extname := fn_to_str(hdr.name);
  933.   writeln('Extracting file : ', extname);
  934.   open_ext;
  935.   unpack(hdr);
  936.   close_ext
  937. end; (* proc extract *)
  938.  
  939. procedure extarc;
  940. var hdr : heads;
  941. begin
  942.   open_arc;
  943.   while readhdr(hdr) do
  944.     extract_file(hdr);
  945.   close_arc
  946. end; (* proc extarc *)
  947.  
  948. procedure PrintHeading;
  949. begin
  950.   writeln;
  951.   writeln('Turbo Pascal DEARC Utility');
  952.   writeln('Version 3.01, 8/8/87');
  953.   writeln('Supports Phil Katz "squashed" files');
  954.   writeln;
  955. end; (* proc PrintHeading *)
  956.  
  957. begin
  958.   PrintHeading; { print a heading }
  959.   GetArcName;   { get the archive file name }
  960.   extarc;       { extract all files from the archive }
  961. end.
  962.  
  963.  
  964.