zipviewu.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. {------8<-------------Snip---------------8<------------Snip------------8<-------}
  2. {$I-}
  3. UNIT zipviewu;
  4. (*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\\/\/\/\/\/\/\/\*)
  5. (* Unit : Zip View Date : March 23, 1994 *)
  6. (* By : John Shipley Ver : 1.0 *)
  7. (* *)
  8. (* Credits : Steve Wierenga - ZIPV.PAS found in SWAG - Got me started on the *)
  9. (* zipviewu code since ZIPV.PAS was fairly easy to read unlike *)
  10. (* some other code I had seen. *)
  11. (* *)
  12. (* Tom Guinther - ZIPPER.PAS found in ZIPPER.ZIP (1989) available *)
  13. (* on my BBS "The Brook Forest Inn 714-951-5282" This code helped *)
  14. (* clarify many things. The zipper code is probably better than *)
  15. (* this code and well documented. *)
  16. (* *)
  17. (* PkWare's APPNOTE.TXT found in PKZ110.EXE *)
  18. (* *)
  19. (* This unit is offered to the Public Domain so long as credit is given *)
  20. (* where credit is due. I accept NO liablity for what this code does to your *)
  21. (* system or your friends or anyone elses. You have the code, so you can fix *)
  22. (* it. If this code formats your hard drive and you loose your lifes work, *)
  23. (* then all I can say is "Why didn't you back it up?" *)
  24. (* *)
  25. (* Purpose: To mimic "PKUNZIP -v <filename>" output. (v2.04g) *)
  26. (* The code is pretty close to the purpose, but not perfect. *)
  27. (* *)
  28. (* Demo : *)
  29. (* *)
  30. (* PROGRAM zip_viewit; *)
  31. (* USES DOS,CRT,zipviewu; *)
  32. (* BEGIN *)
  33. (* IF PARAMCOUNT<>0 THEN *)
  34. (* BEGIN *)
  35. (* zipview(PARAMSTR(1)); *)
  36. (* END; *)
  37. (* END. *)
  38. (*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\\/\/\/\/\/\/\/\*)
  39. INTERFACE
  40. USES DOS,CRT;
  41. PROCEDURE zipview(zipfile: STRING);
  42. IMPLEMENTATION
  43. CONST hexdigit : ARRAY[0..15] OF CHAR = '0123456789abcdef';
  44. FUNCTION hexbyte(b: byte): STRING; (* Byte to Hexbyte *)
  45. BEGIN
  46. hexbyte := hexdigit[b SHR 4]+hexdigit[b AND $f];
  47. END;
  48. FUNCTION hexlong(l: LONGINT): STRING; (* Longint to Hexlong *)
  49. VAR n : ARRAY[1..4] OF BYTE ABSOLUTE l;
  50. BEGIN
  51. hexlong := hexbyte(n[4])+hexbyte(n[3])+hexbyte(n[2])+hexbyte(n[1]);
  52. END;
  53. FUNCTION lenn(s: STRING): INTEGER; (* Like LENGTH, but skips color codes *)
  54. VAR i,len : INTEGER;
  55. BEGIN
  56. len := LENGTH(s);
  57. i := 1;
  58. WHILE (i<=LENGTH(s)) DO
  59. BEGIN
  60. IF (s[i] IN [#3,'^']) THEN
  61. IF (i<LENGTH(s)) THEN
  62. BEGIN
  63. DEC(len,2);
  64. INC(i);
  65. END;
  66. INC(i);
  67. END;
  68. lenn := len;
  69. END;
  70. FUNCTION mln(s: STRING; l: INTEGER): STRING; (* Left Justify *)
  71. BEGIN
  72. WHILE (lenn(s)<l) DO s := s+' ';
  73. IF (lenn(s)>l) THEN
  74. REPEAT
  75. s := COPY(s,1,LENGTH(s)-1)
  76. UNTIL (lenn(s)=l) OR (LENGTH(s)=0);
  77. mln := s;
  78. END;
  79. FUNCTION mrn(s: STRING; l: INTEGER): STRING; (* Right Justify *)
  80. BEGIN
  81. WHILE lenn(s)<l DO s := ' '+s;
  82. IF lenn(s)>l THEN s := COPY(s,1,l);
  83. mrn := s;
  84. END;
  85. FUNCTION cstr(i: LONGINT): STRING; (* convert integer type to string *)
  86. VAR c : STRING[16];
  87. BEGIN
  88. STR(i,c);
  89. cstr := c;
  90. END;
  91. FUNCTION tch(s: STRING): STRING; (* Ensure 2 Digits *)
  92. BEGIN
  93. IF (LENGTH(s)>2) THEN s := COPY(s,LENGTH(s)-1,2)
  94. ELSE IF (LENGTH(s)=1) THEN s := '0'+s;
  95. tch := s;
  96. END;
  97. FUNCTION b2attr(a,g: BYTE): STRING; (* Byte to Attribute *)
  98. VAR attr : STRING[5];
  99. BEGIN
  100. attr := '--w- ';
  101. IF (g AND 1)=1 THEN attr[5]:='*'; (* Encrypted? *)
  102. IF (a AND 1)=1 THEN attr[3]:='r'; (* Read Only? *)
  103. IF (a AND 2)=2 THEN attr[2]:='h'; (* Hidden? *)
  104. IF (a AND 4)=4 THEN attr[1]:='s'; (* System? *)
  105. IF (a AND 8)=8 THEN attr[4]:='?'; (* Unknown at this time *)
  106. b2attr := attr;
  107. END;
  108. FUNCTION w2date(d: WORD): STRING; (* Word to Date *)
  109. VAR s : STRING;
  110. BEGIN
  111. s := tch(cstr((d SHR 5) AND 15 ))+'-'+ (* Month *)
  112. tch(cstr((d ) AND 31 ))+'-'+ (* Day *)
  113. tch(cstr(((d SHR 9) AND 127)+80)); (* Year *)
  114. w2date := s;
  115. END;
  116. FUNCTION w2time(t: WORD): STRING; (* Word to Time *)
  117. VAR s : STRING;
  118. BEGIN
  119. s := tch(cstr((t SHR 11) AND 31))+':'+ (* Hour *)
  120. tch(cstr((t SHR 5) AND 63)); (* Minute *)
  121. w2time := s;
  122. END;
  123. PROCEDURE zipview(zipfile: STRING); (* View the ZIP File *)
  124. CONST lsig = $04034B50; (* Local Signature *)
  125. csig = $02014b50; (* Central Signature *)
  126. TYPE lheader = RECORD (* Local Header *)
  127. signature : LONGINT; (* local file header signature *)
  128. version, (* version mad by *)
  129. gpflag, (* general purpose flags *)
  130. compress, (* compression method *)
  131. time,date : WORD; (* last mod file time and date *)
  132. crc32, (* crc-32 *)
  133. csize, (* compressed size *)
  134. usize : LONGINT; (* uncompressed size *)
  135. fnamelen, (* filename length *)
  136. extrafield : WORD; (* extra field length *)
  137. END;
  138. cheader = RECORD (* Central Header *)
  139. signature : LONGINT; (* central file header signature *)
  140. version : WORD; (* version made by *)
  141. vneeded : WORD; (* version needed to extract *)
  142. gpflag : ARRAY[1..2] OF BYTE;(* general purpose flags *)
  143. compress : WORD; (* compression method *)
  144. time : WORD; (* last mod file time *)
  145. date : WORD; (* last mod file date *)
  146. crc32 : LONGINT; (* crc-32 *)
  147. csize : LONGINT; (* compressed size *)
  148. usize : LONGINT; (* uncompressed size *)
  149. fnamelen : WORD; (* filename length *)
  150. extrafield : WORD; (* extra field length *)
  151. fcl : WORD; (* file comment length *)
  152. dns : WORD; (* disk number start *)
  153. ifa : WORD; (* internal file attributes *)
  154. efa : ARRAY[1..4] OF BYTE; (* external file attr *)
  155. roolh : LONGINT; (* relative offset of local header *)
  156. END;
  157. VAR z : INTEGER; (* Number of files processed counter *)
  158. totalu, (* Total bytes that were compressed *)
  159. totalc : LONGINT; (* result of total bytes being compressed *)
  160. hdr : ^cheader; (* temporary cental header file record *)
  161. f : FILE; (* file var *)
  162. s : STRING; (* archive filename string *)
  163. percent : BYTE; (* Temporary var holding percent compressed *)
  164. numfiles : WORD; (* Number of files in archive *)
  165. CONST comptypes : ARRAY[0..8] OF STRING[7] = (* Compression Types *)
  166. ('Stored ', (* Not Compressed *)
  167. 'Shrunk ', (* Shrunk *)
  168. 'Reduce1', (* Reduced 1 *)
  169. 'Reduce2', (* Reduced 2 *)
  170. 'Reduce3', (* Reduced 3 *)
  171. 'Reduce4', (* Reduced 4 *)
  172. 'Implode', (* Imploded *)
  173. 'NotSure', (* Unknown at this time *)
  174. 'DeflatN'); (* Deflated *)
  175. FUNCTION seekc(VAR f: FILE): BOOLEAN;
  176. VAR curpos : LONGINT; (* current file position *)
  177. buf : lheader; (* Temporary local header record *)
  178. ioerror : INTEGER; (* Temporary IOResult holder *)
  179. result : WORD; (* Blockread Result *)
  180. BEGIN
  181. seekc := FALSE; (* init seekc *)
  182. curpos := 0; (* init current file position *)
  183. SEEK(f,0); (* goto start of file *)
  184. BLOCKREAD(f,buf,SIZEOF(lheader),result); (* Grab first local header *)
  185. ioerror := IORESULT; (* Test for error *)
  186. WHILE (ioerror = 0) AND (buf.signature=lsig) DO (* Test if OK..continue *)
  187. BEGIN
  188. INC(numfiles); (* Increment number of files *)
  189. WITH buf DO (* Find end of local header *)
  190. curpos := FILEPOS(f)+fnamelen+extrafield+csize;
  191. SEEK(f,curpos); (* Goto end of local header *)
  192. BLOCKREAD(f,buf,SIZEOF(lheader),result); (* Grab next local header *)
  193. ioerror := IORESULT; (* Test for error *)
  194. END;
  195. IF ioerror<>0 THEN EXIT; (* If error then exit function *)
  196. IF (buf.signature=csig) THEN (* Did we find the first central header? *)
  197. BEGIN
  198. seekc := TRUE; (* Found first central header *)
  199. SEEK(f,curpos); (* Ensure we are at central headers file position *)
  200. END;
  201. END;
  202. VAR curpos : LONGINT;
  203. BEGIN
  204. numfiles := 0; (* Counter of Number of Files to Determine When Done *)
  205. z := 0; (* Counter of Number of Files Processed *)
  206. totalu := 0; (* Total Bytes of Uncompressed Files *)
  207. totalc := 0; (* Total Size after being Compressed *)
  208. NEW(hdr); (* Dynamically Allocate Memory for a Temp Header Record *)
  209. ASSIGN(f,zipfile); (* Assign Filename to File Var *)
  210. {$I-}
  211. RESET(f,1); (* Open Untyped File *)
  212. {$I+}
  213. IF IORESULT<>0 THEN (* If we get an error, exit program *)
  214. BEGIN
  215. WRITELN('Error - File not found.');
  216. HALT(253);
  217. END;
  218. IF NOT seekc(f) THEN (* Skip Local Headers and goto first Central Header *)
  219. BEGIN (* If we could not locate a Central Header *)
  220. CLOSE(f); (* Close Untyped File *)
  221. WRITELN('Error - Corrupted or Not a ZIP File.');
  222. HALT(254); (* Exit Program *)
  223. END;
  224. WRITELN(' Length Method Size Ratio Date Time CRC-32 '+
  225. ' Attr Name');
  226. WRITELN(' ------ ------ ----- ----- ---- ---- --------'+
  227. ' ---- ----');
  228. REPEAT
  229. FILLCHAR(s,SIZEOF(s),#0); (* Clear Name String *)
  230. BLOCKREAD(f,hdr^,SIZEOF(cheader)); (* Read File Header *)
  231. BLOCKREAD(f,MEM[SEG(s):OFS(s)+1],hdr^.fnamelen); (* Read Archive Name *)
  232. s[0] := CHR(hdr^.fnamelen); (* Get Archive Name Length *)
  233. IF (hdr^.signature=csig) THEN (* Is a header *)
  234. BEGIN
  235. INC(z); (* Increment File Counter *)
  236. WRITE(mrn(cstr(hdr^.usize),7)); (* Display Uncompressed Size *)
  237. WRITE(' '+mrn(comptypes[hdr^.compress],7)); (* Compression Method *)
  238. WRITE(mrn(cstr(hdr^.csize),8)); (* Display Compressed Size *)
  239. percent := ROUND(100.0-(hdr^.csize/hdr^.usize*100.0));
  240. WRITE(mrn(cstr(percent),4)+'% '); (* Display Compression Percent *)
  241. WRITE(' '+w2date(hdr^.date)+' '); (* Display Date Last Modified *)
  242. WRITE(' '+w2time(hdr^.time)+' '); (* Display Time Last Modified *)
  243. WRITE(' '+hexlong(hdr^.crc32)+' '); (* Display CRC-32 in Hex *)
  244. WRITE(b2attr(hdr^.efa[1],hdr^.gpflag[1])); (* Display Attributes *)
  245. WRITELN(' '+mln(s,13)); (* Display Archive Filename *)
  246. INC(totalu,hdr^.usize); (* Increment size uncompressed *)
  247. INC(totalc,hdr^.csize); (* Increment size compressed *)
  248. END;
  249. SEEK(f,FILEPOS(f)+hdr^.extrafield+hdr^.fcl);
  250. UNTIL (hdr^.signature<>csig) OR EOF(f) OR (z=numfiles); (* No more Files *)
  251. WRITELN(' ------ ------ --- '+
  252. ' -------');
  253. WRITE(mrn(cstr(totalu),7)+' '); (* Display Total Uncompressed *)
  254. WRITE(mrn(cstr(totalc),7)+' '); (* Display Total Compressed *)
  255. WRITE((100-TotalC/TotalU*100):3:0,'%'+mrn(' ',34)); (* Display Percent *)
  256. WRITELN(mrn(cstr(z),7)); (* Display Number of Files *)
  257. CLOSE(f); (* Close Untyped File *)
  258. DISPOSE(hdr); (* Deallocate Header Var Memory *)
  259. END;
  260. END.