program darc2; {$R-$U-$C-$K-} { Program: DIRARC.PAS Version: 2.0 Date: 6/1/86 Author: Steve Fox, Albuquerque ROS (505)299-5974 Revision: David W. Carroll, High Sierra RBBS (209) 296-3534 Credits: Based heavily on DARC.PAS and intended as a companion to that program. Description: Display the directory of an archive created by version 4.30 or earlier of the ARC utility (copyright 1985 by System Enhancement Associates) in a format similar to the "v"erbose command. Some minor differences in the computed values of the stowage factors may be noted due to rounding. Upadtes: 2.0 Supports ARC512 added modes. Displays mode number as item "T" as well as complete text description of arc mode. Language: Turbo Pascal Version 3.0 and later (either MS-DOS or CP/M). Usage: DIRARC arcname where arcname is the path/file name of the archive file. If the file extent is omitted, .ARC is assumed. } const BLOCKSIZE = 128; arcmarc = 26; { special archive marker } arcver = 8; { archive header version code } strlen = 80; { standard string length } fnlen = 12; { file name length - 1 } type long = record { used to simulate long (4 byte) integers } l, h : integer end; Str10 = string[10]; StrStd = string[strlen]; fntype = array [0..fnlen] of char; buftype = array [1..BLOCKSIZE] of byte; heads = record name : fntype; size : long; date : integer; time : integer; crc : integer; length : long end; hexvalue = string[2]; var endfile : boolean; hdrver : byte; arcptr : integer; arcname, extname : StrStd; arcbuf : buftype; arcfile : file; function hexval(bt : byte) : hexvalue; { Convert 8 bit value to hex } const hexcnv : array[0..15] of char = '0123456789ABCDEF'; begin hexval := hexcnv[bt shr 4] + hexcnv[bt and $0F] end; function pad(stg : StrStd; i : integer) : StrStd; { Pad string with spaces to length of i } var j : integer; begin j := length(stg); FillChar(stg[succ(j)], i - j, ' '); stg[0] := chr(i); pad := stg end; function intstr(n, w: integer): Str10; { Return a string value (width 'w')for the input integer ('n') } var stg: Str10; begin str(n:w, stg); intstr := stg end; procedure abort(msg : StrStd); { terminate the program with an error message } begin writeln('ABORT: ', msg); halt end; function fn_to_str(var fn : fntype) : StrStd; { convert strings from C format (trailing 0) to Turbo Pascal format (leading length byte). } var s : StrStd; i : integer; begin s := ''; i := 0; while fn[i] <> #0 do begin s := s + fn[i]; i := succ(i) end; fn_to_str := s end; function unsigned_to_real(u : integer) : real; { convert unsigned integer to real } { note: INT is a function that returns a REAL!!!} begin if u >= 0 then unsigned_to_real := Int(u) else if u = $8000 then unsigned_to_real := 32768.0 else unsigned_to_real := 65536.0 + u end; function long_to_real(l : long) : real; { convert long integer to a real } { note: INT is a function that returns a REAL!!! } const rcon = 65536.0; var r : real; s : (POS, NEG); begin if l.h >= 0 then begin r := Int(l.h) * rcon; s := POS end else begin s := NEG; if l.h = $8000 then r := rcon * rcon else r := Int(-l.h) * rcon end; r := r + unsigned_to_real(l.l); if s = NEG then long_to_real := -r else long_to_real := r end; procedure Read_Block; { read a block from the archive file } begin if EOF(arcfile) then endfile := TRUE else BlockRead(arcfile, arcbuf, 1); arcptr := 1 end; function get_arc : byte; { read 1 character from the archive file } begin if endfile then get_arc := 0 else begin get_arc := arcbuf[arcptr]; if arcptr = BLOCKSIZE then Read_Block else arcptr := succ(arcptr) end end; procedure fread(var buf; reclen : integer); { read a record from the archive file } var i : integer; b : array [1..strlen] of byte absolute buf; begin for i := 1 to reclen do b[i] := get_arc end; function readhdr(var hdr : heads) : boolean; { read a file header from the archive file } { FALSE = eof found; TRUE = header found } var try : integer; name : fntype; begin try := 10; if endfile then begin readhdr := FALSE; exit end; while get_arc <> arcmarc do begin if try = 0 then abort(arcname + ' is not an archive'); try := pred(try); writeln(arcname, ' is not an archive, or is out of sync'); if endfile then abort('Archive length error') end; hdrver := get_arc; if hdrver < 0 then abort('Invalid header in archive ' + arcname); if hdrver = 0 then begin { special end of file marker } readhdr := FALSE; exit end; if hdrver > arcver then begin fread(name, fnlen); writeln('Cannot handle file ', fn_to_str(name), ' in archive ', arcname); writeln('You need a newer version of this program.'); halt end; if hdrver = 1 then begin fread(hdr, sizeof(heads) - sizeof(long)); hdrver := 2; hdr.length := hdr.size end else fread(hdr, sizeof(heads)); readhdr := TRUE end; procedure PrintHeading; begin writeln; writeln('Turbo Pascal DIRARC Utility'); writeln('Version 2.0, 6/1/86'); writeln('Lists the directory of .ARC files '); writeln('created with ARC version 5.12 and earlier'); writeln end; procedure GetArcName; { get the name of the archive file } var i : integer; begin if ParamCount = 1 then arcname := ParamStr(1) else if ParamCount > 1 then abort('Too many parameters') else begin write('Enter archive filename: '); readln(arcname); if arcname = '' then abort('No file name entered'); writeln; writeln end; for i := 1 to length(arcname) do arcname[i] := UpCase(arcname[i]); if pos('.', arcname) = 0 then arcname := arcname + '.ARC' end; function int_time(time : integer) : StrStd; { Convert integer format time to printable string } var ampm : char; hour, minute : integer; line : string[6]; begin minute := (time shr 5) and $003F; hour := time shr 11; if hour > 12 then begin hour := hour - 12; ampm := 'p' end else ampm := 'a'; if hour = 0 then hour := 12; line := intstr(hour, 2) + ':' + intstr(minute, 2) + ampm; if line[4] = ' ' then line[4] := '0'; int_time := line end; function int_date(date : integer) : StrStd; { Convert standard integer format date to printable string } const month_name : array[1..12] of string[3] = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); var day, month, year : integer; line : string[9]; begin day := date and $001F; month := (date shr 5) and $000F; year := (date shr 9 + 80) mod 100; if month in [1..12] then line := month_name[month] else line := ' '; line := intstr(day, 2) + ' ' + line + ' ' + intstr(year, 2); if line[8] = ' ' then line[8] := '0'; int_date := line end; procedure open_arc; { open the archive file for input processing } begin {$I-} assign(arcfile, arcname); {$I+} if IOresult <> 0 then abort('Cannot open archive file.'); {$I-} reset(arcfile); {$I+} if IOresult <> 0 then abort('Cannot open archive file.'); endfile := FALSE; Read_Block end; procedure close_arc; { close the archive file } begin close(arcfile) end; procedure directory; const stowage : array[1..8] of string[8] = (' -None- ', ' -None- ', ' Packed ', 'Squeezed', 'LZCrunch', 'LZCrunch', 'LZW Pack','Dynam LZ'); var i, total_files, sf : integer; size_org, size_now, next_ptr, total_length, total_size : real; stg_time, stg_date : Str10; hdr : heads; begin writeln('Name Length Stowage T SF Size now Date Time CRC'); writeln('============ ======== ======== = ==== ======== ========= ====== ===='); total_files := 0; next_ptr := 0.0; total_size := 0.0; total_length := 0.0; open_arc; while readhdr(hdr) do begin extname := fn_to_str(hdr.name); total_files := succ(total_files); size_org := long_to_real(hdr.length); total_length := total_length + size_org; size_now := long_to_real(hdr.size); total_size := total_size + size_now; stg_time := int_time(hdr.time); stg_date := int_date(hdr.date); if size_org > 0 then sf := round(100.0 * (size_org - size_now) / size_org) else sf := 0; writeln( pad(extname, 12), size_org:10:0, stowage[hdrver]:10, hdrver:2, sf:5, '%', size_now:10:0, stg_date:11, stg_time:8, hexval(hi(hdr.crc)):4, hexval(lo(hdr.crc)):2); next_ptr := next_ptr + size_now + 29.0; i := trunc(next_ptr / 128.0); seek(arcfile, i); Read_Block; arcptr := succ(round(next_ptr - 128.0 * i)) end; close_arc; writeln(' ==== ======== ==== ========'); if total_length > 0 then sf := round(100.0 * (total_length - total_size) / total_length) else sf := 0; writeln( 'Total', total_files:7, total_length:10:0, ' ':10, ' ', sf:5, '%', total_size:10:0) end; begin PrintHeading; { print a heading } GetArcName; { get the archive file name } directory end.