unzip.pas 46 KB

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