home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / ECO30603.ZIP / ECO30603.LZH / ECOLIBII / ECO_CFI.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-06-26  |  52.5 KB  |  1,554 lines

  1. {
  2.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  3.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  4.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  5.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  6.     ▓▓▓▓▓▓▓▓·──                                              ──·▓▓▓▓▓▓▓▓▓▓▓
  7.     ▓▓▓▓▓▓▓▓│                                                  │░░▓▓▓▓▓▓▓▓▓
  8.     ▓▓▓▓▓▓▓▓   Unit was conceived, designed and written         ░░▓▓▓▓▓▓▓▓▓
  9.     ▓▓▓▓▓▓▓▓   by Floor A.C. Naaijkens for                      ░░▓▓▓▓▓▓▓▓▓
  10.     ▓▓▓▓▓▓▓▓   UltiHouse Software / The ECO Group.              ░░▓▓▓▓▓▓▓▓▓
  11.     ▓▓▓▓▓▓▓▓                                                    ░░▓▓▓▓▓▓▓▓▓
  12.     ▓▓▓▓▓▓▓▓   (C) MCMXCII by EUROCON PANATIONAL CORPORATION.   ░░▓▓▓▓▓▓▓▓▓
  13.     ▓▓▓▓▓▓▓▓   All Rights Reserved for The ECO Group.           ░░▓▓▓▓▓▓▓▓▓
  14.     ▓▓▓▓▓▓▓▓                                                    ░░▓▓▓▓▓▓▓▓▓
  15.     ▓▓▓▓▓▓▓▓│                                                  │░░▓▓▓▓▓▓▓▓▓
  16.     ▓▓▓▓▓▓▓▓·──                                              ──·░░▓▓▓▓▓▓▓▓▓
  17.     ▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓▓▓▓▓
  18.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  19.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  20.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  21. }
  22. (*
  23.  
  24.          ┌────────────────[ File Information Report ]────────────────┐
  25.          │                                                           │
  26.          │   Sourcefile for The Fast Commander, V3.51 and higher.    │
  27.          │   All material is protected and licensed.                 │
  28.          │   (C) Copyright 1992 by EUROCON PANATIONAL CORPORATION.   │
  29.          │   Written exclusively by Floor Naaijkens for              │
  30.          │   UltiHouse Software / The ECO Group All Rights Reserved. │
  31.          │   See various documentory files for further information   │
  32.          │   on how to handle these files.                           │
  33.          │                                                           │
  34.          │   Filename:      ECO_CFI.PAS                              │
  35.          │   Version:       3.51                                     │
  36.          │   Last change:   02-05-91  14:14                          │
  37.          │   Dependencies:  FIL·, EXT·, MEM·, SCN·, DOS·, ····,      │
  38.          │                  ····, ····, ····, ····, ····, ····.      │
  39.          │                                                           │
  40.          └───────────────────────────────────────────────────────────┘
  41.  
  42. *)
  43. {$I-,V-,F+,O+,D-,L-}
  44. unit ECO_cfi; { cfi = compression file interface }
  45.  
  46. interface
  47. uses 
  48.   dos
  49.   
  50.   ;
  51.  
  52. const 
  53.   cfismartmode : boolean = false; { niet verder zoeken na geen hit }
  54.   cfisfx       : boolean = false; {       niet in exe & com kijken }
  55.  
  56. type 
  57.   cfityperecord = record
  58.     cfiname      : string[67]; {filename only 12 chars!!!!!} {even meer !!}
  59.     cfipath      : string[67]; {directory if used}
  60.     cficrc       : longint;    {crc check}
  61.     cfipsize     : longint;    {packed size file}
  62.     cfiosize     : longint;    {original size file}
  63.     cfitime      : longint;    {dos packed time}
  64.     cfiattr      : byte;       {zip and lzh/lzs only}
  65.     cfimethod    : word;       {soort compressie}
  66.     cfiptotal    : longint;    {total packed size}
  67.     cfiototal    : longint;    {total original size}
  68.   end;
  69.   str79          = string[79];
  70.   str8           = string[8];
  71.  
  72.  
  73. var 
  74.   cfierror          : boolean;
  75.   cfifile           : file;                          { used by all routines }
  76.   cfipos            : longint;               { position where info begins!! }
  77.   cfifilename       : str79;
  78.   cfitype           : cfityperecord;
  79.   cfityp            : byte;                { type archive : zoo, arc, lzh etc }
  80.   readcentralheader : boolean; { read also zip central header default false }
  81.  
  82.  
  83.  
  84.   procedure closecfi;
  85.   function opencfifile(f : str79) : boolean;
  86.   function cfinext : boolean;
  87.   function dectohex(l : longint;cfityp : byte) : str8;
  88.  
  89.  
  90.  
  91. implementation
  92.  
  93. const 
  94.   arc = 1;
  95.   zip = 2;
  96.   lzh = 3;
  97.   zoo = 4;
  98.   dwc = 5;
  99.   lbr = 6;
  100.   arj = 7;
  101.  
  102.  
  103. type 
  104.   dataarray = array [1..512] of byte;
  105.  
  106.  
  107. var 
  108.   { heeft groote van de stap die genomen moet worden }
  109.   internal_stap               :   longint;
  110.   {   }
  111.   internal_centralheaderfound :   boolean;
  112.   { voor bekijken of een file die file wel is }
  113.   data                        : dataarray;
  114.   {  # bytes read from zoo file               }
  115.   bytes_read                  :      word;
  116.   cfinextproc                 : procedure;
  117.  
  118.  
  119.  
  120. procedure cfinextempty;
  121. begin
  122.   cfierror := true;
  123. end;
  124.  
  125.  
  126. procedure uppercase(var f : string);
  127. var 
  128.   loop : byte;
  129.   len  : byte absolute f;
  130.  
  131. begin
  132.   for loop := 1 to len do f[loop] := upcase(f[loop]);
  133. end;
  134.  
  135.  
  136. const archive_marker        = 26      {  marks start of an archive header   };
  137.  
  138.  
  139.  
  140. procedure cfinextarc;
  141. { ---------------------------------------------------------------------- }
  142. {                   map of archive file entry header                     }
  143. { ---------------------------------------------------------------------- }
  144.  
  145. const 
  146.   archive_header_length = 29      {  length of an archive header entry  };
  147.   max_subdirs           = 20      {  maximum number of nested subdirs   };
  148.  
  149. type 
  150.   fnametype = array[1..13] of char;
  151.  
  152.   arc_entry_type = record
  153.     marker   : byte      {  flags beginning of entry  };
  154.     version  : byte      {  compression method        };
  155.     filename : fnametype {  file and extension        };
  156.     size     : longint   {  compressed size           };
  157.     date     : word      {  packed date               };
  158.     time     : word      {  packed time               };
  159.     crc      : word      {  cyclic redundancy check   };
  160.     olength  : longint   {  original length           };
  161.   end;
  162.  
  163.     
  164. var {  header for one file in archive  }
  165.   arc_entry     : arc_entry_type absolute data;
  166.   {  nested directory names in       }
  167.   {  archive                         }
  168.   subdir_names  : array [1..max_subdirs] of string[13];
  169.   subdir_depth  : integer;             {  current subdirectory in archive }
  170.   arcfilename   : string[79];          {  long file name              }
  171.   loop          : byte;
  172.   timedate      : longint;
  173.   timedatew     : array [1..2] of word absolute timedate;
  174.  
  175.  
  176.  
  177.   function convertmethod(m : word) : word;
  178.   var 
  179.     cm : word;
  180.  
  181.   begin
  182.     case m of
  183.       1 : cm := 1; {stored 1, file header lacks length field, (sea)}
  184.       2 : cm := 2; {stored 2? (sea)}
  185.       3 : cm := 3; {crunched (sea)}
  186.       4 : cm := 4; {crunched (sea)}
  187.       5 : cm := 5; {crunched (sea)}
  188.       6 : cm := 6; {crunched (sea)}
  189.       7 : cm := 7; {crunched (sea)}
  190.       8 : cm := 8; {crunched (sea)}
  191.       9 : cm := 9; {squashed (only pkware)}
  192.      10 : cm := 10; {curshed (only nogate)}
  193.      11 : cm := 11; {distlled (only nogate)}
  194.      else cm := 255; {unknown}
  195.     end;
  196.     convertmethod := cm
  197.   end;
  198.  
  199.  
  200.  
  201.  
  202. begin
  203.   if cfierror then exit;
  204.   cfierror := true; {assume error}
  205.   seek(cfifile, cfipos+internal_stap);
  206.   if ioresult <> 0 then exit; {error}
  207.   blockread(cfifile, arc_entry, sizeof(arc_entry_type), bytes_read);
  208.   if ioresult <> 0 then exit;
  209.   if (bytes_read<2) or (bytes_read<>sizeof(arc_entry_type)) then exit;
  210.   if arc_entry.marker <> archive_marker then exit;
  211.  
  212. { internal_stap wordt afzonderlijk gezet aangezien lengte afhangt van version }
  213.   inc(cfipos, internal_stap); {dit is algemeen de stap niet!}
  214.   with arc_entry do case version of
  215.     0     : exit; {end of archive}
  216.     1..19 : begin {compressed file}
  217.       if (bytes_read<archive_header_length) then exit;
  218.       internal_stap := archive_header_length + size;
  219.  
  220.       { wat ben ik hier in gods naam aan het doen????? }
  221.       if version = 1 then begin
  222.         olength := size;
  223.         version := 2;
  224.         dec(internal_stap, 2);
  225.       end;
  226.     end;
  227.     30    : begin { subdirectory begins  }
  228.       if (bytes_read<archive_header_length) then exit;
  229.       internal_stap := archive_header_length;
  230.       if subdir_depth < max_subdirs then begin
  231.         inc(subdir_depth);
  232.         subdir_names[subdir_depth] := copy(filename, 1, 
  233.           pred(pos(#0, filename))
  234.         );
  235.       end;
  236.     end;
  237.     31    : begin {end of subdirectory}
  238.       { remove this subdirectory from current nesting }
  239.       if (subdir_depth>0) then dec(subdir_depth);
  240.       internal_stap := 2; {end of dir length}
  241.     end;
  242.     { if other version number just check for length en update internal_stap }
  243.     else begin
  244.       if (bytes_read<archive_header_length) then exit;
  245.       internal_stap := archive_header_length + size;
  246.     end;
  247.   end; { end of case }
  248.  
  249.  
  250.   cfitype.cfiname := copy(arc_entry.filename, 1, 
  251.     pred(pos(#0, arc_entry.filename))
  252.   );
  253.  
  254.  { nu subdirectory's nog aan elkaar breien als ze bestaan natuurlijk }
  255.  arcfilename := '';
  256.  if subdir_depth > 0 then begin
  257.    for loop := 1 to subdir_depth do
  258.      arcfilename := concat(arcfilename, subdir_names[loop], '\');
  259.    delete(arcfilename, length(arcfilename), 1); { del laatste char }
  260.  end;
  261.  cfitype.cfipath := arcfilename;
  262.  
  263.  with cfitype do begin
  264.    cfipsize  := arc_entry.size;
  265.    cfiosize  := arc_entry.olength;
  266.  
  267.    timedatew[1] := arc_entry.time;
  268.    timedatew[2] := arc_entry.date;
  269.    cfitime   := timedate;
  270.  
  271.    cficrc    := arc_entry.crc;
  272.    cfiattr   := 0; {geen info in arc files}
  273.    cfimethod := convertmethod(arc_entry.version);
  274.  end;
  275.  
  276.  cfierror := false;
  277. end;
  278.  
  279.  
  280.  
  281. function testforarc(var data : dataarray) : boolean;
  282. begin
  283.   testforarc := false;
  284.   if data[1] <> archive_marker then exit;
  285.   cfityp := arc;
  286.   testforarc := true;
  287. end;
  288.  
  289.  
  290.  
  291. const 
  292.   zip_local_header_signature    = $04034b50;
  293.  
  294.  
  295.  
  296.   procedure cfinextzip;
  297.   { ---------------------------------------------------------------------- }
  298.   {                map of zip file entry headers                           }
  299.   { ---------------------------------------------------------------------- }
  300.  
  301.   const 
  302.     zip_central_header_signature  = $02014b50;
  303.     zip_end_central_dir_signature = $06054b50;
  304.  
  305.   type {  structure of a local file header  }
  306.     zip_local_header_type = record
  307.       signature           : longint  {  header signature         };
  308.       version             : word     {  vers. needed to extract  };
  309.       bitflag             : word     {  general flags            };
  310.       compressionmethod   : word     {  compression type used    };
  311.       timedate            : longint  {  file creation time&date  };
  312.       crc32               : longint  {  32-bit crc of file       };
  313.       compressedsize      : longint  {  compressed size of file  };
  314.       uncompressedsize    : longint  {  original size of file    };
  315.       filenamelength      : word     {  length of file name      };
  316.       extrafieldlength    : word     {  length of extra stuff    };
  317.     end;
  318.  
  319.     {  structure of the central directory record  }
  320.     zip_central_header_type = record
  321.       signature           : longint {  header signature         };
  322.       versionmadeby       : word    {  system id/program vers.  };
  323.       versionneeded       : word    {  vers. needed to extract  };
  324.       bitflag             : word    {  general flags            };
  325.       compressionmethod   : word    {  compression type used    };
  326.       timedate            : longint {  file creation time&date  };
  327.       crc32               : longint {  32-bit crc of file       };
  328.       compressedsize      : longint {  compressed size of file  };
  329.       uncompressedsize    : longint {  original size of file    };
  330.       filenamelength      : word    {  length of file name      };
  331.       extrafieldlength    : word    {  length of extra stuff    };
  332.       commentfieldlength  : word    {  length of comments       };
  333.       diskstartnumber     : word    {  disk # file starts on    };
  334.       internalattributes  : word    {  text/non-text flags      };
  335.       externalattributes  : longint {  file system attributes   };
  336.       localheaderoffset   : longint {  where local hdr starts   };
  337.     end;
  338.  
  339.   var 
  340.     zip_entrylocal   : zip_local_header_type;{ local header }
  341.     zip_entrycentral : zip_central_header_type absolute data;{ central header }
  342.     zipfilename      : str79;
  343.     e                : string[4]; {extention}
  344.  
  345.  
  346.  
  347.  
  348.   function readfilename(var len : word) : boolean;
  349.   begin
  350.     readfilename := false;
  351.     if len > 79 then len := 79; {niet echt goed maar moet kunnen}
  352.     blockread(cfifile, zipfilename[1], len, bytes_read);
  353.     if ioresult <> 0 then exit;
  354.     if bytes_read<>len then exit;
  355.     zipfilename[0] := chr(len);
  356.     with cfitype do begin
  357.       fsplit(zipfilename, cfipath, cfiname, e);
  358.       cfiname := concat(cfiname, e);
  359.     end;
  360.     readfilename := true;
  361.   end;
  362.  
  363.  
  364.  
  365.   function convertmethod1(m : word) : word;
  366.   var cm : word;
  367.   begin
  368.     case m of
  369.       0  : cm := 50; {stored}
  370.       1  : cm := 51; {shrunk}
  371.       2  : cm := 52; {reduced factor 1}
  372.       3  : cm := 53; {reduced factor 2}
  373.       4  : cm := 54; {reduced factor 3}
  374.       5  : cm := 55; {reduced factor 4}
  375.       6  : cm := 56; {imploding}
  376.       else cm := 255; {unknown}
  377.     end;
  378.     convertmethod1 := cm
  379.   end;
  380.  
  381.  
  382.  
  383.   function convertmethod2(m : word) : word;
  384.   var cm : word;
  385.   begin
  386.     case m of
  387.       0  : cm := 80; {stored}
  388.       1  : cm := 81; {shrunk}
  389.       2  : cm := 82; {reduced factor 1}
  390.       3  : cm := 83; {reduced factor 2}
  391.       4  : cm := 84; {reduced factor 3}
  392.       5  : cm := 85; {reduced factor 4}
  393.       6  : cm := 86; {imploding}
  394.       else cm := 255; {unknow}
  395.      end;
  396.      convertmethod2 := cm
  397.    end;
  398.  
  399.  
  400. begin
  401.   if cfierror then exit; { er is een error dus we gaan niet verder }
  402.   cfierror := true; { assume error }
  403.   seek(cfifile, cfipos+internal_stap);
  404.   if ioresult <> 0 then exit; {error}
  405.   if not internal_centralheaderfound then begin
  406.     blockread(cfifile, zip_entrylocal, sizeof(zip_local_header_type), bytes_read);
  407.     if ioresult <> 0 then exit;
  408.     if bytes_read < sizeof(zip_local_header_type) then exit; {error}
  409.     {  nu checken wat gelezen is  }
  410.     if zip_entrylocal.signature = zip_local_header_signature then
  411.      { info wordt ingevuld in cfitype }
  412.     with cfitype do begin
  413.       if not readfilename(zip_entrylocal.filenamelength) then exit;
  414.       cficrc    := zip_entrylocal.crc32;
  415.       cfipsize  := zip_entrylocal.compressedsize;
  416.       cfiosize  := zip_entrylocal.uncompressedsize;
  417.       cfitime   := zip_entrylocal.timedate;
  418.       cfimethod := convertmethod1(zip_entrylocal.compressionmethod);
  419.       cfiattr   := 0; {niet aanwezig in local header}
  420.  
  421.       inc(cfipos, internal_stap);
  422.       internal_stap := sizeof(zip_local_header_type) +
  423.                        zip_entrylocal.filenamelength +
  424.                        zip_entrylocal.extrafieldlength +
  425.                        zip_entrylocal.compressedsize;
  426.       cfierror  := false;
  427.       exit;
  428.     end;
  429.   end;
  430.  
  431.  
  432.  
  433.   { als het geen local header is of zijn daar al voorbij dan central header }
  434.   { bekijken zie source hieronder                                           }
  435.   if not readcentralheader then exit;
  436.  
  437.   if internal_centralheaderfound then begin
  438.     blockread(cfifile, zip_entrycentral, sizeof(zip_central_header_type), 
  439.               bytes_read);
  440.     if ioresult <> 0 then exit;
  441.     if bytes_read < sizeof(zip_central_header_type) then exit; {error}
  442.   end;
  443.  
  444.   if (not internal_centralheaderfound) and (
  445.     zip_entrylocal.signature=zip_central_header_signature
  446.   ) then begin
  447.     seek(cfifile, cfipos+internal_stap);
  448.     if ioresult <> 0 then exit; {error}
  449.     blockread(cfifile, zip_entrycentral, sizeof(zip_central_header_type), 
  450.       bytes_read
  451.     );
  452.     if ioresult <> 0 then exit;
  453.     if bytes_read < sizeof(zip_central_header_type) then exit; {error}
  454.     internal_centralheaderfound := true;
  455.   end;
  456.  
  457.   if (internal_centralheaderfound) and
  458.      (zip_entrycentral.signature=zip_central_header_signature) then
  459.    { info wordt ingevuld in cfitype }
  460.   with cfitype do begin
  461.     if not readfilename(zip_entrycentral.filenamelength) then exit;
  462.     cficrc    := zip_entrycentral.crc32;
  463.     cfipsize  := zip_entrycentral.compressedsize;
  464.     cfiosize  := zip_entrycentral.uncompressedsize;
  465.     cfitime   := zip_entrycentral.timedate;
  466.     cfimethod := convertmethod2(zip_entrycentral.compressionmethod);
  467.     cfiattr   := zip_entrycentral.externalattributes;
  468.  
  469.     inc(cfipos, internal_stap);
  470.     internal_stap := sizeof(zip_central_header_type) +
  471.       zip_entrycentral.filenamelength +
  472.       zip_entrycentral.extrafieldlength +
  473.       zip_entrycentral.commentfieldlength;
  474.     cfierror := false;
  475.     exit;
  476.   end;
  477. end;
  478.  
  479.  
  480.  
  481.  
  482. function testforzip(var data : dataarray) : boolean;
  483. var signature : longint absolute data;
  484. begin
  485.   testforzip := false;
  486.   if signature <> zip_local_header_signature then exit;
  487.  
  488.   cfityp := zip;
  489.   testforzip := true;
  490. end;
  491.  
  492.  
  493.  
  494.  
  495. {define dochecksum}
  496.  
  497. { ---------------------------------------------------------------------- }
  498. {                   map of lzh file entry header                         }
  499. { ---------------------------------------------------------------------- }
  500.  
  501. type char5           = array[1..5] of char;
  502.  
  503.      lzh_entry_type  = record
  504.       reclen   : byte      {  header record length      };
  505.       checksum : byte      {  checksum of header bytes  };
  506.       compress : char5     {  compression type          };
  507.       csize    : longint   {  compressed size           };
  508.       osize    : longint   {  original size             };
  509.       timedate : longint   {  packed time&date          };
  510.       attr     : word      {  file attributes           };
  511.       fnamelen : byte      {  length of file name       };
  512.      end;
  513.  
  514.  
  515. procedure cfinextlzh;
  516. var lzh_entry     : lzh_entry_type absolute data;
  517.     lenname       : byte;
  518.     lzhfilename   : str79;
  519.     e             : string[4];
  520.     crccheck      : word;
  521.  
  522.   function convertmethod : word;
  523.   var cm : word;
  524.   begin
  525.    cm := 255; {unknown}
  526.    with lzh_entry do
  527.     begin
  528.      {lzh}
  529.      if compress = '-lh0-' then cm := 200;
  530.      if compress = '-lh1-' then cm := 201;
  531.      if compress = '-lh2-' then cm := 202;
  532.      if compress = '-lh3-' then cm := 203;
  533.      if compress = '-lh4-' then cm := 204;
  534.      if compress = '-lh5-' then cm := 205;
  535.  
  536.      {lzs vanaf 230 }
  537.      if compress = '-lz0-' then cm := 230;{?}
  538.      if compress = '-lz1-' then cm := 231;{?}
  539.      if compress = '-lz2-' then cm := 232;{?}
  540.      if compress = '-lz3-' then cm := 233;{?}
  541.      if compress = '-lz4-' then cm := 234;
  542.      if compress = '-lz5-' then cm := 235;
  543.     end; {with}
  544.  
  545.    convertmethod := cm
  546.   end;
  547.  
  548. begin
  549.  if cfierror then exit; { als error dan niet verder want wie weet! }
  550.  cfierror := true; { assume error }
  551.  seek(cfifile, cfipos+internal_stap);
  552.  if ioresult <> 0 then exit; {error}
  553.  blockread(cfifile, lzh_entry, sizeof(lzh_entry_type), bytes_read);
  554.  if ioresult <> 0 then exit;
  555.  if bytes_read <> sizeof(lzh_entry_type) then exit;
  556.  lenname := lzh_entry.fnamelen;
  557.  blockread(cfifile, lzhfilename[1], lenname, bytes_read);
  558.  if ioresult <> 0 then exit;
  559.  if lzh_entry.fnamelen <> bytes_read then exit;
  560.  blockread(cfifile, crccheck, sizeof(crccheck), bytes_read);
  561.  if ioresult <> 0 then exit;
  562.  if sizeof(crccheck) <> bytes_read then exit;
  563.  
  564.  lzhfilename[0] := chr(lzh_entry.fnamelen);
  565.  
  566.  with cfitype do
  567.   begin
  568.    fsplit(lzhfilename, cfipath, cfiname, e);
  569.    cfiname   := concat(cfiname, e);
  570.    cficrc    := crccheck;
  571.    cfipsize  := lzh_entry.csize;
  572.    cfiosize  := lzh_entry.osize;
  573.    cfitime   := lzh_entry.timedate;
  574.    cfiattr   := lzh_entry.attr;
  575.    cfimethod := convertmethod; {moet toch wat invullen niet}
  576.    inc(cfipos, internal_stap);
  577.    internal_stap := lzh_entry.reclen + lzh_entry.csize + 2; {2 van crc}
  578.    if internal_stap < 0 then exit; {fout ??!}
  579.   end;
  580.  cfierror := false;
  581. end;
  582.  
  583.  
  584. function testforlzh(var data : dataarray) : boolean;
  585. var lzhentry : lzh_entry_type absolute data;
  586.     f        : str79;
  587.     loop     : integer;
  588.     crc      : word;
  589.     crcw     : array [1..2] of byte absolute crc;
  590.  
  591.   { berekent crc van entry }
  592.   function mksum : byte;
  593.   var i        : byte;
  594.       checksum : byte;
  595.       lzhcheck : array[1..sizeof(lzh_entry_type)] of byte absolute data;
  596.   begin
  597.    checksum := 0;
  598.  
  599.    for i := 3 to 22 do checksum := (checksum + lzhcheck[i]);
  600.    for i := 1 to lzhentry.fnamelen do checksum := (checksum + ord(f[i]));
  601.    checksum := checksum+lo(crc);
  602.    checksum := checksum+hi(crc);
  603.  
  604.    mksum := checksum;
  605.   end;
  606.  
  607. begin
  608.  testforlzh := false;
  609.  
  610.  if lzhentry.fnamelen > 79 then exit;
  611.  for loop := sizeof(lzh_entry_type) to sizeof(lzh_entry_type)+
  612.              lzhentry.fnamelen do
  613.   f[loop-sizeof(lzh_entry_type)] := chr(data[loop]);
  614.  
  615.  crcw[1] := data[sizeof(lzh_entry_type)+lzhentry.fnamelen+1];
  616.  crcw[2] := data[sizeof(lzh_entry_type)+lzhentry.fnamelen+2];
  617.  
  618. {$IFDEF DOCHECKSUM}
  619.  if mksum <> lzhentry.checksum then exit;
  620. {$ENDIF}
  621.  
  622.  cfityp := lzh;
  623.  testforlzh := true;
  624. end;
  625.  
  626.  
  627. const valid_zoo  = $fdc4a7dc            {  valid zoo tag           };
  628.  
  629. procedure cfinextzoo;
  630. { ---------------------------------------------------------------------- }
  631. {                   maps of zoo file headers and entries                 }
  632. { ---------------------------------------------------------------------- }
  633.  
  634. const pathsize   = 256                  {  max length of pathname  };
  635.       fnamesize  = 13                   {  size of dos filename    };
  636.       lfnamesize = 256                  {  size of long filename   };
  637.  
  638. type fname_type       = array [1..fnamesize] of char;
  639.      lfname_type      = array [1..lfnamesize] of char;
  640.      path_type        = array [1..pathsize] of char;
  641.  
  642.      {  one entry in zoo library fixed part of entry       }
  643.      zoo_entry_type  = record
  644.       zoo_tag     : longint              {  tag -- redundancy check  };
  645.       zoo_type    : byte                 {  type of directory entry  };
  646.       pack_method : byte                 {  0 = no packing, 1 = normal lzw  };
  647.       next        : longint              {  pos'n of next directory entry  };
  648.       offset      : longint              {  position of this file  };
  649.       date        : word                 {  dos format date  };
  650.       time        : word                 {  dos format time  };
  651.       file_crc    : word                 {  crc of this file  };
  652.       org_size    : longint              {  original file size  };
  653.       size_now    : longint              {  compressed file size  };
  654.       major_ver   : byte                 {  version required to extract ...  };
  655.       minor_ver   : byte                 {  this file (minimum)              };
  656.       deleted     : byte                 {  will be 1 if deleted, 0 if not  };
  657.       struc       : byte                 {  file structure if any  };
  658.       comment     : longint              {  points to comment;  zero if none  };
  659.       cmt_size    : word                 {  length of comment, 0 if none  };
  660.       fname       : fname_type           {  filename  };
  661.  
  662.       var_dir_len : integer              {  length of variable part of dir entry  };
  663.       time_zone   : byte                 {  time zone where file was created  };
  664.       dir_crc     : word                 {  crc of directory entry  };
  665.      end;
  666.  
  667.                                    {  variable part of entry  }
  668.  
  669.    zoo_varying_type = array [1..4+pathsize+lfnamesize] of char;
  670.  
  671.    {  varying field definitions follow   }
  672.    {  for descriptive purposes.  any or  }
  673.    {  all of these can be missing,       }
  674.    {  depending upon the setting of      }
  675.    {  var_dir_len above and namlen and   }
  676.    {  dirlen here.                       }
  677.  
  678.   function convertmethod(m : word) : word;
  679.   var cm : word;
  680.   begin
  681.    case m of
  682.     0 : cm := 100; {stored}
  683.     1 : cm := 101; {lwz compression}
  684.     else cm := 255; {unknown}
  685.    end;
  686.    convertmethod := cm
  687.   end;
  688.  
  689. var namlen        : byte             {  length of long filename   };
  690.     dirlen        : byte             {  length of directory name  };
  691.     system_id     : integer          {  filesystem id             };
  692.  
  693.     zoo_entry     : zoo_entry_type;
  694.     zoo_varying   : zoo_varying_type     {  varying part of zoo entry        };
  695.     zoo_pos       : longint              {  current byte offset in zoo file  };
  696.     zoofilename   : string               {  long file name                   };
  697.     directname    : string               {  directory name                   };
  698.     timedate      : longint;
  699.     timedatew     : array [1..2] of word absolute timedate;
  700. begin
  701.  if cfierror then exit; { er is een error dus we gaan niet verder }
  702.  cfierror := true; { assume error }
  703. {  cfipos kan niet wordt gebruikt aangezien ze worden aangegeven door  }
  704. {  de internal_stap die de presiezer plek heeft                        }
  705.  seek(cfifile, {cfipos+}internal_stap);
  706.  if ioresult <> 0 then exit; {error}
  707.  blockread(cfifile, zoo_entry, sizeof(zoo_entry_type), bytes_read);
  708.  if ioresult <> 0 then exit;
  709.  if bytes_read < sizeof(zoo_entry_type) then exit;
  710.  if zoo_entry.zoo_tag <> valid_zoo then exit;
  711.  
  712.  {  get filename and posibele directory and proces this information  }
  713.  { here we get short name }
  714.  cfitype.cfipath := '';
  715.  cfitype.cfiname := copy(zoo_entry.fname, 1, pred(pos(#0, zoo_entry.fname)));
  716.  
  717.  if zoo_entry.var_dir_len > 0 then
  718.   begin
  719.    blockread(cfifile, zoo_varying, zoo_entry.var_dir_len, bytes_read);
  720.     if ioresult <> 0 then exit;
  721.     if (bytes_read=zoo_entry.var_dir_len) then with zoo_entry do
  722.      begin { here we get long name }
  723.       { get length names }
  724.       namlen := ord(zoo_varying[1]);
  725.       dirlen := ord(zoo_varying[2]);
  726.       {  get system_id  }
  727.       if (namlen+dirlen+2) < var_dir_len then
  728.        move(zoo_varying[namlen+dirlen+3], system_id, 2)
  729.        else system_id := 4095;
  730.  
  731.       if (dirlen>0) or (namlen>0) then
  732.        begin
  733.         {  get filename wordt niet ondersteund want kan langer zijn dan  }
  734.         {  12 charakters                                                 }
  735.         if namlen>0 then
  736.          begin
  737.           move(zoo_varying[3], zoofilename[1], pred(namlen));
  738.           zoofilename[0] := chr(pred(namlen));
  739.          end;{ else} zoofilename := cfitype.cfiname;
  740.         { get directory name }
  741.         if (dirlen>0) then
  742.          begin
  743.           move(zoo_varying[3+namlen], directname[1], pred(dirlen));
  744.           directname[0] := chr(pred(dirlen));
  745.           { append '/' if system_id says so }
  746.           if (system_id<=2) then
  747.            if (directname[length(directname)] <> '/') then
  748.             directname := directname+'/';
  749.           cfitype.cfipath := directname;
  750.          end;
  751.        end;
  752.      end;
  753.   end;
  754.  
  755.  if zoo_entry.deleted <> 0 then cfitype.cfiname := '*DELETED*';
  756.  if zoo_entry.next = 0 then exit; {einde zoo file}
  757.  
  758.  with cfitype do
  759.   begin
  760.    cficrc    := zoo_entry.file_crc;
  761.    cfipsize  := zoo_entry.size_now;
  762.    cfiosize  := zoo_entry.org_size;
  763.  
  764.    timedatew[1] := zoo_entry.time;
  765.    timedatew[2] := zoo_entry.date;
  766.    cfitime   := timedate;
  767.    cfiattr   := 0;
  768.    cfimethod := convertmethod(zoo_entry.pack_method);
  769.  
  770.    cfipos := internal_stap;
  771.    internal_stap := zoo_entry.next;
  772.    cfierror := false;
  773.   end;
  774. end;
  775.  
  776.  
  777. function testforzoo(var data : dataarray) : boolean;
  778. {  deze procedure checkt op zoo file en als hij er een vindt dan wordt de  }
  779. {  eerste file entry opgeslagen in internal_stap                           }
  780. { ---------------------------------------------------------------------- }
  781. {                   maps of zoo file headers and entries                 }
  782. { ---------------------------------------------------------------------- }
  783. const siz_text   = 20                   {  length of header text   };
  784. type header_text_type = array [1..siz_text] of char;
  785.      {  zoo file header  }
  786.      zoo_header_type = record
  787.       header_text : header_text_type     {  character text       };
  788.       zoo_tag     : longint              {  identifies archives  };
  789.       zoo_start   : longint              {  where data starts    };
  790.       zoo_minus   : longint              {  consistency check    };
  791.       zoo_major   : char                 {  major version #      };
  792.       zoo_minor   : char                 {  minor version #      };
  793.      end;
  794.  
  795. var zoo_header    : zoo_header_type absolute data; {  header for zoo file  }
  796. begin
  797.  testforzoo := false; {assume no zoo file}
  798.  {wordt van uitgegaan dat start = 0 }
  799.  if zoo_header.zoo_tag <> valid_zoo then exit; {geen zoo file}
  800.  
  801.  internal_stap := zoo_header.zoo_start;
  802.  cfityp := zoo;
  803.  testforzoo := true; {zoo file checks so far ok}
  804. end;
  805.  
  806.  
  807. function blockpos(var buffer;size : word;s : string) : integer;
  808. { search in buffer of size bytes for the string s }
  809. begin
  810. { load "buffer" address into es:di, "buffer" offset into bx, length(s) -
  811.   1 into dx, contents of "s[1]" into al, offset of "s[2]" into si, and
  812.   "size" - length(s) + 1 into cx.  if "size" < length(s), or if
  813.   length(s) = 0, return zero. }
  814.  
  815.   inline($1e/               {        push    ds           }
  816.          $16/               {        push    ss           }
  817.          $1f/               {        pop     ds           }
  818.          $c4/$be/>buffer/   {        les     di, buffer[bp]}
  819.          $89/$fb/           {        mov     bx, di        }
  820.          $8b/$8e/>size/     {        mov     cx, size[bp]  }
  821.          $8d/$b6/>s+2/      {        lea     si, s+2[bp]   }
  822.          $8a/$86/>s+1/      {        mov     al, s+1[bp]   }
  823.          $8a/$96/>s/        {        mov     dl, s[bp]     }
  824.          $84/$d2/           {        test    dl, dl        }
  825.          $74/$23/           {        jz      error        }
  826.          $fe/$ca/           {        dec     dl           }
  827.          $30/$f6/           {        xor     dh, dh        }
  828.          $29/$d1/           {        sub     cx, dx        }
  829.          $76/$1b/           {        jbe     error        }
  830.  
  831.   { scan the es:di buffer, looking for the first occurrence of "s[1]."  if
  832.     not found prior to reaching length(s) characters before the end of the
  833.     buffer, return zero.  if length(s) = 1, the entire string has been
  834.     found, so report success. }
  835.  
  836.        $fc/               {        cld                  }
  837.        $f2/               {next:   repne                }
  838.        $ae/               {        scasb                }
  839.        $75/$16/           {        jne     error        }
  840.        $85/$d2/           {        test    dx, dx        }
  841.        $74/$0c/           {        jz      found        }
  842.  
  843.   { compare "s" (which is at ss:si) with the es:di buffer, in both cases
  844.     starting with the first byte just past the length byte of the string.
  845.     if "s" does not match what is at the di position of the buffer, reset
  846.     the registers to the values they had just prior to the comparison, and
  847.     look again for the next occurrence of the length byte. }
  848.  
  849.          $51/               {        push    cx           }
  850.          $57/               {        push    di           }
  851.          $56/               {        push    si           }
  852.          $89/$d1/           {        mov     cx, dx        }
  853.          $f3/               {        repe                 }
  854.          $a6/               {        cmpsb                }
  855.          $5e/               {        pop     si           }
  856.          $5f/               {        pop     di           }
  857.          $59/               {        pop     cx           }
  858.          $75/$ec/           {        jne     next         }
  859.  
  860.   { string found in buffer.  set ax to the offset, within buffer, of the
  861.     first byte of the string (the length byte), assuming that the first
  862.     byte of the buffer is at offset 1. }
  863.  
  864.          $89/$f8/           {found:  mov     ax, di        }
  865.          $29/$d8/           {        sub     ax, bx        }
  866.          $eb/$02/           {        jmp     short return }
  867.  
  868.   { an "error" condition.  return zero. }
  869.  
  870.          $31/$c0/           {error:  xor     ax, ax        }
  871.          $89/$46/$fe/       {return: mov     [bp-2], ax    }
  872.          $1f)               {        pop     ds           }
  873. end;
  874.  
  875.  
  876. { ---------------------------------------------------------------------- }
  877. {    names of the months and days in each month for date conversions     }
  878. { ---------------------------------------------------------------------- }
  879. const {  # of seconds local time leads/lags  }
  880.       {  greenwich mean time (gmt)           }
  881.       gmt_difference        : word    = 7 * 3600;
  882.       use_daylight_savings  : boolean = true;
  883.       days_per_month : array[1..12] of byte
  884.                        = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
  885.  
  886. { ---------------------------------------------------------------------- }
  887. {    starting/ending dates for daylight savings time from 1980 to now    }
  888. { ---------------------------------------------------------------------- }
  889.  
  890. type
  891.    daylight_savings_record = record
  892.                                 starting_time : longint;
  893.                                 ending_time   : longint;
  894.                              end;
  895.  
  896. var
  897.    daylight_savings_time : array[1980..2000] of daylight_savings_record;
  898.  
  899.  
  900. procedure get_unix_style_date(     date  : longint;
  901.                                var year  : word;
  902.                                var month : word;
  903.                                var day   : word;
  904.                                var hour  : word;
  905.                                var mins  : word;
  906.                                var secs  : word );
  907.  
  908. { ---------------------------------------------------------------------- }
  909. {                                                                        }
  910. {      procedure:  get_unix_style_date                                   }
  911. {                                                                        }
  912. {      purpose:    converts date in unix form to ymd, hms form           }
  913. {                                                                        }
  914. { ---------------------------------------------------------------------- }
  915.  
  916. const
  917.    secs_per_year      = 31536000;
  918.    secs_per_leap_year = 31622400;
  919.    secs_per_day       = 86400;
  920.    secs_per_hour      = 3600;
  921.    secs_per_minute    = 60;
  922.  
  923. var
  924.    rdate     : longint;
  925.    savedate  : longint;
  926.    t         : longint;
  927.  
  928. begin {  get_unix_style_date  }
  929.                                    {  starting date is january 1, 1970  }
  930.    year  := 1970;
  931.    month := 1;
  932.  
  933.    rdate    := date - gmt_difference;
  934.    savedate := rdate;
  935.                                    {  sweep out year  }
  936.    while( rdate > 0 ) do
  937.       begin
  938.  
  939.          if ( year mod 4 ) = 0 then
  940.             t := secs_per_leap_year
  941.          else
  942.             t := secs_per_year;
  943.  
  944.          rdate := rdate - t;
  945.  
  946.          inc( year );
  947.  
  948.       end;
  949.  
  950.    rdate := rdate + t;
  951.  
  952.    dec( year );
  953.                                    {  adjust for daylight savings time  }
  954.                                    {  if necessary                      }
  955.    if use_daylight_savings then
  956.       with daylight_savings_time[year] do
  957.          begin
  958.             if ( ( savedate >= starting_time ) and
  959.                  ( savedate <= ending_time   )     ) then
  960.                rdate := rdate + secs_per_hour;
  961.          end;
  962.  
  963.                                    {  adjust for leap year  }
  964.  
  965.    if ( ( year mod 4 ) = 0 ) then
  966.       days_per_month[ 2 ] := 29
  967.    else
  968.       days_per_month[ 2 ] := 28;
  969.  
  970.                                    {  sweep out month  }
  971.    while( rdate > 0 ) do
  972.       begin
  973.  
  974.          t     := longint( days_per_month[ month ] ) * secs_per_day;
  975.  
  976.          rdate := rdate - t;
  977.  
  978.          inc( month );
  979.  
  980.       end;
  981.  
  982.    rdate := rdate + t;
  983.  
  984.    dec( month );
  985.                                    {  get day  }
  986.  
  987.    day   := ( rdate + pred( secs_per_day ) ) div secs_per_day;
  988.    rdate := rdate - longint( pred( day ) ) * secs_per_day;
  989.  
  990.                                    {  get time within day  }
  991.  
  992.    hour  := rdate div secs_per_hour;
  993.    rdate := rdate mod secs_per_hour;
  994.  
  995.    mins  := rdate div secs_per_minute;
  996.    secs  := rdate mod secs_per_minute;
  997.  
  998. end   {  get_unix_style_date  };
  999.  
  1000. {  de dataarray wordt altijd gebruikt om groote stukken data te bewaren  }
  1001. {  hierdoor is het stack gebruik een stuk lager                          }
  1002. type fnametype = array [1..13] of char;
  1003.  
  1004. procedure cfinextdwc;
  1005. type {  individual file entry  }
  1006.      dwc_entry_type  = record
  1007.       filename : fnametype {  file and extension        };
  1008.       size     : longint   {  original size             };
  1009.       time     : longint   {  packed date and time unix };
  1010.       new_size : longint   {  compressed size           };
  1011.       fpos     : longint   {  position in dwc file      };
  1012.       method   : byte      {  compression method        };
  1013.       sz_c     : byte      {  size of comment           };
  1014.       sz_d     : byte      {  size of dir name on add   };
  1015.       crc      : word      {  cyclic redundancy check   };
  1016.      end;
  1017.  
  1018.  
  1019.   function convertmethod(m : word) : word;
  1020.   var cm : word;
  1021.   begin
  1022.    case m of
  1023.     2 : cm := 250; {stored}
  1024.     1 : cm := 251; {crunched}
  1025.     else cm := 255; {unknown}
  1026.    end;
  1027.    convertmethod := cm
  1028.   end;
  1029.  
  1030.  
  1031.     {  entry for one file in dwc lib    }
  1032. var dwcentry : dwc_entry_type absolute data;
  1033.     dt       : datetime;
  1034. begin
  1035.  cfierror := true; {assume error}
  1036.  seek(cfifile, {cfipos+}internal_stap);
  1037.  if ioresult <> 0 then exit;
  1038.  blockread(cfifile, dwcentry, sizeof(dwc_entry_type), bytes_read);
  1039.  if ioresult <> 0 then exit;
  1040.  if bytes_read < sizeof(dwc_entry_type) then exit;
  1041.  
  1042.  with cfitype do
  1043.   begin
  1044.    cfiname   := copy(dwcentry.filename, 1, pred(pos(#0, dwcentry.filename)));
  1045.    cfipath   := '';
  1046.    cfipsize  := dwcentry.new_size;
  1047.    cfiosize  := dwcentry.size;
  1048.    cfimethod := convertmethod(dwcentry.method);
  1049.    cfiattr   := 0; {niet in dwc}
  1050.    cficrc    := dwcentry.crc;
  1051.    get_unix_style_date(dwcentry.time, dt.year, dt.month, dt.day, dt.hour, 
  1052.                        dt.min, dt.sec);
  1053.    packtime(dt, cfitime);
  1054.    cfipos := internal_stap;
  1055.    internal_stap := internal_stap + bytes_read; {next entry zoiets als zoo}
  1056.   end;
  1057.  
  1058.  cfierror := false;
  1059. end;
  1060.  
  1061.  
  1062. function testfordwc(var data : dataarray) : boolean;
  1063. const bufsize    = 256;
  1064.       maxentries = 1800              {  maximum # of files in dwc file  };
  1065.  
  1066. type id_type   = array [1..3] of char;
  1067.      {  header for entire dwc file  }
  1068.      dwc_header_type = record
  1069.       size    : word       {  size of archive structure, future expansion  };
  1070.       ent_sz  : byte       {  size of directory entry, future expansion    };
  1071.       header  : fnametype  {  name of header file to print on listings     };
  1072.       time    : longint    {  time stamp of last modification to archive   };
  1073.       entries : longint    {  number of entries in archive                 };
  1074.       id_3    : id_type    {  the string "DWC" to identify archive         };
  1075.      end;
  1076.  
  1077. var buf          : array [1..bufsize] of char absolute data;
  1078.     count        : word;
  1079.     l            : longint;
  1080.     dwcpos       : longint;
  1081.     id_found     : boolean;
  1082.     i            : integer;
  1083.     dwcheader    : dwc_header_type absolute data;
  1084.     dir_size     : word;{  size in bytes of directory  }
  1085. begin
  1086.  testfordwc := false;
  1087.  l := filesize(cfifile); count := 1;
  1088.  id_found := false;
  1089.  
  1090.  repeat
  1091.   dwcpos := l - (count*bufsize-pred(count)*5);
  1092.   if dwcpos < 0 then dwcpos := 0;
  1093.   seek(cfifile, dwcpos);
  1094.   if ioresult <> 0 then exit;
  1095.   fillchar(buf, bufsize, #0);{empty buff (just to be sure) }
  1096.   blockread(cfifile, buf, bufsize, bytes_read);
  1097.   if ioresult <> 0 then exit;
  1098.   i := blockpos(buf, bufsize, 'DWC');
  1099.   if i <> 0 then id_found := true else inc(count);
  1100.  until (count>10) or (id_found);
  1101.  
  1102.  if id_found then
  1103.   begin
  1104.    { we found true end of dwc file (i hope)  }
  1105.    dwcpos := dwcpos + i + 2;
  1106.    seek(cfifile, dwcpos-sizeof(dwc_header_type));
  1107.    if ioresult <> 0 then exit;
  1108.    blockread(cfifile, dwcheader, sizeof(dwc_header_type), bytes_read);
  1109.    if ioresult <> 0 then exit;
  1110.    if bytes_read < sizeof(dwc_header_type) then exit;
  1111.    {  check # of entries for reasonableness  }
  1112.    if (dwcheader.entries<0) or (dwcheader.entries>maxentries) then exit;
  1113.    with dwcheader do
  1114.     begin
  1115.      dir_size := entries * ent_sz;
  1116.      internal_stap := dwcpos - (dir_size + size);
  1117.     end;{with}
  1118.   end;
  1119.  
  1120.  seek(cfifile, 0); {zoals standaard bij andere archives}
  1121.  if ioresult <> 0 then exit;
  1122.  cfityp := dwc;
  1123.  testfordwc := true;
  1124. end;
  1125.  
  1126.  
  1127. var lbr_dir_size  : integer;        {  # of entries in library directory      }
  1128. { ---------------------------------------------------------------------- }
  1129. {               map of library file (.lbr) entry header                  }
  1130. { ---------------------------------------------------------------------- }
  1131. const lbr_header_length = 32          {  length of library file header entry    };
  1132.  
  1133. type lbr_entry_type = record
  1134.       flag  : byte                   {  lbr - entry flag            };
  1135.       name  : array [1..8] of char   {  file name                   };
  1136.       ext   : array [1..3] of char   {  extension                   };
  1137.       offset: word                   {  offset within library       };
  1138.       n_sec : word                   {  number of 128-byte sectors  };
  1139.       crc   : word                   {  crc (optional)              };
  1140.       date  : word                   {  # days since 1/1/1978       };
  1141.       udate : word                   {  date of last update         };
  1142.       time  : word                   {  packed time                 };
  1143.       utime : word                   {  time of last update         };
  1144.       pads  : array [1..6] of char   {  currently unused            };
  1145.      end;
  1146.  
  1147.  
  1148. procedure cfinextlbr;
  1149. const ndays : array [1..12] of integer = ( 31, 28, 31, 30, 31, 30, 
  1150.                                            31, 31, 30, 31, 30, 31  );
  1151. var lbrentry      : lbr_entry_type; {  header describing one file in library  }
  1152.     timedate      : longint;
  1153.     timedatew     : array [1..2] of word absolute timedate;
  1154.     month         : integer;
  1155.     year          : integer;
  1156.     done          : boolean;
  1157.     t             : integer;
  1158.  
  1159.   function convertmethod : word;
  1160.   begin
  1161.    convertmethod := 181;
  1162.   end;
  1163.  
  1164. begin
  1165.  cfierror := true;
  1166.  seek(cfifile, cfipos+internal_stap);
  1167.  if ioresult <> 0 then exit;
  1168.  
  1169.  blockread(cfifile, lbrentry, sizeof(lbr_entry_type), bytes_read);
  1170.  if ioresult <> 0 then exit;
  1171.  if bytes_read < lbr_header_length then exit;
  1172.  if lbrentry.flag <> 0 then exit;
  1173.  with lbrentry do
  1174.   begin
  1175.   {  pick up time/date of creation this  }
  1176.   {  entry if specified.  if the update  }
  1177.   {  time/date is different, then we     }
  1178.   {  will report that instead.           }
  1179.  
  1180.    if time = 0 then
  1181.     begin
  1182.      time := utime;
  1183.      date := udate;
  1184.     end else if (time<>utime) or (date<>udate) then
  1185.               begin
  1186.                time := utime;
  1187.                date := udate;
  1188.               end;
  1189.   {  convert date from library format of  }
  1190.   {  # days since 1/1/1978 to dos format  }
  1191.    month := 1;
  1192.    year  := 78;
  1193.    {  this is done using brute force.  }
  1194.    repeat
  1195.    {  account for leap years  }
  1196.  
  1197.     t := 365 + ord(year mod 4 = 0);
  1198.  
  1199.    {  see if we have less than 1 year left  }
  1200.  
  1201.     done := (date<t);
  1202.  
  1203.     if (not done) then
  1204.      begin
  1205.       year := succ(year);
  1206.       date := date - t;
  1207.      end;
  1208.  
  1209.    until done;
  1210.    {  now get months and days within year  }
  1211.    repeat
  1212.     t := ndays[month] + ord((month = 2) and (year mod 4 = 0));
  1213.  
  1214.     done := (date<t) ;
  1215.  
  1216.     if (not done) then
  1217.      begin
  1218.       month := succ(month);
  1219.       date  := date - t;
  1220.      end;
  1221.  
  1222.    until done;
  1223.    {  if > 1980, convert to dos date  }
  1224.    {  else leave unconverted.         }
  1225.  
  1226.    if (year>=80) then
  1227.     date := (year - 80) shl 9 + month shl 5 + date
  1228.     else date := 0;
  1229.   end;{with}
  1230.  
  1231.  with cfitype do
  1232.   begin
  1233.    cfiname      := copy(lbrentry.name, 1, pred(pos(' ', lbrentry.name)));
  1234.    if cfiname = '' then cfiname := lbrentry.name;
  1235.    if lbrentry.ext <> '   ' then cfiname := concat(cfiname, '.', lbrentry.ext);
  1236.    cfiosize     := lbrentry.n_sec * 128;
  1237.    cfipsize     := lbrentry.n_sec;
  1238.  
  1239.    timedatew[1] := lbrentry.time;
  1240.    timedatew[2] := lbrentry.date;
  1241.    cfitime      := timedate;
  1242.  
  1243.    cficrc       := lbrentry.crc;
  1244.    cfiattr      := 0; {niet aanwezig}
  1245.  
  1246.    cfimethod := convertmethod;
  1247.  
  1248.    inc(cfipos, internal_stap);
  1249.    internal_stap := lbr_header_length;
  1250.   end;
  1251.  
  1252.  cfierror := false;
  1253. end;
  1254.  
  1255.  
  1256. function testforlbr(var data : dataarray) : boolean;
  1257. var lbrentry   : lbr_entry_type absolute data;
  1258. begin
  1259.  testforlbr := false;
  1260.   with lbrentry do
  1261.    begin
  1262.     if lbrentry.flag <> 0 then exit;
  1263.     internal_stap := lbr_header_length;
  1264.    end;
  1265.  
  1266.  cfityp := lbr;
  1267.  testforlbr := true;
  1268. end;
  1269.  
  1270.  
  1271. { ---------------------------------------------------------------------- }
  1272. {                   map of arj file entry header                         }
  1273. { ---------------------------------------------------------------------- }
  1274.  
  1275. const arjheaderid1 = $60ea;
  1276.       arjheaderid2 = 60000;
  1277.  
  1278. type arj_entry_type   = record
  1279.       headerid        : word;
  1280.       headersize      : word; {  size after first_hdr_size  }
  1281.       first_hdr_size  : byte;
  1282.       res             : byte;
  1283.       archiveversion  : byte; {  version needed to extract  }
  1284.       hostos          : byte;
  1285.       arjflags        : byte;
  1286.       method          : byte;
  1287.       filetype        : byte;
  1288.       reserved        : byte;{byte}
  1289.       timedate        : longint;
  1290.       compsize        : longint; {  compressed size  }
  1291.       orgsize         : longint; {  orginal size  }
  1292.       orgcrc          : longint;
  1293.       fileaccesmode   : word;
  1294.       entrynamepos    : word;
  1295.       hostdata        : word;
  1296.       {  extra data follows  }
  1297.      end;
  1298.  
  1299.  
  1300. procedure cfinextarj;
  1301. var arj_entry     : arj_entry_type;
  1302.     lenname       : byte;
  1303.     arjfilename   : str79;
  1304.     extraheader   : word;
  1305.  
  1306.   function convertmethod(m : word) : word;
  1307.   var cm : word;
  1308.   begin
  1309.    case m of
  1310.     0 : cm := 190; {stored}
  1311.     1 : cm := 191; {1..3 compressed most}
  1312.     2 : cm := 192;
  1313.     3 : cm := 193;
  1314.     4 : cm := 194; {compressed fastest}
  1315.     else cm := 255; {unknown}
  1316.    end;
  1317.    convertmethod := cm
  1318.   end;
  1319.  
  1320. begin
  1321.  if cfierror then exit; { als error dan niet verder want wie weet! }
  1322.  cfierror := true; { assume error }
  1323.  seek(cfifile, cfipos+internal_stap);
  1324.  if ioresult <> 0 then exit; {error}
  1325.  blockread(cfifile, arj_entry, sizeof(arj_entry), bytes_read);
  1326.  if bytes_read < sizeof(arj_entry) then exit;
  1327.  if (arj_entry.headerid<>arjheaderid1) and (arj_entry.headerid<>arjheaderid2)
  1328.   then exit;
  1329.  if arj_entry.headersize = 0 then exit;
  1330.  
  1331.  extraheader := (arj_entry.headersize-arj_entry.first_hdr_size);
  1332.  
  1333.  with arj_entry do
  1334.   begin
  1335.    blockread(cfifile, data, extraheader, bytes_read);
  1336.    if ioresult <> 0 then exit;
  1337.  
  1338.    for lenname := 1 to extraheader do
  1339.     begin
  1340.      if data[lenname] = 0 then
  1341.       begin
  1342.        arjfilename[0] := chr(lenname-1);
  1343.        lenname := extraheader;
  1344.       end else arjfilename[lenname] := chr(data[lenname]);
  1345.     end;
  1346.   end; {with}
  1347.  
  1348.  with cfitype do
  1349.   begin
  1350.    cfiname   := arjfilename;
  1351.    cfipath   := '';
  1352.    cficrc    := arj_entry.orgcrc;
  1353.    cfipsize  := arj_entry.compsize;
  1354.    cfiosize  := arj_entry.orgsize;
  1355.    cfitime   := arj_entry.timedate;
  1356.    cfimethod := convertmethod(arj_entry.method);
  1357.    cfiattr   := arj_entry.fileaccesmode;
  1358.  
  1359.    inc(cfipos, internal_stap);
  1360.    internal_stap := arj_entry.headersize+arj_entry.compsize+10;
  1361.  
  1362.    cfierror := false;
  1363.    exit;
  1364.   end; {with}
  1365. end;
  1366.  
  1367.  
  1368. function testforarj(var data : dataarray) : boolean;
  1369. var arj_entry : arj_entry_type absolute data;
  1370. begin
  1371.  testforarj := false;
  1372.  if (arj_entry.headerid<>arjheaderid1) and (arj_entry.headerid<>arjheaderid2)
  1373.   then exit;
  1374.  
  1375.  internal_stap := arj_entry.headersize + 10;{10???????}
  1376.  cfityp := arj;
  1377.  testforarj := true;
  1378. end;
  1379.  
  1380.  
  1381. procedure closecfi;
  1382. begin
  1383.  close(cfifile);
  1384.  { gewoon fout opvangen }
  1385.  if ioresult <> 0 then;
  1386. end;
  1387.  
  1388. function opencfifile;
  1389. const datablock = 100;
  1390. var ext        : string[4]; {extentie string}
  1391.     readbuffer : boolean; {test of data moet worden ingelezen}
  1392.     isarchive  : boolean;
  1393. begin
  1394. { initialiseren van enkele variabelen }
  1395.  cfifilename := f;
  1396.  cfipos := 0; internal_stap := 0; internal_centralheaderfound := false;
  1397.  cfierror := true; opencfifile := false;
  1398.  with cfitype do
  1399.   begin
  1400.    cfiptotal := 0;
  1401.    cfiototal := 0;
  1402.   end;
  1403.  
  1404. { openen van file }
  1405.  assign(cfifile, f);
  1406.  reset(cfifile, 1);
  1407.  if ioresult <> 0 then exit;
  1408.  
  1409.  { testen op soort file met behulp van extentie }
  1410.  ext := copy(f, succ(pos('.', f)), 3); {get extention}
  1411.  uppercase(ext); isarchive := false;
  1412. { bij dwc staat het aan het einde van de file !!!!! dus geen zin om dubbel }
  1413. { iets te laden. data wordt gebruikt als buffer                            }
  1414.  if (ext='DWC') then isarchive := testfordwc(data);
  1415.  
  1416.  readbuffer := false;
  1417.  if (not isarchive) then
  1418.   begin
  1419.    if (ext<>'ZIP') or (ext<>'PAK') or (ext<>'ARC') or (ext<>'PKA') or
  1420.       (ext<>'ZOO') or (ext<>'LBR') or (ext<>'ARJ') then
  1421.       begin
  1422.        if cfismartmode and (ext<>'EXE') and (ext<>'COM') then
  1423.         readbuffer := true;
  1424.        if cfisfx and ((ext='EXE') or (ext='COM')) then
  1425.         readbuffer := true;
  1426.       end else readbuffer := true;
  1427.   end;
  1428.  
  1429.  
  1430.  fillchar(data, sizeof(data), #0); { fill with nothing }
  1431.  if readbuffer then
  1432.   begin
  1433.    blockread(cfifile, data, datablock);
  1434.    if ioresult <> 0 then exit;
  1435.    seek(cfifile, 0);
  1436.    if ioresult <> 0 then exit;
  1437.   end;
  1438.  
  1439.  if (not isarchive) and (readbuffer) then
  1440.   begin {geen dwc of andere extentie}
  1441.    if (ext='PAK') or (ext='ARC') or (ext='PKA') then
  1442.     isarchive := testforarc(data);
  1443.    if (ext='ZIP') then isarchive := testforzip(data);
  1444.    if (ext='LZH') or (ext='ICE') or (ext='LZS') then
  1445.     isarchive := testforlzh(data);
  1446.    if (ext='ZOO') then isarchive := testforzoo(data);
  1447.    if (ext='LBR') then isarchive := testforlbr(data);
  1448.    if (ext='ARJ') then isarchive := testforarj(data);
  1449.   end;
  1450.  
  1451.  if (readbuffer) and (not isarchive) and (cfismartmode) and ((ext<>'COM')
  1452.     or (ext<>'EXE')) then
  1453.   begin {geen hit met extentie zoek het zelf uit}
  1454.   {  dit kan alleen bij zip, lzh/lzs, zoo, arc files  }
  1455.    if not isarchive then isarchive := testforarc(data);
  1456.    if not isarchive then isarchive := testforzip(data);
  1457.    if not isarchive then isarchive := testforzoo(data);
  1458.    if not isarchive then isarchive := testforlzh(data);
  1459.    if not isarchive then isarchive := testforarj(data);
  1460.   end;
  1461.  
  1462.  if isarchive then
  1463.   begin
  1464.    case cfityp of
  1465.     arc : cfinextproc := cfinextarc;
  1466.     zip : cfinextproc := cfinextzip;
  1467.     lzh : cfinextproc := cfinextlzh;
  1468.     zoo : cfinextproc := cfinextzoo;
  1469.     dwc : cfinextproc := cfinextdwc;
  1470.     lbr : cfinextproc := cfinextlbr;
  1471.     arj : cfinextproc := cfinextarj;
  1472.    end; {case}
  1473.   end;
  1474.  
  1475.  if not isarchive then begin
  1476.    closecfi;
  1477.    cfinextproc := cfinextempty;
  1478.    exit;
  1479.   end;
  1480.  cfierror := false; opencfifile := true;
  1481. end;
  1482.  
  1483. function cfinext;
  1484. label repeatagain;
  1485. begin
  1486. repeatagain:
  1487.  cfinext := false;
  1488.  {pointer naar een variabele procedure zie cfityp}
  1489.  cfinextproc;
  1490.  
  1491.  if not cfierror then with cfitype do
  1492.   begin
  1493.    inc(cfiptotal, cfipsize);
  1494.    inc(cfiototal, cfiosize);
  1495.    uppercase(cfiname);
  1496.    if cfiname='*DELETED*' then goto repeatagain;
  1497.    uppercase(cfipath);
  1498.    cfinext := true;
  1499.   end;
  1500. end;
  1501.  
  1502.  
  1503. { local procedure to mask out and store nybbles in a string }
  1504. procedure maskout;
  1505. begin
  1506. inline(
  1507.   $b5/$04/           {     mov  ch, 4         ; number of digits }
  1508.   $b1/$04/           { l1: mov  cl, 4         ; set count to 4 bits }
  1509.   $d3/$c3/           {     rol  bx, cl        ; left digit to right }
  1510.   $88/$d8/           {     mov  al, bl        ; move to al }
  1511.   $24/$0f/           {     and  al, 15        ; mask off left digit }
  1512.   $04/$30/           {     add  al, '0'       ; convert hex to ascii }
  1513.   $3c/$39/           {     cmp  al, '9'       ; is it > 9? }
  1514.   $76/$02/           {     jbe  l2            ; jump if digit = 0 to 9 }
  1515.   $04/$07/           {     add  al, 7         ; digit is a to f }
  1516.   $47/               { l2: inc  di            ; increment string index }
  1517.   $26/$88/$05/       {     mov  es:[di], al   ; store byte in string }
  1518.   $fe/$cd/           {     dec  ch            ; decrement digit count }
  1519.   $75/$e8);          {     jnz  l1            ; if not 0, keep on scanning }
  1520. end;   { maskout }
  1521.  
  1522. function declongtohex(l : longint) : str8;
  1523. begin
  1524. inline(
  1525.   $c4/$7e/$0a/       {     les  di, string    ; load string }
  1526.   $26/$c6/$05/$08/   {     mov  es:[di], 8    ; set length byte }
  1527.   $8b/$5e/$08);      {     mov  bx, [bp+8]    ; load high word of longint }
  1528.   maskout;
  1529. inline(
  1530.   $8b/$5e/$06);      {     mov  bx, [bp+6]    ; load low word of longint }
  1531.   maskout;
  1532. end;  { hexlongint }
  1533.  
  1534. function dectohex;
  1535. var temp : str8;
  1536. begin
  1537.  temp := declongtohex(l);
  1538.  if (cfityp<>zip) and (cfityp<>arj) then
  1539.   begin
  1540.    delete(temp, 1, 4);
  1541.    temp := '  '+temp;
  1542.   end;
  1543.  dectohex := temp;
  1544. end;
  1545.  
  1546.  
  1547.  
  1548. begin
  1549.   cfierror := true; cfipos := 0;
  1550.   readcentralheader := false; internal_stap := 0;
  1551.   internal_centralheaderfound := false;
  1552.   cfinextproc := cfinextempty;
  1553. end.
  1554.