home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / COMPRESS / UNZIP12.ZIP / UNZ.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-03-13  |  20.2 KB  |  898 lines

  1.  
  2. (*
  3.  * Copyright 1987, 1989 Samuel H. Smith;  All rights reserved
  4.  *
  5.  * This is a component of the ProDoor System.
  6.  * Do not distribute modified versions without my permission.
  7.  * Do not remove or alter this notice or any other copyright notice.
  8.  * If you use this in your own program you must distribute source code.
  9.  * Do not use any of this in a commercial product.
  10.  *
  11.  *)
  12.  
  13. (*
  14.  * UnZip - A simple zipfile extract utility
  15.  *
  16.  *)
  17.  
  18. {$I+}    {I/O checking}
  19. {$N-}    {Numeric coprocessor}
  20. {$V-}    {Relaxes string typing}
  21. {$B-}    {Boolean complete evaluation}
  22. {$S-}    {Stack checking}
  23. {$R-}    {Range checking}
  24. {$D+}    {Global debug information}
  25. {$L+}    {Local debug information}
  26.  
  27. {$M 5000,0,0} {minstack,minheap,maxheap}
  28.  
  29. program UnZip;
  30.  
  31. Uses
  32.    Dos, Mdosio;
  33.  
  34. const
  35.    version = 'UnZip:  Zipfile Extract v1.1ß of 03-06-89;  (C) 1989 S.H.Smith';
  36.  
  37.  
  38.  
  39. (*
  40.  * ProZip2.int - ZIP file interface library      (2-15-89 shs)
  41.  *
  42.  * Data declarations for the archive text-view functions.
  43.  *
  44.  *)
  45.  
  46. (* ----------------------------------------------------------- *)
  47. (*
  48.  * ZIPfile layout declarations
  49.  *
  50.  *)
  51.  
  52. type
  53.    signature_type = longint;
  54.  
  55. const
  56.    local_file_header_signature = $04034b50;
  57.  
  58. type
  59.    local_file_header = record
  60.       version_needed_to_extract:    word;
  61.       general_purpose_bit_flag:     word;
  62.       compression_method:           word;
  63.       last_mod_file_time:           word;
  64.       last_mod_file_date:           word;
  65.       crc32:                        longint;
  66.       compressed_size:              longint;
  67.       uncompressed_size:            longint;
  68.       filename_length:              word;
  69.       extra_field_length:           word;
  70.    end;
  71.  
  72. const
  73.    central_file_header_signature = $02014b50;
  74.  
  75. type
  76.    central_directory_file_header = record
  77.       version_made_by:                 word;
  78.       version_needed_to_extract:       word;
  79.       general_purpose_bit_flag:        word;
  80.       compression_method:              word;
  81.       last_mod_file_time:              word;
  82.       last_mod_file_date:              word;
  83.       crc32:                           longint;
  84.       compressed_size:                 longint;
  85.       uncompressed_size:               longint;
  86.       filename_length:                 word;
  87.       extra_field_length:              word;
  88.       file_comment_length:             word;
  89.       disk_number_start:               word;
  90.       internal_file_attributes:        word;
  91.       external_file_attributes:        longint;
  92.       relative_offset_local_header:    longint;
  93.    end;
  94.  
  95. const
  96.    end_central_dir_signature = $06054b50;
  97.  
  98. type
  99.    end_central_dir_record = record
  100.       number_this_disk:                         word;
  101.       number_disk_with_start_central_directory: word;
  102.       total_entries_central_dir_on_this_disk:   word;
  103.       total_entries_central_dir:                word;
  104.       size_central_directory:                   longint;
  105.       offset_start_central_directory:           longint;
  106.       zipfile_comment_length:                   word;
  107.    end;
  108.  
  109.  
  110.  
  111. (* ----------------------------------------------------------- *)
  112. (*
  113.  * input file variables
  114.  *
  115.  *)
  116.  
  117. const
  118.    uinbufsize = 512;    {input buffer size}
  119. var
  120.    zipeof:      boolean;
  121.    csize:       longint;
  122.    cusize:      longint;
  123.    cmethod:     integer;
  124.    ctime:       word;
  125.    cdate:       word;
  126.    inbuf:       array[1..uinbufsize] of byte;
  127.    inpos:       integer;
  128.    incnt:       integer;
  129.    pc:          byte;
  130.    pcbits:      byte;
  131.    pcbitv:      byte;
  132.    zipfd:       dos_handle;
  133.    zipfn:       dos_filename;
  134.  
  135.  
  136.  
  137. (* ----------------------------------------------------------- *)
  138. (*
  139.  * output stream variables
  140.  *
  141.  *)
  142.  
  143. var
  144.    outbuf:      array[0..4096] of byte; {for rle look-back}
  145.    outpos:      longint;                {absolute position in outfile}
  146.    outcnt:      integer;
  147.    outfd:       dos_handle;
  148.    filename:    string;
  149.    extra:       string;
  150.  
  151.  
  152.  
  153. (* ----------------------------------------------------------- *)
  154.  
  155. type
  156.    Sarray = array[0..255] of string[64];
  157.  
  158. var
  159.    factor:     integer;
  160.    followers:  Sarray;
  161.    ExState:    integer;
  162.    C:          integer;
  163.    V:          integer;
  164.    Len:        integer;
  165.  
  166. const
  167.    hsize =     8192;
  168.  
  169. type
  170.    hsize_array_integer = array[0..hsize] of integer;
  171.    hsize_array_byte    = array[0..hsize] of byte;
  172.  
  173. var
  174.    prefix_of:  hsize_array_integer;
  175.    suffix_of:  hsize_array_byte;
  176.    stack:      hsize_array_byte;
  177.    stackp:     integer;
  178.  
  179.  
  180.  
  181. (*
  182.  * Zipfile input/output handlers
  183.  *
  184.  *)
  185.  
  186.  
  187. (* ------------------------------------------------------------- *)
  188. procedure skip_csize;
  189. begin
  190.    dos_lseek(zipfd,csize,seek_cur);
  191.    zipeof := true;
  192.    csize := 0;
  193.    incnt := 0;
  194. end;
  195.  
  196.  
  197. (* ------------------------------------------------------------- *)
  198. procedure ReadByte(var x: byte);
  199. begin
  200.    if incnt = 0 then
  201.    begin
  202.       if csize = 0 then
  203.       begin
  204.          zipeof := true;
  205.          exit;
  206.       end;
  207.  
  208.       inpos := sizeof(inbuf);
  209.       if inpos > csize then
  210.          inpos := csize;
  211.       incnt := dos_read(zipfd,inbuf,inpos);
  212.  
  213.       inpos := 1;
  214.       dec(csize,incnt);
  215.    end;
  216.  
  217.    x := inbuf[inpos];
  218.    inc(inpos);
  219.    dec(incnt);
  220. end;
  221.  
  222.  
  223. (*
  224.  * Copyright 1987, 1989 Samuel H. Smith;  All rights reserved
  225.  *
  226.  * This is a component of the ProDoor System.
  227.  * Do not distribute modified versions without my permission.
  228.  * Do not remove or alter this notice or any other copyright notice.
  229.  * If you use this in your own program you must distribute source code.
  230.  * Do not use any of this in a commercial product.
  231.  *
  232.  *)
  233.  
  234. (******************************************************
  235.  *
  236.  * Procedure:  itoh
  237.  *
  238.  * Purpose:    converts an integer into a string of hex digits
  239.  *
  240.  * Example:    s := itoh(i);
  241.  *
  242.  *)
  243.  
  244. function itoh(i: longint): string;   {integer to hex conversion}
  245. var
  246.    h:   string;
  247.    w:   word;
  248.  
  249.    procedure digit(ix: integer; ii: word);
  250.    begin
  251.       ii := ii and 15;
  252.       if ii > 9 then 
  253.          ii := ii + 7 + ord('a') - ord('A');
  254.       h[ix] := chr(ii + ord('0'));
  255.    end;
  256.  
  257. begin
  258.    w := i and $FFFF;
  259.    h[0] := chr(4);
  260.    digit(1,w shr 12);
  261.    digit(2,w shr 8);
  262.    digit(3,w shr 4);
  263.    digit(4,w);
  264.    itoh := h;   
  265. end;
  266.  
  267.  
  268. (* ------------------------------------------------------------- *)
  269. procedure ReadBits(bits: integer; var result: integer);
  270.    {read the specified number of bits}
  271. const
  272.    bit:     integer = 0;
  273.    bitv:    integer = 0;
  274.    x:       integer = 0;
  275. begin
  276.    x := 0;
  277.    bitv := 1;
  278.  
  279.    for bit := 0 to bits-1 do
  280.    begin
  281.  
  282.       if pcbits > 0 then
  283.       begin
  284.          dec(pcbits);
  285.          pcbitv := pcbitv shl 1;
  286.       end
  287.       else
  288.  
  289.       begin
  290.          ReadByte(pc);
  291.          pcbits := 7;
  292.          pcbitv := 1;
  293.       end;
  294.  
  295.       if (pc and pcbitv) <> 0 then
  296.          x := x or bitv;
  297.  
  298.       bitv := bitv shl 1;
  299.    end;
  300.  
  301. (* writeln(bits,'-',itoh(x)); *)
  302.    result := x;
  303. end;
  304.  
  305.  
  306. (* ---------------------------------------------------------- *)
  307. procedure get_string(ln: word; var s: string);
  308. var
  309.    n: word;
  310. begin
  311.    if ln > 255 then
  312.       ln := 255;
  313.    n := dos_read(zipfd,s[1],ln);
  314.    s[0] := chr(ln);
  315. end;
  316.  
  317.  
  318. (* ------------------------------------------------------------- *)
  319. procedure OutByte (c: integer);
  320.    (* output each character from archive to screen *)
  321. begin
  322.    outbuf[outcnt {outpos mod sizeof(outbuf)} ] := c;
  323.    inc(outpos);
  324.    inc(outcnt);
  325.  
  326.    if outcnt = sizeof(outbuf) then
  327.    begin
  328.       dos_write(outfd,outbuf,outcnt);
  329.       outcnt := 0;
  330.       write('.');
  331.    end;
  332. end;
  333.  
  334.  
  335. (*
  336.  * expand 'reduced' members of a zipfile
  337.  *
  338.  *)
  339.  
  340. (*
  341.  * The Reducing algorithm is actually a combination of two
  342.  * distinct algorithms.  The first algorithm compresses repeated
  343.  * byte sequences, and the second algorithm takes the compressed
  344.  * stream from the first algorithm and applies a probabilistic
  345.  * compression method.
  346.  *
  347.  *)
  348.  
  349. function reduce_L(x: byte): byte;
  350. begin
  351.    case factor of
  352.       1: reduce_L := x and $7f;
  353.       2: reduce_L := x and $3f;
  354.       3: reduce_L := x and $1f;
  355.       4: reduce_L := x and $0f;
  356.    end;
  357. end;
  358.  
  359. function reduce_F(x: byte): byte;
  360. begin
  361.    case factor of
  362.       1: if x = 127 then reduce_F := 2 else reduce_F := 3;
  363.       2: if x = 63  then reduce_F := 2 else reduce_F := 3;
  364.       3: if x = 31  then reduce_F := 2 else reduce_F := 3;
  365.       4: if x = 15  then reduce_F := 2 else reduce_F := 3;
  366.    end;
  367. end;
  368.  
  369. function reduce_D(x,y: byte): word;
  370. begin
  371.    case factor of
  372.       1: reduce_D := ((x shr 7) and $01) * 256 + Y + 1;
  373.       2: reduce_D := ((x shr 6) and $03) * 256 + Y + 1;
  374.       3: reduce_D := ((x shr 5) and $07) * 256 + Y + 1;
  375.       4: reduce_D := ((x shr 4) and $0f) * 256 + Y + 1;
  376.    end;
  377. end;
  378.  
  379. function reduce_B(x: byte): word;
  380.    {number of bits needed to encode the specified number}
  381. begin
  382.    case x-1 of
  383.       0..1:    reduce_B := 1;
  384.       2..3:    reduce_B := 2;
  385.       4..7:    reduce_B := 3;
  386.       8..15:   reduce_B := 4;
  387.      16..31:   reduce_B := 5;
  388.      32..63:   reduce_B := 6;
  389.      64..127:  reduce_B := 7;
  390.    else        reduce_B := 8;
  391.    end;
  392. end;
  393.  
  394. procedure Expand(c: byte);
  395. const
  396.    DLE = 144;
  397. var
  398.    op:   longint;
  399.    i:    integer;
  400.  
  401. begin
  402.  
  403.    case ExState of
  404.         0:  if C <> DLE then
  405.                 outbyte(C)
  406.             else
  407.                 ExState := 1;
  408.  
  409.         1:  if C <> 0 then
  410.             begin
  411.                 V := C;
  412.                 Len := reduce_L(V);
  413.                 ExState := reduce_F(Len);
  414.             end
  415.             else
  416.             begin
  417.                 outbyte(DLE);
  418.                 ExState := 0;
  419.             end;
  420.  
  421.         2:  begin
  422.                Len := Len + C;
  423.                ExState := 3;
  424.             end;
  425.  
  426.         3:  begin
  427.                op := outpos-reduce_D(V,C);
  428.                for i := 0 to Len+2 do
  429.                begin
  430.                   if op < 0 then
  431.                      outbyte(0)
  432.                   else
  433.                      outbyte(outbuf[op mod sizeof(outbuf)]);
  434.                   inc(op);
  435.                end;
  436.  
  437.                ExState := 0;
  438.             end;
  439.    end;
  440. end;
  441.  
  442.  
  443. procedure LoadFollowers;
  444. var
  445.    x: integer;
  446.    i: integer;
  447.    b: integer;
  448. begin
  449.    for x := 255 downto 0 do
  450.    begin
  451.       ReadBits(6,b);
  452.       followers[x][0] := chr(b);
  453.  
  454.       for i := 1 to length(followers[x]) do
  455.       begin
  456.          ReadBits(8,b);
  457.          followers[x][i] := chr(b);
  458.       end;
  459.    end;
  460. end;
  461.  
  462.  
  463. (* ----------------------------------------------------------- *)
  464. procedure unReduce;
  465.    {expand probablisticly reduced data}
  466.  
  467. var
  468.    lchar:   integer;
  469.    lout:    integer;
  470.    I:       integer;
  471.  
  472. begin
  473.    factor := cmethod - 1;
  474.    if (factor < 1) or (factor > 4) then
  475.    begin
  476.       skip_csize;
  477.       exit;
  478.    end;
  479.  
  480.    ExState := 0;
  481.    LoadFollowers;
  482.    lchar := 0;
  483.  
  484.    while (not zipeof) and (outpos < cusize) do
  485.    begin
  486.  
  487.       if followers[lchar] = '' then
  488.          ReadBits( 8,lout )
  489.       else
  490.  
  491.       begin
  492.          ReadBits(1,lout);
  493.          if lout <> 0 then
  494.             ReadBits( 8,lout )
  495.          else
  496.          begin
  497.             ReadBits( reduce_B(length(followers[lchar])), I );
  498.             lout := ord( followers[lchar][I+1] );
  499.          end;
  500.       end;
  501.  
  502.       if zipeof then
  503.          exit;
  504.  
  505.       Expand( lout );
  506.       lchar := lout;
  507.    end;
  508.  
  509. end;
  510.  
  511.  
  512.  
  513. (*
  514.  * expand 'shrunk' members of a zipfile
  515.  *
  516.  *)
  517.  
  518. (*
  519.  * UnShrinking
  520.  * -----------
  521.  *
  522.  * Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
  523.  * with partial clearing.  The initial code size is 9 bits, and
  524.  * the maximum code size is 13 bits.  Shrinking differs from
  525.  * conventional Dynamic Ziv-lempel-Welch implementations in several
  526.  * respects:
  527.  *
  528.  * 1)  The code size is controlled by the compressor, and is not
  529.  *     automatically increased when codes larger than the current
  530.  *     code size are created (but not necessarily used).  When
  531.  *     the decompressor encounters the code sequence 256
  532.  *     (decimal) followed by 1, it should increase the code size
  533.  *     read from the input stream to the next bit size.  No
  534.  *     blocking of the codes is performed, so the next code at
  535.  *     the increased size should be read from the input stream
  536.  *     immediately after where the previous code at the smaller
  537.  *     bit size was read.  Again, the decompressor should not
  538.  *     increase the code size used until the sequence 256,1 is
  539.  *     encountered.
  540.  *
  541.  * 2)  When the table becomes full, total clearing is not
  542.  *     performed.  Rather, when the compresser emits the code
  543.  *     sequence 256,2 (decimal), the decompressor should clear
  544.  *     all leaf nodes from the Ziv-Lempel tree, and continue to
  545.  *     use the current code size.  The nodes that are cleared
  546.  *     from the Ziv-Lempel tree are then re-used, with the lowest
  547.  *     code value re-used first, and the highest code value
  548.  *     re-used last.  The compressor can emit the sequence 256,2
  549.  *     at any time.
  550.  *
  551.  *)
  552.  
  553. procedure unShrink;
  554.  
  555. const
  556.    max_bits =  13;
  557.    init_bits = 9;
  558.    first_ent = 257;
  559.    clear =     256;
  560.    
  561. var
  562.    cbits:      integer;
  563.    maxcode:    integer;
  564.    free_ent:   integer;
  565.    maxcodemax: integer;
  566.    offset:     integer;
  567.    sizex:      integer;
  568.    finchar:    integer;
  569.    code:       integer;
  570.    oldcode:    integer;
  571.    incode:     integer;
  572.  
  573.  
  574. (* ------------------------------------------------------------- *)
  575. procedure partial_clear;
  576. var
  577.    pr:   integer;
  578.    cd:   integer;
  579.  
  580. begin
  581.    {mark all nodes as potentially unused}
  582.    for cd := first_ent to free_ent-1 do
  583.       word(prefix_of[cd]) := prefix_of[cd] or $8000;
  584.  
  585.  
  586.    {unmark those that are used by other nodes}
  587.    for cd := first_ent to free_ent-1 do
  588.    begin
  589.       pr := prefix_of[cd] and $7fff;    {reference to another node?}
  590.       if pr >= first_ent then           {flag node as referenced}
  591.          prefix_of[pr] := prefix_of[pr] and $7fff;
  592.    end;
  593.  
  594.  
  595.    {clear the ones that are still marked}
  596.    for cd := first_ent to free_ent-1 do
  597.       if (prefix_of[cd] and $8000) <> 0 then
  598.          prefix_of[cd] := -1;
  599.  
  600.  
  601.    {find first cleared node as next free_ent}
  602.    free_ent := first_ent;
  603.    while (free_ent < maxcodemax) and (prefix_of[free_ent] <> -1) do
  604.       inc(free_ent);
  605. end;
  606.  
  607.  
  608. (* ------------------------------------------------------------- *)
  609. begin
  610.    (* decompress the file *)
  611.    maxcodemax := 1 shl max_bits;
  612.    cbits := init_bits;
  613.    maxcode := (1 shl cbits)- 1;
  614.    free_ent := first_ent;
  615.    offset := 0;
  616.    sizex := 0;
  617.  
  618.    fillchar(prefix_of,sizeof(prefix_of),$FF);
  619.    for code := 255 downto 0 do
  620.    begin
  621.       prefix_of[code] := 0;
  622.       suffix_of[code] := code;
  623.    end;
  624.  
  625.    ReadBits(cbits,oldcode);
  626.    if zipeof then
  627.       exit;
  628.    finchar := oldcode;
  629.  
  630.    OutByte(finchar);
  631.  
  632.    stackp := 0;
  633.  
  634.    while (not zipeof) do
  635.    begin
  636.       ReadBits(cbits,code);
  637.       if zipeof then
  638.          exit;
  639.  
  640.       while (code = clear) do
  641.       begin
  642.          ReadBits(cbits,code);
  643.  
  644.          case code of
  645.             1: begin
  646.                   inc(cbits);
  647.                   if cbits = max_bits then
  648.                      maxcode := maxcodemax
  649.                   else
  650.                      maxcode := (1 shl cbits) - 1;
  651.                end;
  652.  
  653.             2: partial_clear;
  654.          end;
  655.  
  656.          ReadBits(cbits,code);
  657.          if zipeof then
  658.             exit;
  659.       end;
  660.  
  661.  
  662.       {special case for KwKwK string}
  663.       incode := code;
  664.       if prefix_of[code] = -1 then
  665.       begin
  666.          stack[stackp] := finchar;
  667.          inc(stackp);
  668.          code := oldcode;
  669.       end;
  670.  
  671.  
  672.       {generate output characters in reverse order}
  673.       while (code >= first_ent) do
  674.       begin
  675.          stack[stackp] := suffix_of[code];
  676.          inc(stackp);
  677.          code := prefix_of[code];
  678.       end;
  679.  
  680.       finchar := suffix_of[code];
  681.       stack[stackp] := finchar;
  682.       inc(stackp);
  683.  
  684.  
  685.       {and put them out in forward order}
  686.       while (stackp > 0) do
  687.       begin
  688.          dec(stackp);
  689.          OutByte(stack[stackp]);
  690.       end;
  691.  
  692.  
  693.       {generate new entry}
  694.       code := free_ent;
  695.       if code < maxcodemax then
  696.       begin
  697.          prefix_of[code] := oldcode;
  698.          suffix_of[code] := finchar;
  699.          while (free_ent < maxcodemax) and (prefix_of[free_ent] <> -1) do
  700.             inc(free_ent);
  701.       end;
  702.  
  703.  
  704.       {remember previous code}
  705.       oldcode := incode;
  706.    end;
  707.  
  708. end;
  709.  
  710.  
  711.  
  712. (*
  713.  * ProZip2.int - ZIP file interface library      (2-15-89 shs)
  714.  *
  715.  * This procedure displays the text contents of a specified archive
  716.  * file.  The filename must be fully specified and verified.
  717.  *
  718.  *)
  719.  
  720.  
  721. (* ---------------------------------------------------------- *)
  722. procedure extract_member;
  723. var
  724.    b: byte;
  725.  
  726. begin
  727.    pcbits := 0;
  728.    incnt := 0;
  729.    outpos := 0;
  730.    outcnt := 0;
  731.    zipeof := false;
  732.  
  733.    outfd := dos_create(filename);
  734.    if outfd = dos_error then
  735.    begin
  736.       writeln('Can''t create output: ', filename);
  737.       halt;
  738.    end;
  739.  
  740.    case cmethod of
  741.       0:    {stored}
  742.             begin
  743.                write(' Extract: ',filename,' ...');
  744.                while (not zipeof) do
  745.                begin
  746.                   ReadByte(b);
  747.                   OutByte(b);
  748.                end;
  749.             end;
  750.  
  751.       1:    begin
  752.                write('UnShrink: ',filename,' ...');
  753.                UnShrink;
  754.             end;
  755.  
  756.       2..5: begin
  757.                write('  Expand: ',filename,' ...');
  758.                UnReduce;
  759.             end;
  760.  
  761.       else  write('Unknown compression method.');
  762.    end;
  763.  
  764.    if outcnt > 0 then
  765.       dos_write(outfd,outbuf,outcnt);
  766.  
  767.    dos_file_times(outfd,time_set,ctime,cdate);
  768.    dos_close(outfd);
  769.  
  770.    writeln('  done.');
  771. end;
  772.  
  773.  
  774. (* ---------------------------------------------------------- *)
  775. procedure process_local_file_header;
  776. var
  777.    n:             word;
  778.    rec:           local_file_header;
  779.  
  780. begin
  781.    n := dos_read(zipfd,rec,sizeof(rec));
  782.    get_string(rec.filename_length,filename);
  783.    get_string(rec.extra_field_length,extra);
  784.    csize := rec.compressed_size;
  785.    cusize := rec.uncompressed_size;
  786.    cmethod := rec.compression_method;
  787.    ctime := rec.last_mod_file_time;
  788.    cdate := rec.last_mod_file_date;
  789.    extract_member;
  790. end;
  791.  
  792.  
  793. (* ---------------------------------------------------------- *)
  794. procedure process_central_file_header;
  795. var
  796.    n:             word;
  797.    rec:           central_directory_file_header;
  798.    filename:      string;
  799.    extra:         string;
  800.    comment:       string;
  801.  
  802. begin
  803.    n := dos_read(zipfd,rec,sizeof(rec));
  804.    get_string(rec.filename_length,filename);
  805.    get_string(rec.extra_field_length,extra);
  806.    get_string(rec.file_comment_length,comment);
  807. end;
  808.  
  809.  
  810. (* ---------------------------------------------------------- *)
  811. procedure process_end_central_dir;
  812. var
  813.    n:             word;
  814.    rec:           end_central_dir_record;
  815.    comment:       string;
  816.  
  817. begin
  818.    n := dos_read(zipfd,rec,sizeof(rec));
  819.    get_string(rec.zipfile_comment_length,comment);
  820. end;
  821.  
  822.  
  823. (* ---------------------------------------------------------- *)
  824. procedure process_headers;
  825. var
  826.    sig:  longint;
  827.  
  828. begin
  829.    dos_lseek(zipfd,0,seek_start);
  830.  
  831.    while true do
  832.    begin
  833.       if dos_read(zipfd,sig,sizeof(sig)) <> sizeof(sig) then
  834.          exit
  835.       else
  836.  
  837.       if sig = local_file_header_signature then
  838.          process_local_file_header
  839.       else
  840.  
  841.       if sig = central_file_header_signature then
  842.          process_central_file_header
  843.       else
  844.  
  845.       if sig = end_central_dir_signature then
  846.       begin
  847.          process_end_central_dir;
  848.          exit;
  849.       end
  850.  
  851.       else
  852.       begin
  853.          writeln('Invalid Zipfile Header');
  854.          exit;
  855.       end;
  856.    end;
  857.  
  858. end;
  859.  
  860.  
  861. (* ---------------------------------------------------------- *)
  862. procedure extract_zipfile;
  863. begin
  864.    zipfd := dos_open(zipfn,open_read);
  865.    if zipfd = dos_error then
  866.       exit;
  867.  
  868.    process_headers;
  869.  
  870.    dos_close(zipfd);
  871. end;
  872.  
  873.  
  874. (*
  875.  * main program
  876.  *
  877.  *)
  878.  
  879. begin
  880.    writeln;
  881.    writeln(version);
  882.    writeln('Courtesy of:  S.H.Smith  and  The Tool Shop BBS,  (602) 279-2673.');
  883.    writeln;
  884.    if paramcount <> 1 then
  885.    begin
  886.       writeln('Usage:  UnZip FILE[.zip]');
  887.       halt;
  888.    end;
  889.  
  890.    zipfn := paramstr(1);
  891.    if pos('.',zipfn) = 0 then
  892.       zipfn := zipfn + '.ZIP';
  893.  
  894.    extract_zipfile;
  895. end.
  896.  
  897.  
  898.