unzip.pas 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581
  1. {$IFNDEF FPC_DOTTEDUNITS}
  2. unit Unzip;
  3. {$ENDIF FPC_DOTTEDUNITS}
  4. {$mode tp}
  5. { ----------------------------------------------------------------- }
  6. { unzip.c -- IO on .zip files using zlib
  7. Version 0.15 beta, Mar 19th, 1998,
  8. unzip.h -- IO for uncompress .zip files using zlib
  9. Version 0.15 beta, Mar 19th, 1998,
  10. Copyright (C) 1998 Gilles Vollant <[email protected]>
  11. http://www.winimage.com/zLibDll/zip.htm
  12. This unzip package allow extract file from .ZIP file, compatible
  13. with PKZip 2.04g, WinZip, InfoZip tools and compatible.
  14. Encryption and multi volume ZipFile (span) are not supported.
  15. Old compressions used by old PKZip 1.x are not supported
  16. Pascal tranlastion
  17. Copyright (C) 2000 by Jacques Nomssi Nzali
  18. For conditions of distribution and use, see copyright notice in readme.txt }
  19. interface
  20. {$ifdef WIN32}
  21. {$define Delphi}
  22. {$endif}
  23. {$IFDEF FPC_DOTTEDUNITS}
  24. uses
  25. //zutil,
  26. System.ZLib.Zbase,
  27. //Api.Z,
  28. System.ZLib.Ziputils;
  29. {$ELSE FPC_DOTTEDUNITS}
  30. uses
  31. //zutil,
  32. zbase,
  33. //zLib,
  34. ziputils;
  35. {$ENDIF FPC_DOTTEDUNITS}
  36. const
  37. UNZ_OK = (0);
  38. UNZ_END_OF_LIST_OF_FILE = (-100);
  39. UNZ_ERRNO = (Z_ERRNO);
  40. UNZ_EOF = (0);
  41. UNZ_PARAMERROR = (-102);
  42. UNZ_BADZIPFILE = (-103);
  43. UNZ_INTERNALERROR = (-104);
  44. UNZ_CRCERROR = (-105);
  45. (*
  46. { tm_unz contain date/time info }
  47. type
  48. tm_unz = record
  49. tm_sec : integer; { seconds after the minute - [0,59] }
  50. tm_min : integer; { minutes after the hour - [0,59] }
  51. tm_hour : integer; { hours since midnight - [0,23] }
  52. tm_mday : integer; { day of the month - [1,31] }
  53. tm_mon : integer; { months since January - [0,11] }
  54. tm_year : integer; { years - [1980..2044] }
  55. end;
  56. *)
  57. { unz_global_info structure contain global data about the ZIPfile
  58. These data comes from the end of central dir }
  59. type
  60. unz_global_info = record
  61. number_entry: longint; { total number of entries in
  62. the central dir on this disk }
  63. size_comment: longint; { size of the global comment of the zipfile }
  64. end;
  65. { unz_file_info contain information about a file in the zipfile }
  66. type
  67. unz_file_info = record
  68. version: longint; { version made by 2 bytes }
  69. version_needed: longint; { version needed to extract 2 bytes }
  70. flag: longint; { general purpose bit flag 2 bytes }
  71. compression_method: longint; { compression method 2 bytes }
  72. dosDate: longint; { last mod file date in Dos fmt 4 bytes }
  73. crc: longint; { crc-32 4 bytes }
  74. compressed_size: longint; { compressed size 4 bytes }
  75. uncompressed_size: longint; { uncompressed size 4 bytes }
  76. size_filename: longint; { filename length 2 bytes }
  77. size_file_extra: longint; { extra field length 2 bytes }
  78. size_file_comment: longint; { file comment length 2 bytes }
  79. disk_num_start: longint; { disk number start 2 bytes }
  80. internal_fa: longint; { internal file attributes 2 bytes }
  81. external_fa: longint; { external file attributes 4 bytes }
  82. tmu_date: tm_unz;
  83. end;
  84. unz_file_info_ptr = ^unz_file_info;
  85. function unzStringFileNameCompare(const fileName1: PAnsiChar; const fileName2: PAnsiChar; iCaseSensitivity: longint): longint;
  86. { Compare two filename (fileName1,fileName2).
  87. If iCaseSenisivity = 1 (1=true),
  88. comparision is case sensitive (like strcmp)
  89. If iCaseSenisivity = 2 (0=false),
  90. comparision is not case sensitive (like strcmpi or strcasecmp)
  91. If iCaseSenisivity = 0, case sensitivity is defaut of your
  92. operating system like 1 on Unix, 2 on Windows)
  93. }
  94. function unzOpen(const path: PAnsiChar): unzFile;
  95. { Open a Zip file. path contain the full pathname (by example,
  96. on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
  97. "zlib/zlib111.zip".
  98. If the zipfile cannot be opened (file don't exist or in not valid), the
  99. return value is NIL.
  100. Else, the return value is a unzFile Handle, usable with other function
  101. of this unzip package.
  102. }
  103. function unzClose(afile: unzFile): longint;
  104. { Close a ZipFile opened with unzipOpen.
  105. If there are files inside the .Zip opened with unzOpenCurrentFile()
  106. (see later), these files MUST be closed with unzipCloseCurrentFile()
  107. before a call unzipClose.
  108. return UNZ_OK if there is no problem. }
  109. function unzGetGlobalInfo(afile: unzFile; var pglobal_info: unz_global_info): longint;
  110. { Write info about the ZipFile in the *pglobal_info structure.
  111. No preparation of the structure is needed
  112. return UNZ_OK if there is no problem. }
  113. function unzGetGlobalComment(afile: unzFile; szComment: PAnsiChar; uSizeBuf: longint): longint;
  114. { Get the global comment string of the ZipFile, in the szComment buffer.
  115. uSizeBuf is the size of the szComment buffer.
  116. return the number of byte copied or an error code <0 }
  117. {***************************************************************************}
  118. { Unzip package allow you browse the directory of the zipfile }
  119. function unzGoToFirstFile(afile: unzFile): longint;
  120. { Set the current file of the zipfile to the first file.
  121. return UNZ_OK if there is no problem }
  122. function unzGoToNextFile(afile: unzFile): longint;
  123. { Set the current file of the zipfile to the next file.
  124. return UNZ_OK if there is no problem
  125. return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. }
  126. function unzLocateFile(afile: unzFile; const szFileName: PAnsiChar; iCaseSensitivity: longint): longint; { ZEXPORT }
  127. { Try locate the file szFileName in the zipfile.
  128. For the iCaseSensitivity signification, see unzStringFileNameCompare
  129. return value :
  130. UNZ_OK if the file is found. It becomes the current file.
  131. UNZ_END_OF_LIST_OF_FILE if the file is not found }
  132. function unzGetCurrentFileInfo(afile: unzFile; pfile_info: unz_file_info_ptr; szFileName: PAnsiChar; fileNameBufferSize: longint; extraField: pointer; extraFieldBufferSize: longint; szComment: PAnsiChar; commentBufferSize: longint): longint; { ZEXPORT }
  133. { Get Info about the current file
  134. if pfile_info<>NIL, the pfile_info^ structure will contain somes
  135. info about the current file
  136. if szFileName<>NIL, the filemane string will be copied in szFileName
  137. (fileNameBufferSize is the size of the buffer)
  138. if extraField<>NIL, the extra field information will be copied in
  139. extraField (extraFieldBufferSize is the size of the buffer).
  140. This is the Central-header version of the extra field
  141. if szComment<>NIL, the comment string of the file will be copied in
  142. szComment (commentBufferSize is the size of the buffer) }
  143. {***************************************************************************}
  144. {* for reading the content of the current zipfile, you can open it, read data
  145. from it, and close it (you can close it before reading all the file) }
  146. function unzOpenCurrentFile(afile: unzFile): longint; { ZEXPORT }
  147. { Open for reading data the current file in the zipfile.
  148. If there is no error, the return value is UNZ_OK. }
  149. function unzCloseCurrentFile(afile: unzFile): longint; { ZEXPORT }
  150. { Close the file in zip opened with unzOpenCurrentFile
  151. Return UNZ_CRCERROR if all the file was read but the CRC is not good }
  152. function unzReadCurrentFile(afile: unzFile; buf: pointer; len: cardinal): longint; { ZEXPORT }
  153. { Read bytes from the current file (opened by unzOpenCurrentFile)
  154. buf contain buffer where data must be copied
  155. len the size of buf.
  156. return the number of byte copied if somes bytes are copied
  157. return 0 if the end of file was reached
  158. return <0 with error code if there is an error
  159. (UNZ_ERRNO for IO error, or zLib error for uncompress error) }
  160. function unztell(afile: unzFile): z_off_t;
  161. { Give the current position in uncompressed data }
  162. function unzeof(afile: unzFile): longint;
  163. { return 1 if the end of file was reached, 0 elsewhere
  164. ! checks for valid params }
  165. function unzGetLocalExtrafield(afile: unzFile; buf: pointer; len: cardinal): longint;
  166. { Read extra field from the current file (opened by unzOpenCurrentFile)
  167. This is the local-header version of the extra field (sometimes, there is
  168. more info in the local-header version than in the central-header)
  169. if buf=NIL, it return the size of the local extra field
  170. if buf<>NIL, len is the size of the buffer, the extra header is copied in
  171. buf.
  172. the return value is the number of bytes copied in buf, or (if <0)
  173. the error code }
  174. { ----------------------------------------------------------------- }
  175. implementation
  176. {$IFDEF FPC_DOTTEDUNITS}
  177. uses
  178. {$ifdef Delphi}
  179. SysUtils,
  180. {$else}
  181. System.Strings,
  182. {$endif}
  183. System.ZLib.Zinflate, System.Hash.Crc;
  184. {$ELSE FPC_DOTTEDUNITS}
  185. uses
  186. {$ifdef Delphi}
  187. SysUtils,
  188. {$else}
  189. strings,
  190. {$endif}
  191. zInflate, crc;
  192. {$ENDIF FPC_DOTTEDUNITS}
  193. {$ifdef unix and not def (CASESENSITIVITYDEFAULT_YES) and \
  194. !defined(CASESENSITIVITYDEFAULT_NO)}
  195. {$define CASESENSITIVITYDEFAULT_NO}
  196. {$endif}
  197. const
  198. UNZ_BUFSIZE = Z_BUFSIZE;
  199. UNZ_MAXFILENAMEINZIP = Z_MAXFILENAMEINZIP;
  200. const
  201. unz_copyright: PAnsiChar = ' unzip 0.15 Copyright 1998 Gilles Vollant ';
  202. { unz_file_info_internal contain internal info about a file in zipfile }
  203. type
  204. unz_file_info_internal = record
  205. offset_curfile: longint; { relative offset of local header 4 bytes }
  206. end;
  207. unz_file_info_internal_ptr = ^unz_file_info_internal;
  208. { file_in_zip_read_info_s contain internal information about a file
  209. in zipfile, when reading and decompress it }
  210. type
  211. file_in_zip_read_info_s = record
  212. read_buffer: PAnsiChar; { internal buffer for compressed data }
  213. stream: z_stream; { zLib stream structure for inflate }
  214. pos_in_zipfile: longint; { position in byte on the zipfile, for fseek}
  215. stream_initialised: boolean; { flag set if stream structure is initialised}
  216. offset_local_extrafield: longint; { offset of the local extra field }
  217. size_local_extrafield: smallint; { size of the local extra field }
  218. pos_local_extrafield: longint; { position in the local extra field in read}
  219. crc32: longint; { crc32 of all data uncompressed }
  220. crc32_wait: longint; { crc32 we must obtain after decompress all }
  221. rest_read_compressed: longint; { number of byte to be decompressed }
  222. rest_read_uncompressed: longint; {number of byte to be obtained after decomp}
  223. afile: FILEptr; { io structure of the zipfile }
  224. compression_method: longint; { compression method (0=store) }
  225. byte_before_the_zipfile: longint; { byte before the zipfile, (>0 for sfx) }
  226. end;
  227. file_in_zip_read_info_s_ptr = ^file_in_zip_read_info_s;
  228. { unz_s contain internal information about the zipfile }
  229. type
  230. unz_s = record
  231. afile: FILEptr; { io structore of the zipfile }
  232. gi: unz_global_info; { public global information }
  233. byte_before_the_zipfile: longint; { byte before the zipfile, (>0 for sfx)}
  234. num_file: longint; { number of the current file in the zipfile}
  235. pos_in_central_dir: longint; { pos of the current file in the central dir}
  236. current_file_ok: boolean; { flag about the usability of the current file}
  237. central_pos: longint; { position of the beginning of the central dir}
  238. size_central_dir: longint; { size of the central directory }
  239. offset_central_dir: longint; { offset of start of central directory with
  240. respect to the starting disk number }
  241. cur_file_info: unz_file_info; { public info about the current file in zip}
  242. cur_file_info_internal: unz_file_info_internal; { private info about it}
  243. pfile_in_zip_read: file_in_zip_read_info_s_ptr; { structure about the current
  244. file if we are decompressing it }
  245. end;
  246. unz_s_ptr = ^unz_s;
  247. { ===========================================================================
  248. Read a byte from a gz_stream; update next_in and avail_in. Return EOF
  249. for end of file.
  250. IN assertion: the stream s has been sucessfully opened for reading. }
  251. function unzlocal_getByte(fin: FILEptr; var pi: longint): longint;
  252. var
  253. c: byte;
  254. err: longint;
  255. begin
  256. err := fread(@c, 1, 1, fin);
  257. if (err = 1) then
  258. begin
  259. pi := longint(c);
  260. unzlocal_getByte := UNZ_OK;
  261. {exit;}
  262. end
  263. else
  264. if feof(fin) = 1 then {if ferror(fin) then}
  265. unzlocal_getByte := UNZ_ERRNO
  266. else
  267. unzlocal_getByte := UNZ_EOF{exit;};
  268. end;
  269. { ===========================================================================
  270. Reads a long in LSB order from the given gz_stream. Sets }
  271. function unzlocal_getShort(fin: FILEptr; var pX: longint): longint;
  272. var
  273. x: longint;
  274. i: longint;
  275. err: longint;
  276. begin
  277. err := unzlocal_getByte(fin, i);
  278. x := longint(i);
  279. if (err = UNZ_OK) then
  280. err := unzlocal_getByte(fin, i);
  281. Inc(x, longint(i) shl 8);
  282. if (err = UNZ_OK) then
  283. pX := x
  284. else
  285. pX := 0;
  286. unzlocal_getShort := err;
  287. end;
  288. function unzlocal_getLong(fin: FILEptr; var pX: longint): longint;
  289. var
  290. x: longint;
  291. i: longint;
  292. err: longint;
  293. begin
  294. err := unzlocal_getByte(fin, i);
  295. x := longint(i);
  296. if (err = UNZ_OK) then
  297. err := unzlocal_getByte(fin, i);
  298. Inc(x, longint(i) shl 8);
  299. if (err = UNZ_OK) then
  300. err := unzlocal_getByte(fin, i);
  301. Inc(x, longint(i) shl 16);
  302. if (err = UNZ_OK) then
  303. err := unzlocal_getByte(fin, i);
  304. Inc(x, longint(i) shl 24);
  305. if (err = UNZ_OK) then
  306. pX := x
  307. else
  308. pX := 0;
  309. unzlocal_getLong := err;
  310. end;
  311. { My own strcmpi / strcasecmp }
  312. function strcmpcasenosensitive_internal(fileName1: PAnsiChar; fileName2: PAnsiChar): longint;
  313. var
  314. c1, c2: AnsiChar;
  315. begin
  316. repeat
  317. c1 := fileName1^;
  318. Inc(fileName1);
  319. c2 := fileName2^;
  320. Inc(fileName2);
  321. if (c1 >= 'a') and (c1 <= 'z') then
  322. Dec(c1, $20);
  323. if (c2 >= 'a') and (c2 <= 'z') then
  324. Dec(c2, $20);
  325. if (c1 = #0) then
  326. begin
  327. if c2 = #0 then
  328. strcmpcasenosensitive_internal := 0
  329. else
  330. strcmpcasenosensitive_internal := -1;
  331. exit;
  332. end;
  333. if (c2 = #0) then
  334. begin
  335. strcmpcasenosensitive_internal := 1;
  336. exit;
  337. end;
  338. if (c1 < c2) then
  339. begin
  340. strcmpcasenosensitive_internal := -1;
  341. exit;
  342. end;
  343. if (c1 > c2) then
  344. begin
  345. strcmpcasenosensitive_internal := 1;
  346. exit;
  347. end;
  348. until False;
  349. end;
  350. const
  351. CASESENSITIVITYDEFAULTVALUE = 2;
  352. function unzStringFileNameCompare(const fileName1: PAnsiChar; const fileName2: PAnsiChar; iCaseSensitivity: longint): longint; { ZEXPORT }
  353. { Compare two filename (fileName1,fileName2).
  354. If iCaseSenisivity = 1 (1=true),
  355. comparision is case sensitive (like strcmp)
  356. If iCaseSenisivity = 2 (0=false),
  357. comparision is not case sensitive (like strcmpi or strcasecmp)
  358. If iCaseSenisivity = 0, case sensitivity is defaut of your
  359. operating system like 1 on Unix, 2 on Windows)
  360. }
  361. begin
  362. if (iCaseSensitivity = 0) then
  363. iCaseSensitivity := CASESENSITIVITYDEFAULTVALUE;
  364. if (iCaseSensitivity = 1) then
  365. begin
  366. unzStringFileNameCompare := strComp(fileName1, fileName2);
  367. exit;
  368. end;
  369. unzStringFileNameCompare := strcmpcasenosensitive_internal(fileName1, fileName2);
  370. end;
  371. const
  372. BUFREADCOMMENT = $400;
  373. { Locate the Central directory of a zipfile (at the end, just before
  374. the global comment) }
  375. function unzlocal_SearchCentralDir(fin: FILEptr): longint;
  376. var
  377. buf: Pbytearray;
  378. uSizeFile: longint;
  379. uBackRead: longint;
  380. uMaxBack: longint;
  381. uPosFound: longint;
  382. var
  383. uReadSize, uReadPos: longint;
  384. i: longint;
  385. begin
  386. uMaxBack := $ffff; { maximum size of global comment }
  387. uPosFound := 0;
  388. if (fseek(fin, 0, SEEK_END) <> 0) then
  389. begin
  390. unzlocal_SearchCentralDir := 0;
  391. exit;
  392. end;
  393. uSizeFile := ftell(fin);
  394. if (uMaxBack > uSizeFile) then
  395. uMaxBack := uSizeFile;
  396. buf := Pbytearray(AllocMem(BUFREADCOMMENT + 4));
  397. if (buf = nil) then
  398. begin
  399. unzlocal_SearchCentralDir := 0;
  400. exit;
  401. end;
  402. uBackRead := 4;
  403. while (uBackRead < uMaxBack) do
  404. begin
  405. if (uBackRead + BUFREADCOMMENT > uMaxBack) then
  406. uBackRead := uMaxBack
  407. else
  408. Inc(uBackRead, BUFREADCOMMENT);
  409. uReadPos := uSizeFile - uBackRead;
  410. if ((BUFREADCOMMENT + 4) < (uSizeFile - uReadPos)) then
  411. uReadSize := (BUFREADCOMMENT + 4)
  412. else
  413. uReadSize := (uSizeFile - uReadPos);
  414. if fseek(fin, uReadPos, SEEK_SET) <> 0 then
  415. break;
  416. if fread(buf, uReadSize, 1, fin) <> 1 then
  417. break;
  418. i := uReadSize - 3;
  419. while (i > 0) do
  420. begin
  421. Dec(i);
  422. if (buf^[i] = $50) and (buf^[i + 1] = $4b) and { ENDHEADERMAGIC }
  423. (buf^[i + 2] = $05) and (buf^[i + 3] = $06) then
  424. begin
  425. uPosFound := uReadPos + i;
  426. break;
  427. end;
  428. end;
  429. if (uPosFound <> 0) then
  430. break;
  431. end;
  432. FreeMem(buf);
  433. unzlocal_SearchCentralDir := uPosFound;
  434. end;
  435. { Open a Zip file. path contain the full pathname (by example,
  436. on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
  437. "zlib/zlib111.zip".
  438. If the zipfile cannot be opened (file don't exist or in not valid), the
  439. return value is NIL.
  440. Else, the return value is a unzFile Handle, usable with other function
  441. of this unzip package.
  442. }
  443. function unzOpen(const path: PAnsiChar): unzFile; { ZEXPORT }
  444. var
  445. us: unz_s;
  446. s: unz_s_ptr;
  447. central_pos, uL: longint;
  448. fin: FILEptr;
  449. number_disk: longint; { number of the current dist, used for spaning ZIP,
  450. unsupported, always 0 }
  451. number_disk_with_CD: longint; { number the the disk with central dir,
  452. used for spaning ZIP, unsupported, always 0 }
  453. number_entry_CD: longint; { total number of entries in the central dir
  454. (same than number_entry on nospan) }
  455. err: longint;
  456. begin
  457. err := UNZ_OK;
  458. if (unz_copyright[0] <> ' ') then
  459. begin
  460. unzOpen := nil;
  461. exit;
  462. end;
  463. fin := fopen(path, fopenread);
  464. if (fin = nil) then
  465. begin
  466. unzOpen := nil;
  467. exit;
  468. end;
  469. central_pos := unzlocal_SearchCentralDir(fin);
  470. if (central_pos = 0) then
  471. err := UNZ_ERRNO;
  472. if (fseek(fin, central_pos, SEEK_SET) <> 0) then
  473. err := UNZ_ERRNO;
  474. { the signature, already checked }
  475. if (unzlocal_getLong(fin, uL) <> UNZ_OK) then
  476. err := UNZ_ERRNO;
  477. { number of this disk }
  478. if (unzlocal_getShort(fin, number_disk) <> UNZ_OK) then
  479. err := UNZ_ERRNO;
  480. { number of the disk with the start of the central directory }
  481. if (unzlocal_getShort(fin, number_disk_with_CD) <> UNZ_OK) then
  482. err := UNZ_ERRNO;
  483. { total number of entries in the central dir on this disk }
  484. if (unzlocal_getShort(fin, us.gi.number_entry) <> UNZ_OK) then
  485. err := UNZ_ERRNO;
  486. { total number of entries in the central dir }
  487. if (unzlocal_getShort(fin, number_entry_CD) <> UNZ_OK) then
  488. err := UNZ_ERRNO;
  489. if ((number_entry_CD <> us.gi.number_entry) or
  490. (number_disk_with_CD <> 0) or
  491. (number_disk <> 0)) then
  492. err := UNZ_BADZIPFILE;
  493. { size of the central directory }
  494. if (unzlocal_getLong(fin, us.size_central_dir) <> UNZ_OK) then
  495. err := UNZ_ERRNO;
  496. { offset of start of central directory with respect to the
  497. starting disk number }
  498. if (unzlocal_getLong(fin, us.offset_central_dir) <> UNZ_OK) then
  499. err := UNZ_ERRNO;
  500. { zipfile comment length }
  501. if (unzlocal_getShort(fin, us.gi.size_comment) <> UNZ_OK) then
  502. err := UNZ_ERRNO;
  503. if ((central_pos < us.offset_central_dir + us.size_central_dir) and
  504. (err = UNZ_OK)) then
  505. err := UNZ_BADZIPFILE;
  506. if (err <> UNZ_OK) then
  507. begin
  508. fclose(fin);
  509. unzOpen := nil;
  510. exit;
  511. end;
  512. us.afile := fin;
  513. us.byte_before_the_zipfile := central_pos -
  514. (us.offset_central_dir + us.size_central_dir);
  515. us.central_pos := central_pos;
  516. us.pfile_in_zip_read := nil;
  517. s := unz_s_ptr(AllocMem(sizeof(unz_s)));
  518. s^ := us;
  519. unzGoToFirstFile(unzFile(s));
  520. unzOpen := unzFile(s);
  521. end;
  522. { Close a ZipFile opened with unzipOpen.
  523. If there are files inside the .Zip opened with unzOpenCurrentFile()
  524. (see later), these files MUST be closed with unzipCloseCurrentFile()
  525. before a call unzipClose.
  526. return UNZ_OK if there is no problem. }
  527. function unzClose(afile: unzFile): longint; { ZEXPORT }
  528. var
  529. s: unz_s_ptr;
  530. begin
  531. if (afile = nil) then
  532. begin
  533. unzClose := UNZ_PARAMERROR;
  534. exit;
  535. end;
  536. s := unz_s_ptr(afile);
  537. if (s^.pfile_in_zip_read <> nil) then
  538. unzCloseCurrentFile(afile);
  539. fclose(s^.afile);
  540. FreeMem(s);
  541. unzClose := UNZ_OK;
  542. end;
  543. { Write info about the ZipFile in the pglobal_info structure.
  544. No preparation of the structure is needed
  545. return UNZ_OK if there is no problem. }
  546. function unzGetGlobalInfo(afile: unzFile; var pglobal_info: unz_global_info): longint; { ZEXPORT }
  547. var
  548. s: unz_s_ptr;
  549. begin
  550. if (afile = nil) then
  551. begin
  552. unzGetGlobalInfo := UNZ_PARAMERROR;
  553. exit;
  554. end;
  555. s := unz_s_ptr(afile);
  556. pglobal_info := s^.gi;
  557. unzGetGlobalInfo := UNZ_OK;
  558. end;
  559. { Translate date/time from Dos format to tm_unz (more easily readable) }
  560. procedure unzlocal_DosDateToTmuDate(ulDosDate: longint; var ptm: tm_unz);
  561. var
  562. uDate: longint;
  563. begin
  564. uDate := longint(ulDosDate shr 16);
  565. ptm.tm_mday := integer(uDate and $1f);
  566. ptm.tm_mon := integer((((uDate) and $1E0) div $20) - 1);
  567. ptm.tm_year := integer(((uDate and $0FE00) div $0200) + 1980);
  568. ptm.tm_hour := integer((ulDosDate and $F800) div $800);
  569. ptm.tm_min := integer((ulDosDate and $7E0) div $20);
  570. ptm.tm_sec := integer(2 * (ulDosDate and $1f));
  571. end;
  572. { Get Info about the current file in the zipfile, with internal only info }
  573. function unzlocal_GetCurrentFileInfoInternal(afile: unzFile; pfile_info: unz_file_info_ptr; pfile_info_internal: unz_file_info_internal_ptr; szFileName: PAnsiChar; fileNameBufferSize: longint; extraField: pointer; extraFieldBufferSize: longint; szComment: PAnsiChar; commentBufferSize: longint): longint;
  574. var
  575. s: unz_s_ptr;
  576. file_info: unz_file_info;
  577. file_info_internal: unz_file_info_internal;
  578. err: longint;
  579. uMagic: longint;
  580. lSeek: longint;
  581. var
  582. uSizeRead: longint;
  583. begin
  584. err := UNZ_OK;
  585. lSeek := 0;
  586. if (afile = nil) then
  587. begin
  588. unzlocal_GetCurrentFileInfoInternal := UNZ_PARAMERROR;
  589. exit;
  590. end;
  591. s := unz_s_ptr(afile);
  592. if (fseek(s^.afile,
  593. s^.pos_in_central_dir + s^.byte_before_the_zipfile, SEEK_SET) <> 0) then
  594. err := UNZ_ERRNO;
  595. { we check the magic }
  596. if (err = UNZ_OK) then
  597. if (unzlocal_getLong(s^.afile, uMagic) <> UNZ_OK) then
  598. err := UNZ_ERRNO
  599. else
  600. if (uMagic <> CENTRALHEADERMAGIC) then
  601. err := UNZ_BADZIPFILE;
  602. if (unzlocal_getShort(s^.afile, file_info.version) <> UNZ_OK) then
  603. err := UNZ_ERRNO;
  604. if (unzlocal_getShort(s^.afile, file_info.version_needed) <> UNZ_OK) then
  605. err := UNZ_ERRNO;
  606. if (unzlocal_getShort(s^.afile, file_info.flag) <> UNZ_OK) then
  607. err := UNZ_ERRNO;
  608. if (unzlocal_getShort(s^.afile, file_info.compression_method) <> UNZ_OK) then
  609. err := UNZ_ERRNO;
  610. if (unzlocal_getLong(s^.afile, file_info.dosDate) <> UNZ_OK) then
  611. err := UNZ_ERRNO;
  612. unzlocal_DosDateToTmuDate(file_info.dosDate, file_info.tmu_date);
  613. if (unzlocal_getLong(s^.afile, file_info.crc) <> UNZ_OK) then
  614. err := UNZ_ERRNO;
  615. if (unzlocal_getLong(s^.afile, file_info.compressed_size) <> UNZ_OK) then
  616. err := UNZ_ERRNO;
  617. if (unzlocal_getLong(s^.afile, file_info.uncompressed_size) <> UNZ_OK) then
  618. err := UNZ_ERRNO;
  619. if (unzlocal_getShort(s^.afile, file_info.size_filename) <> UNZ_OK) then
  620. err := UNZ_ERRNO;
  621. if (unzlocal_getShort(s^.afile, file_info.size_file_extra) <> UNZ_OK) then
  622. err := UNZ_ERRNO;
  623. if (unzlocal_getShort(s^.afile, file_info.size_file_comment) <> UNZ_OK) then
  624. err := UNZ_ERRNO;
  625. if (unzlocal_getShort(s^.afile, file_info.disk_num_start) <> UNZ_OK) then
  626. err := UNZ_ERRNO;
  627. if (unzlocal_getShort(s^.afile, file_info.internal_fa) <> UNZ_OK) then
  628. err := UNZ_ERRNO;
  629. if (unzlocal_getLong(s^.afile, file_info.external_fa) <> UNZ_OK) then
  630. err := UNZ_ERRNO;
  631. if (unzlocal_getLong(s^.afile, file_info_internal.offset_curfile) <> UNZ_OK) then
  632. err := UNZ_ERRNO;
  633. Inc(lSeek, file_info.size_filename);
  634. if ((err = UNZ_OK) and (szFileName <> nil)) then
  635. begin
  636. if (file_info.size_filename < fileNameBufferSize) then
  637. begin
  638. (szFileName +file_info.size_filename)^ := #0;
  639. uSizeRead := file_info.size_filename;
  640. end
  641. else
  642. uSizeRead := fileNameBufferSize;
  643. if (file_info.size_filename > 0) and (fileNameBufferSize > 0) then
  644. if fread(szFileName, uSizeRead, 1, s^.afile) <> 1 then
  645. err := UNZ_ERRNO;
  646. Dec(lSeek, uSizeRead);
  647. end;
  648. if ((err = UNZ_OK) and (extraField <> nil)) then
  649. begin
  650. if (file_info.size_file_extra < extraFieldBufferSize) then
  651. uSizeRead := file_info.size_file_extra
  652. else
  653. uSizeRead := extraFieldBufferSize;
  654. if (lSeek <> 0) then
  655. if (fseek(s^.afile, lSeek, SEEK_CUR) = 0) then
  656. lSeek := 0
  657. else
  658. err := UNZ_ERRNO;
  659. if ((file_info.size_file_extra > 0) and (extraFieldBufferSize > 0)) then
  660. if fread(extraField, uSizeRead, 1, s^.afile) <> 1 then
  661. err := UNZ_ERRNO;
  662. Inc(lSeek, file_info.size_file_extra - uSizeRead);
  663. end
  664. else
  665. Inc(lSeek, file_info.size_file_extra);
  666. if ((err = UNZ_OK) and (szComment <> nil)) then
  667. begin
  668. if (file_info.size_file_comment < commentBufferSize) then
  669. begin
  670. (szComment +file_info.size_file_comment)^ := #0;
  671. uSizeRead := file_info.size_file_comment;
  672. end
  673. else
  674. uSizeRead := commentBufferSize;
  675. if (lSeek <> 0) then
  676. if (fseek(s^.afile, lSeek, SEEK_CUR) = 0) then
  677. lSeek := 0
  678. else
  679. err := UNZ_ERRNO;
  680. if ((file_info.size_file_comment > 0) and (commentBufferSize > 0)) then
  681. if fread(szComment, uSizeRead, 1, s^.afile) <> 1 then
  682. err := UNZ_ERRNO;
  683. Inc(lSeek, file_info.size_file_comment - uSizeRead);
  684. end
  685. else
  686. Inc(lSeek, file_info.size_file_comment);
  687. if ((err = UNZ_OK) and (pfile_info <> nil)) then
  688. pfile_info^ := file_info;
  689. if ((err = UNZ_OK) and (pfile_info_internal <> nil)) then
  690. pfile_info_internal^ := file_info_internal;
  691. unzlocal_GetCurrentFileInfoInternal := err;
  692. end;
  693. { Write info about the ZipFile in the *pglobal_info structure.
  694. No preparation of the structure is needed
  695. return UNZ_OK if there is no problem. }
  696. function unzGetCurrentFileInfo(afile: unzFile; pfile_info: unz_file_info_ptr; szFileName: PAnsiChar; fileNameBufferSize: longint; extraField: pointer; extraFieldBufferSize: longint; szComment: PAnsiChar; commentBufferSize: longint): longint; { ZEXPORT }
  697. { Get Info about the current file
  698. if pfile_info<>NIL, the pfile_info^ structure will contain somes
  699. info about the current file
  700. if szFileName<>NIL, the filemane string will be copied in szFileName
  701. (fileNameBufferSize is the size of the buffer)
  702. if extraField<>NIL, the extra field information will be copied in
  703. extraField (extraFieldBufferSize is the size of the buffer).
  704. This is the Central-header version of the extra field
  705. if szComment<>NIL, the comment string of the file will be copied in
  706. szComment (commentBufferSize is the size of the buffer) }
  707. begin
  708. unzGetCurrentFileInfo := unzlocal_GetCurrentFileInfoInternal(afile,
  709. pfile_info, nil, szFileName, fileNameBufferSize, extraField,
  710. extraFieldBufferSize, szComment, commentBufferSize);
  711. end;
  712. { Set the current file of the zipfile to the first file.
  713. return UNZ_OK if there is no problem }
  714. function unzGoToFirstFile(afile: unzFile): longint; { ZEXPORT }
  715. var
  716. err: longint;
  717. s: unz_s_ptr;
  718. begin
  719. if (afile = nil) then
  720. begin
  721. unzGoToFirstFile := UNZ_PARAMERROR;
  722. exit;
  723. end;
  724. s := unz_s_ptr(afile);
  725. s^.pos_in_central_dir := s^.offset_central_dir;
  726. s^.num_file := 0;
  727. err := unzlocal_GetCurrentFileInfoInternal(afile, @s^.cur_file_info, @s^.cur_file_info_internal, nil, 0, nil, 0, nil, 0);
  728. s^.current_file_ok := (err = UNZ_OK);
  729. unzGoToFirstFile := err;
  730. end;
  731. { Set the current file of the zipfile to the next file.
  732. return UNZ_OK if there is no problem
  733. return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. }
  734. function unzGoToNextFile(afile: unzFile): longint; { ZEXPORT }
  735. var
  736. s: unz_s_ptr;
  737. err: longint;
  738. begin
  739. if (afile = nil) then
  740. begin
  741. unzGoToNextFile := UNZ_PARAMERROR;
  742. exit;
  743. end;
  744. s := unz_s_ptr(afile);
  745. if not s^.current_file_ok then
  746. begin
  747. unzGoToNextFile := UNZ_END_OF_LIST_OF_FILE;
  748. exit;
  749. end;
  750. if (s^.num_file + 1 = s^.gi.number_entry) then
  751. begin
  752. unzGoToNextFile := UNZ_END_OF_LIST_OF_FILE;
  753. exit;
  754. end;
  755. Inc(s^.pos_in_central_dir,
  756. SIZECENTRALDIRITEM + s^.cur_file_info.size_filename +
  757. s^.cur_file_info.size_file_extra + s^.cur_file_info.size_file_comment);
  758. Inc(s^.num_file);
  759. err := unzlocal_GetCurrentFileInfoInternal(afile, @s^.cur_file_info, @s^.cur_file_info_internal, nil, 0, nil, 0, nil, 0);
  760. s^.current_file_ok := (err = UNZ_OK);
  761. unzGoToNextFile := err;
  762. end;
  763. { Try locate the file szFileName in the zipfile.
  764. For the iCaseSensitivity signification, see unzStringFileNameCompare
  765. return value :
  766. UNZ_OK if the file is found. It becomes the current file.
  767. UNZ_END_OF_LIST_OF_FILE if the file is not found }
  768. function unzLocateFile(afile: unzFile; const szFileName: PAnsiChar; iCaseSensitivity: longint): longint; { ZEXPORT }
  769. var
  770. s: unz_s_ptr;
  771. err: longint;
  772. num_fileSaved: longint;
  773. pos_in_central_dirSaved: longint;
  774. var
  775. szCurrentFileName: array[0..UNZ_MAXFILENAMEINZIP + 1 - 1] of AnsiChar;
  776. begin
  777. if (afile = nil) then
  778. begin
  779. unzLocateFile := UNZ_PARAMERROR;
  780. exit;
  781. end;
  782. if (strlen(szFileName) >= UNZ_MAXFILENAMEINZIP) then
  783. begin
  784. unzLocateFile := UNZ_PARAMERROR;
  785. exit;
  786. end;
  787. s := unz_s_ptr(afile);
  788. if (not s^.current_file_ok) then
  789. begin
  790. unzLocateFile := UNZ_END_OF_LIST_OF_FILE;
  791. exit;
  792. end;
  793. num_fileSaved := s^.num_file;
  794. pos_in_central_dirSaved := s^.pos_in_central_dir;
  795. err := unzGoToFirstFile(afile);
  796. while (err = UNZ_OK) do
  797. begin
  798. unzGetCurrentFileInfo(afile, nil,
  799. szCurrentFileName, sizeof(szCurrentFileName) - 1, nil, 0, nil, 0);
  800. if (unzStringFileNameCompare(szCurrentFileName,
  801. szFileName, iCaseSensitivity) = 0) then
  802. begin
  803. unzLocateFile := UNZ_OK;
  804. exit;
  805. end;
  806. err := unzGoToNextFile(afile);
  807. end;
  808. s^.num_file := num_fileSaved;
  809. s^.pos_in_central_dir := pos_in_central_dirSaved;
  810. unzLocateFile := err;
  811. end;
  812. { Read the local header of the current zipfile
  813. Check the coherency of the local header and info in the end of central
  814. directory about this file
  815. store in *piSizeVar the size of extra info in local header
  816. (filename and size of extra field data) }
  817. function unzlocal_CheckCurrentFileCoherencyHeader(s: unz_s_ptr; var piSizeVar: longint; var poffset_local_extrafield: longint; var psize_local_extrafield: integer): longint;
  818. var
  819. uMagic, uData, uFlags: longint;
  820. size_filename: longint;
  821. size_extra_field: longint;
  822. err: longint;
  823. begin
  824. err := UNZ_OK;
  825. piSizeVar := 0;
  826. poffset_local_extrafield := 0;
  827. psize_local_extrafield := 0;
  828. if (fseek(s^.afile, s^.cur_file_info_internal.offset_curfile +
  829. s^.byte_before_the_zipfile, SEEK_SET) <> 0) then
  830. begin
  831. unzlocal_CheckCurrentFileCoherencyHeader := UNZ_ERRNO;
  832. exit;
  833. end;
  834. if (err = UNZ_OK) then
  835. if (unzlocal_getLong(s^.afile, uMagic) <> UNZ_OK) then
  836. err := UNZ_ERRNO
  837. else
  838. if (uMagic <> $04034b50) then
  839. err := UNZ_BADZIPFILE;
  840. if (unzlocal_getShort(s^.afile, uData) <> UNZ_OK) then
  841. err := UNZ_ERRNO;
  842. {
  843. else
  844. if ((err=UNZ_OK) and (uData<>s^.cur_file_info.wVersion)) then
  845. err := UNZ_BADZIPFILE;
  846. }
  847. if (unzlocal_getShort(s^.afile, uFlags) <> UNZ_OK) then
  848. err := UNZ_ERRNO;
  849. if (unzlocal_getShort(s^.afile, uData) <> UNZ_OK) then
  850. err := UNZ_ERRNO
  851. else
  852. if ((err = UNZ_OK) and (uData <> s^.cur_file_info.compression_method)) then
  853. err := UNZ_BADZIPFILE;
  854. if ((err = UNZ_OK) and (s^.cur_file_info.compression_method <> 0) and
  855. (s^.cur_file_info.compression_method <> Z_DEFLATED)) then
  856. err := UNZ_BADZIPFILE;
  857. if (unzlocal_getLong(s^.afile, uData) <> UNZ_OK) then { date/time }
  858. err := UNZ_ERRNO;
  859. if (unzlocal_getLong(s^.afile, uData) <> UNZ_OK) then { crc }
  860. err := UNZ_ERRNO
  861. else
  862. if ((err = UNZ_OK) and (uData <> s^.cur_file_info.crc) and
  863. ((uFlags and 8) = 0)) then
  864. err := UNZ_BADZIPFILE;
  865. if (unzlocal_getLong(s^.afile, uData) <> UNZ_OK) then { size compr }
  866. err := UNZ_ERRNO
  867. else
  868. if ((err = UNZ_OK) and (uData <> s^.cur_file_info.compressed_size) and
  869. ((uFlags and 8) = 0)) then
  870. err := UNZ_BADZIPFILE;
  871. if (unzlocal_getLong(s^.afile, uData) <> UNZ_OK) then { size uncompr }
  872. err := UNZ_ERRNO
  873. else
  874. if ((err = UNZ_OK) and (uData <> s^.cur_file_info.uncompressed_size) and
  875. ((uFlags and 8) = 0)) then
  876. err := UNZ_BADZIPFILE;
  877. if (unzlocal_getShort(s^.afile, size_filename) <> UNZ_OK) then
  878. err := UNZ_ERRNO
  879. else
  880. if ((err = UNZ_OK) and (size_filename <> s^.cur_file_info.size_filename)) then
  881. err := UNZ_BADZIPFILE;
  882. Inc(piSizeVar, integer(size_filename));
  883. if (unzlocal_getShort(s^.afile, size_extra_field) <> UNZ_OK) then
  884. err := UNZ_ERRNO;
  885. poffset_local_extrafield := s^.cur_file_info_internal.offset_curfile +
  886. SIZEZIPLOCALHEADER + size_filename;
  887. psize_local_extrafield := integer(size_extra_field);
  888. Inc(piSizeVar, integer(size_extra_field));
  889. unzlocal_CheckCurrentFileCoherencyHeader := err;
  890. end;
  891. { Open for reading data the current file in the zipfile.
  892. If there is no error, the return value is UNZ_OK. }
  893. function unzOpenCurrentFile(afile: unzFile): longint; { ZEXPORT }
  894. var
  895. err: longint;
  896. Store: boolean;
  897. iSizeVar: longint;
  898. s: unz_s_ptr;
  899. pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
  900. offset_local_extrafield: longint; { offset of the local extra field }
  901. size_local_extrafield: smallint; { size of the local extra field }
  902. begin
  903. err := UNZ_OK;
  904. if (afile = nil) then
  905. begin
  906. unzOpenCurrentFile := UNZ_PARAMERROR;
  907. exit;
  908. end;
  909. s := unz_s_ptr(afile);
  910. if not s^.current_file_ok then
  911. begin
  912. unzOpenCurrentFile := UNZ_PARAMERROR;
  913. exit;
  914. end;
  915. if (s^.pfile_in_zip_read <> nil) then
  916. unzCloseCurrentFile(afile);
  917. if (unzlocal_CheckCurrentFileCoherencyHeader(s, iSizeVar,
  918. offset_local_extrafield, size_local_extrafield) <> UNZ_OK) then
  919. begin
  920. unzOpenCurrentFile := UNZ_BADZIPFILE;
  921. exit;
  922. end;
  923. pfile_in_zip_read_info := file_in_zip_read_info_s_ptr(
  924. AllocMem(sizeof(file_in_zip_read_info_s)));
  925. if (pfile_in_zip_read_info = nil) then
  926. begin
  927. unzOpenCurrentFile := UNZ_INTERNALERROR;
  928. exit;
  929. end;
  930. pfile_in_zip_read_info^.read_buffer := PAnsiChar(AllocMem(UNZ_BUFSIZE));
  931. pfile_in_zip_read_info^.offset_local_extrafield := offset_local_extrafield;
  932. pfile_in_zip_read_info^.size_local_extrafield := size_local_extrafield;
  933. pfile_in_zip_read_info^.pos_local_extrafield := 0;
  934. if (pfile_in_zip_read_info^.read_buffer = nil) then
  935. begin
  936. FreeMem(pfile_in_zip_read_info);
  937. unzOpenCurrentFile := UNZ_INTERNALERROR;
  938. exit;
  939. end;
  940. pfile_in_zip_read_info^.stream_initialised := False;
  941. if ((s^.cur_file_info.compression_method <> 0) and
  942. (s^.cur_file_info.compression_method <> Z_DEFLATED)) then
  943. err := UNZ_BADZIPFILE;
  944. Store := s^.cur_file_info.compression_method = 0;
  945. pfile_in_zip_read_info^.crc32_wait := s^.cur_file_info.crc;
  946. pfile_in_zip_read_info^.crc32 := 0;
  947. pfile_in_zip_read_info^.compression_method := s^.cur_file_info.compression_method;
  948. pfile_in_zip_read_info^.afile := s^.afile;
  949. pfile_in_zip_read_info^.byte_before_the_zipfile := s^.byte_before_the_zipfile;
  950. pfile_in_zip_read_info^.stream.total_out := 0;
  951. if (not Store) then
  952. begin
  953. err := inflateInit2(pfile_in_zip_read_info^.stream, -MAX_WBITS);
  954. if (err = Z_OK) then
  955. pfile_in_zip_read_info^.stream_initialised := True;
  956. { windowBits is passed < 0 to tell that there is no zlib header.
  957. Note that in this case inflate *requires* an extra "dummy" byte
  958. after the compressed stream in order to complete decompression and
  959. return Z_STREAM_END.
  960. In unzip, i don't wait absolutely Z_STREAM_END because I known the
  961. size of both compressed and uncompressed data }
  962. end;
  963. pfile_in_zip_read_info^.rest_read_compressed := s^.cur_file_info.compressed_size;
  964. pfile_in_zip_read_info^.rest_read_uncompressed := s^.cur_file_info.uncompressed_size;
  965. pfile_in_zip_read_info^.pos_in_zipfile :=
  966. s^.cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar;
  967. pfile_in_zip_read_info^.stream.avail_in := 0;
  968. s^.pfile_in_zip_read := pfile_in_zip_read_info;
  969. unzOpenCurrentFile := UNZ_OK;
  970. end;
  971. { Read bytes from the current file (opened by unzOpenCurrentFile)
  972. buf contain buffer where data must be copied
  973. len the size of buf.
  974. return the number of byte copied if somes bytes are copied
  975. return 0 if the end of file was reached
  976. return <0 with error code if there is an error
  977. (UNZ_ERRNO for IO error, or zLib error for uncompress error) }
  978. function unzReadCurrentFile(afile: unzFile; buf: pointer; len: cardinal): longint; { ZEXPORT }
  979. var
  980. err: longint;
  981. iRead: Longint;
  982. s: unz_s_ptr;
  983. pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
  984. var
  985. uReadThis: longint;
  986. var
  987. uDoCopy, i: longint;
  988. var
  989. uTotalOutBefore, uTotalOutAfter: longint;
  990. bufBefore: pbyte;
  991. uOutThis: longint;
  992. flush: longint;
  993. begin
  994. err := UNZ_OK;
  995. iRead := 0;
  996. if (afile = nil) then
  997. begin
  998. unzReadCurrentFile := UNZ_PARAMERROR;
  999. exit;
  1000. end;
  1001. s := unz_s_ptr(afile);
  1002. pfile_in_zip_read_info := s^.pfile_in_zip_read;
  1003. if (pfile_in_zip_read_info = nil) then
  1004. begin
  1005. unzReadCurrentFile := UNZ_PARAMERROR;
  1006. exit;
  1007. end;
  1008. if ((pfile_in_zip_read_info^.read_buffer = nil)) then
  1009. begin
  1010. unzReadCurrentFile := UNZ_END_OF_LIST_OF_FILE;
  1011. exit;
  1012. end;
  1013. if (len = 0) then
  1014. begin
  1015. unzReadCurrentFile := 0;
  1016. exit;
  1017. end;
  1018. pfile_in_zip_read_info^.stream.next_out := pbyte(buf);
  1019. pfile_in_zip_read_info^.stream.avail_out := len;
  1020. if (len > pfile_in_zip_read_info^.rest_read_uncompressed) then
  1021. pfile_in_zip_read_info^.stream.avail_out :=
  1022. pfile_in_zip_read_info^.rest_read_uncompressed;
  1023. while (pfile_in_zip_read_info^.stream.avail_out > 0) do
  1024. begin
  1025. if ((pfile_in_zip_read_info^.stream.avail_in = 0) and
  1026. (pfile_in_zip_read_info^.rest_read_compressed > 0)) then
  1027. begin
  1028. uReadThis := UNZ_BUFSIZE;
  1029. if (pfile_in_zip_read_info^.rest_read_compressed < uReadThis) then
  1030. uReadThis := pfile_in_zip_read_info^.rest_read_compressed;
  1031. if (uReadThis = 0) then
  1032. begin
  1033. unzReadCurrentFile := UNZ_EOF;
  1034. exit;
  1035. end;
  1036. if (fseek(pfile_in_zip_read_info^.afile,
  1037. pfile_in_zip_read_info^.pos_in_zipfile +
  1038. pfile_in_zip_read_info^.byte_before_the_zipfile, SEEK_SET) <> 0) then
  1039. begin
  1040. unzReadCurrentFile := UNZ_ERRNO;
  1041. exit;
  1042. end;
  1043. if fread(pfile_in_zip_read_info^.read_buffer, uReadThis, 1,
  1044. pfile_in_zip_read_info^.afile) <> 1 then
  1045. begin
  1046. unzReadCurrentFile := UNZ_ERRNO;
  1047. exit;
  1048. end;
  1049. Inc(pfile_in_zip_read_info^.pos_in_zipfile, uReadThis);
  1050. Dec(pfile_in_zip_read_info^.rest_read_compressed, uReadThis);
  1051. pfile_in_zip_read_info^.stream.next_in :=
  1052. pbyte(pfile_in_zip_read_info^.read_buffer);
  1053. pfile_in_zip_read_info^.stream.avail_in := uReadThis;
  1054. end;
  1055. if (pfile_in_zip_read_info^.compression_method = 0) then
  1056. begin
  1057. if (pfile_in_zip_read_info^.stream.avail_out <
  1058. pfile_in_zip_read_info^.stream.avail_in) then
  1059. uDoCopy := pfile_in_zip_read_info^.stream.avail_out
  1060. else
  1061. uDoCopy := pfile_in_zip_read_info^.stream.avail_in;
  1062. for i := 0 to uDoCopy - 1 do
  1063. Pbytearray(pfile_in_zip_read_info^.stream.next_out)^[i] :=
  1064. Pbytearray(pfile_in_zip_read_info^.stream.next_in)^[i];
  1065. pfile_in_zip_read_info^.crc32 := crc32(pfile_in_zip_read_info^.crc32,
  1066. pfile_in_zip_read_info^.stream.next_out, uDoCopy);
  1067. Dec(pfile_in_zip_read_info^.rest_read_uncompressed, uDoCopy);
  1068. Dec(pfile_in_zip_read_info^.stream.avail_in, uDoCopy);
  1069. Dec(pfile_in_zip_read_info^.stream.avail_out, uDoCopy);
  1070. Inc(pfile_in_zip_read_info^.stream.next_out, uDoCopy);
  1071. Inc(pfile_in_zip_read_info^.stream.next_in, uDoCopy);
  1072. Inc(pfile_in_zip_read_info^.stream.total_out, uDoCopy);
  1073. Inc(iRead, uDoCopy);
  1074. end
  1075. else
  1076. begin
  1077. flush := Z_SYNC_FLUSH;
  1078. uTotalOutBefore := pfile_in_zip_read_info^.stream.total_out;
  1079. bufBefore := pfile_in_zip_read_info^.stream.next_out;
  1080. {
  1081. if ((pfile_in_zip_read_info^.rest_read_uncompressed =
  1082. pfile_in_zip_read_info^.stream.avail_out) and
  1083. (pfile_in_zip_read_info^.rest_read_compressed = 0)) then
  1084. flush := Z_FINISH;
  1085. }
  1086. err := inflate(pfile_in_zip_read_info^.stream, flush);
  1087. uTotalOutAfter := pfile_in_zip_read_info^.stream.total_out;
  1088. uOutThis := uTotalOutAfter - uTotalOutBefore;
  1089. pfile_in_zip_read_info^.crc32 :=
  1090. crc32(pfile_in_zip_read_info^.crc32, bufBefore, uOutThis);
  1091. Dec(pfile_in_zip_read_info^.rest_read_uncompressed, uOutThis);
  1092. Inc(iRead, uTotalOutAfter - uTotalOutBefore);
  1093. if (err = Z_STREAM_END) then
  1094. begin
  1095. if iRead = 0 then
  1096. unzReadCurrentFile := UNZ_EOF
  1097. else
  1098. unzReadCurrentFile := iRead;
  1099. exit;
  1100. end;
  1101. if (err <> Z_OK) then
  1102. break;
  1103. end;
  1104. end; { while }
  1105. if (err = Z_OK) then
  1106. begin
  1107. unzReadCurrentFile := iRead;
  1108. exit;
  1109. end;
  1110. unzReadCurrentFile := err;
  1111. end;
  1112. { Give the current position in uncompressed data }
  1113. function unztell(afile: unzFile): z_off_t; { ZEXPORT }
  1114. var
  1115. s: unz_s_ptr;
  1116. pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
  1117. begin
  1118. if (afile = nil) then
  1119. begin
  1120. unztell := UNZ_PARAMERROR;
  1121. exit;
  1122. end;
  1123. s := unz_s_ptr(afile);
  1124. pfile_in_zip_read_info := s^.pfile_in_zip_read;
  1125. if (pfile_in_zip_read_info = nil) then
  1126. begin
  1127. unztell := UNZ_PARAMERROR;
  1128. exit;
  1129. end;
  1130. unztell := z_off_t(pfile_in_zip_read_info^.stream.total_out);
  1131. end;
  1132. { return 1 (TRUE) if the end of file was reached, 0 elsewhere }
  1133. function unzeof(afile: unzFile): longint;
  1134. var
  1135. s: unz_s_ptr;
  1136. pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
  1137. begin
  1138. if (afile = nil) then
  1139. begin
  1140. unzeof := UNZ_PARAMERROR;
  1141. exit;
  1142. end;
  1143. s := unz_s_ptr(afile);
  1144. pfile_in_zip_read_info := s^.pfile_in_zip_read;
  1145. if (pfile_in_zip_read_info = nil) then
  1146. begin
  1147. unzeof := UNZ_PARAMERROR;
  1148. exit;
  1149. end;
  1150. if (pfile_in_zip_read_info^.rest_read_uncompressed = 0) then
  1151. unzeof := 1
  1152. else
  1153. unzeof := 0;
  1154. end;
  1155. { Read extra field from the current file (opened by unzOpenCurrentFile)
  1156. This is the local-header version of the extra field (sometimes, there is
  1157. more info in the local-header version than in the central-header)
  1158. if buf=NIL, it return the size of the local extra field
  1159. if buf<>NIL, len is the size of the buffer, the extra header is copied in
  1160. buf.
  1161. the return value is the number of bytes copied in buf, or (if <0)
  1162. the error code }
  1163. function unzGetLocalExtrafield(afile: unzFile; buf: pointer; len: cardinal): longint;
  1164. var
  1165. s: unz_s_ptr;
  1166. pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
  1167. read_now: longint;
  1168. size_to_read: longint;
  1169. begin
  1170. if (afile = nil) then
  1171. begin
  1172. unzGetLocalExtrafield := UNZ_PARAMERROR;
  1173. exit;
  1174. end;
  1175. s := unz_s_ptr(afile);
  1176. pfile_in_zip_read_info := s^.pfile_in_zip_read;
  1177. if (pfile_in_zip_read_info = nil) then
  1178. begin
  1179. unzGetLocalExtrafield := UNZ_PARAMERROR;
  1180. exit;
  1181. end;
  1182. size_to_read := (pfile_in_zip_read_info^.size_local_extrafield -
  1183. pfile_in_zip_read_info^.pos_local_extrafield);
  1184. if (buf = nil) then
  1185. begin
  1186. unzGetLocalExtrafield := longint(size_to_read);
  1187. exit;
  1188. end;
  1189. if (len > size_to_read) then
  1190. read_now := size_to_read
  1191. else
  1192. read_now := len;
  1193. if (read_now = 0) then
  1194. begin
  1195. unzGetLocalExtrafield := 0;
  1196. exit;
  1197. end;
  1198. if (fseek(pfile_in_zip_read_info^.afile,
  1199. pfile_in_zip_read_info^.offset_local_extrafield +
  1200. pfile_in_zip_read_info^.pos_local_extrafield, SEEK_SET) <> 0) then
  1201. begin
  1202. unzGetLocalExtrafield := UNZ_ERRNO;
  1203. exit;
  1204. end;
  1205. if fread(buf, size_to_read, 1, pfile_in_zip_read_info^.afile) <> 1 then
  1206. begin
  1207. unzGetLocalExtrafield := UNZ_ERRNO;
  1208. exit;
  1209. end;
  1210. unzGetLocalExtrafield := longint(read_now);
  1211. end;
  1212. { Close the file in zip opened with unzOpenCurrentFile
  1213. Return UNZ_CRCERROR if all the file was read but the CRC is not good }
  1214. function unzCloseCurrentFile(afile: unzFile): longint; { ZEXPORT }
  1215. var
  1216. err: longint;
  1217. s: unz_s_ptr;
  1218. pfile_in_zip_read_info: file_in_zip_read_info_s_ptr;
  1219. begin
  1220. err := UNZ_OK;
  1221. if (afile = nil) then
  1222. begin
  1223. unzCloseCurrentFile := UNZ_PARAMERROR;
  1224. exit;
  1225. end;
  1226. s := unz_s_ptr(afile);
  1227. pfile_in_zip_read_info := s^.pfile_in_zip_read;
  1228. if (pfile_in_zip_read_info = nil) then
  1229. begin
  1230. unzCloseCurrentFile := UNZ_PARAMERROR;
  1231. exit;
  1232. end;
  1233. if (pfile_in_zip_read_info^.rest_read_uncompressed = 0) then
  1234. if (pfile_in_zip_read_info^.crc32 <> pfile_in_zip_read_info^.crc32_wait) then
  1235. err := UNZ_CRCERROR;
  1236. FreeMem(pfile_in_zip_read_info^.read_buffer);
  1237. pfile_in_zip_read_info^.read_buffer := nil;
  1238. if (pfile_in_zip_read_info^.stream_initialised) then
  1239. inflateEnd(pfile_in_zip_read_info^.stream);
  1240. pfile_in_zip_read_info^.stream_initialised := False;
  1241. FreeMem(pfile_in_zip_read_info);
  1242. s^.pfile_in_zip_read := nil;
  1243. unzCloseCurrentFile := err;
  1244. end;
  1245. { Get the global comment string of the ZipFile, in the szComment buffer.
  1246. uSizeBuf is the size of the szComment buffer.
  1247. return the number of byte copied or an error code <0 }
  1248. function unzGetGlobalComment(afile: unzFile; szComment: PAnsiChar; uSizeBuf: longint): longint; { ZEXPORT }
  1249. var
  1250. s: unz_s_ptr;
  1251. uReadThis: longint;
  1252. begin
  1253. if (afile = nil) then
  1254. begin
  1255. unzGetGlobalComment := UNZ_PARAMERROR;
  1256. exit;
  1257. end;
  1258. s := unz_s_ptr(afile);
  1259. uReadThis := uSizeBuf;
  1260. if (uReadThis > s^.gi.size_comment) then
  1261. uReadThis := s^.gi.size_comment;
  1262. if (fseek(s^.afile, s^.central_pos + 22, SEEK_SET) <> 0) then
  1263. begin
  1264. unzGetGlobalComment := UNZ_ERRNO;
  1265. exit;
  1266. end;
  1267. if (uReadThis > 0) then
  1268. begin
  1269. szComment^ := #0;
  1270. if fread(szComment, uReadThis, 1, s^.afile) <> 1 then
  1271. begin
  1272. unzGetGlobalComment := UNZ_ERRNO;
  1273. exit;
  1274. end;
  1275. end;
  1276. if ((szComment <> nil) and (uSizeBuf > s^.gi.size_comment)) then
  1277. (szComment +s^.gi.size_comment)^ := #0;
  1278. unzGetGlobalComment := longint(uReadThis);
  1279. end;
  1280. end.