/src/zziplib/zzip/fseeko.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 685 lines · 458 code · 48 blank · 179 comment · 112 complexity · d93b017247a53ff2529a54aaf6407560 MD5 · raw file

  1. /*
  2. * NOTE: this is part of libzzipfseeko (i.e. it is not libzzip).
  3. * ==================
  4. *
  5. * These routines are fully independent from the traditional zzip
  6. * implementation. They assume a readonly seekable stdio handle
  7. * representing a complete zip file. The functions show how to
  8. * parse the structure, find files and return a decoded bytestream.
  9. *
  10. * These routines are a bit simple and really here for documenting
  11. * the way to access a zip file. The complexity of zip access comes
  12. * from staggered reading of bytes and reposition of a filepointer in
  13. * a big archive with lots of files and long compressed datastreams.
  14. * Plus varaints of drop-in stdio replacements, obfuscation routines,
  15. * auto fileextensions, drop-in dirent replacements, and so on...
  16. *
  17. * btw, we can _not_ use fgetpos/fsetpos since an fpos_t has no asserted
  18. * relation to a linear seek value as specified in zip info headers. In
  19. * general it is not a problem if your system has no fseeko/ftello pair
  20. * since we can fallback to fseek/ftell which limits the zip disk size
  21. * to 2MiBs but the zip-storable seek values are 32bit limited anyway.
  22. *
  23. * Author:
  24. * Guido Draheim <guidod@gmx.de>
  25. *
  26. * Copyright (c) 2003,2004 Guido Draheim
  27. * All rights reserved,
  28. * use under the restrictions of the
  29. * Lesser GNU General Public License
  30. * or alternatively the restrictions
  31. * of the Mozilla Public License 1.1
  32. */
  33. #define _LARGEFILE_SOURCE 1
  34. #define _ZZIP_ENTRY_STRUCT 1
  35. #include <zzip/fseeko.h>
  36. #include <zzip/fetch.h>
  37. #include <zzip/__mmap.h>
  38. #include <zzip/__fnmatch.h>
  39. #include <assert.h>
  40. #include <stdlib.h>
  41. #include <sys/stat.h>
  42. #if defined ZZIP_HAVE_STRING_H
  43. #include <string.h>
  44. #elif defined ZZIP_HAVE_STRINGS_H
  45. #include <strings.h>
  46. #endif
  47. #if defined ZZIP_HAVE_STDINT_H
  48. #include <stdint.h>
  49. #endif
  50. #if __STDC_VERSION__+0 > 199900L
  51. #define ___
  52. #define ____
  53. #else
  54. #define ___ {
  55. #define ____ }
  56. #endif
  57. #ifndef ZZIP_HAVE_FSEEKO
  58. #define fseeko fseek
  59. #define ftello ftell
  60. #endif
  61. /* note that the struct zzip_entry inherits the zzip_disk_entry values
  62. * and usually carries a copy of its values (in disk format!). To make the
  63. * following code more readable, we use a shorthand notation for the
  64. * upcast needed in C (not needed in C++) as "disk_(entry)".
  65. */
  66. #ifdef __zzip_entry_extends_zzip_disk_entry
  67. #define disk_(_entry_) _entry_
  68. #else
  69. #define disk_(_entry_) (& (_entry_)->head)
  70. #endif
  71. /* we try to round all seeks to the pagesize - since we do not use
  72. * the sys/mmap interface we have to guess a good value here: */
  73. #define PAGESIZE 8192
  74. /* ====================================================================== */
  75. /* helper functions */
  76. /** => zzip_entry_data_offset
  77. * This functions read the correspoding struct zzip_file_header from
  78. * the zip disk of the given "entry". The returned off_t points to the
  79. * end of the file_header where the current fseek pointer has stopped.
  80. * This is used to immediatly parse out any filename/extras block following
  81. * the file_header. The return value is null on error.
  82. */
  83. static zzip_off_t
  84. zzip_entry_fread_file_header(ZZIP_ENTRY * entry,
  85. struct zzip_file_header *file_header)
  86. {
  87. if (! entry || ! file_header)
  88. return 0;
  89. ___ zzip_off_t offset = zzip_disk_entry_fileoffset(disk_(entry));
  90. if (0 > offset || offset >= entry->disksize)
  91. return 0;
  92. if (fseeko(entry->diskfile, offset, SEEK_SET) == -1) return 0;
  93. return (fread(file_header, sizeof(*file_header), 1, entry->diskfile)
  94. ? offset + sizeof(*file_header) : 0);
  95. ____;
  96. }
  97. /** helper functions for (fseeko) zip access api
  98. *
  99. * This functions returns the seekval offset of the data portion of the
  100. * file referenced by the given zzip_entry. It requires an intermediate
  101. * check of the file_header structure (i.e. it reads it from disk). After
  102. * this call, the contained diskfile readposition is already set to the
  103. * data_offset returned here. On error -1 is returned.
  104. */
  105. zzip_off_t
  106. zzip_entry_data_offset(ZZIP_ENTRY * entry)
  107. {
  108. struct zzip_file_header file_header;
  109. if (! entry)
  110. return -1;
  111. ___ zzip_off_t offset = zzip_entry_fread_file_header(entry, &file_header);
  112. if (! offset)
  113. return -1;
  114. offset += zzip_file_header_sizeof_tails(&file_header);
  115. if (fseeko(entry->diskfile, offset, SEEK_SET) == -1)
  116. return -1;
  117. return offset;
  118. ____;
  119. }
  120. /** => zzip_entry_data_offset
  121. * This function is a big helper despite its little name: in a zip file the
  122. * encoded filenames are usually NOT zero-terminated but for common usage
  123. * with libc we need it that way. Secondly, the filename SHOULD be present
  124. * in the zip central directory but if not then we fallback to the filename
  125. * given in the file_header of each compressed data portion.
  126. */
  127. zzip__new__ char *
  128. zzip_entry_strdup_name(ZZIP_ENTRY * entry)
  129. {
  130. if (! entry)
  131. return 0;
  132. ___ zzip_size_t len;
  133. if ((len = zzip_disk_entry_namlen(disk_(entry))))
  134. {
  135. char *name = malloc(len + 1);
  136. if (! name)
  137. return 0;
  138. memcpy(name, entry->tail, len);
  139. name[len] = '\0';
  140. return name;
  141. }
  142. ___ auto struct zzip_file_header header;
  143. if (zzip_entry_fread_file_header(entry, &header)
  144. && (len = zzip_file_header_namlen(&header)))
  145. {
  146. char *name = malloc(len + 1);
  147. if (! name) {
  148. return 0;
  149. } else {
  150. zzip_size_t n = fread(name, 1, len, entry->diskfile);
  151. if (n != len) {
  152. free (name);
  153. return 0;
  154. }
  155. name[n] = '\0';
  156. return name;
  157. }
  158. }
  159. return 0;
  160. ____;
  161. ____;
  162. }
  163. static int
  164. prescan_entry(ZZIP_ENTRY * entry)
  165. {
  166. assert(entry);
  167. ___ zzip_off_t tailsize = zzip_disk_entry_sizeof_tails(disk_(entry));
  168. if (tailsize + 1 > entry->tailalloc)
  169. {
  170. char *newtail = realloc(entry->tail, tailsize + 1);
  171. if (! newtail)
  172. return ENOMEM;
  173. entry->tail = newtail;
  174. entry->tailalloc = tailsize + 1;
  175. }
  176. # ifdef SIZE_MAX /* from stdint.h */
  177. if (tailsize > (zzip_off_t)(SIZE_MAX)) { return EFBIG; }
  178. # endif
  179. ___ zzip_size_t readsize = fread(entry->tail, 1, tailsize, entry->diskfile);
  180. /* name + comment + extras */
  181. if ((zzip_off_t)readsize != tailsize) {
  182. return errno;
  183. } else {
  184. return 0;
  185. } ____; ____;
  186. }
  187. static void
  188. prescan_clear(ZZIP_ENTRY * entry)
  189. {
  190. assert(entry);
  191. if (entry->tail)
  192. free(entry->tail);
  193. entry->tail = 0;
  194. entry->tailalloc = 0;
  195. }
  196. /* ====================================================================== */
  197. /** => zzip_entry_findfile
  198. *
  199. * This function is the first call of all the zip access functions here.
  200. * It contains the code to find the first entry of the zip central directory.
  201. * Here we require the stdio handle to represent a real zip file where the
  202. * disk_trailer is _last_ in the file area, so that its position would be at
  203. * a fixed offset from the end of the file area if not for the comment field
  204. * allowed to be of variable length (which needs us to do a little search
  205. * for the disk_tailer). However, in this simple implementation we disregard
  206. * any disk_trailer info telling about multidisk archives, so we just return
  207. * a pointer to the first entry in the zip central directory of that file.
  208. *
  209. * For an actual means, we are going to search backwards from the end
  210. * of the mmaped block looking for the PK-magic signature of a
  211. * disk_trailer. If we see one then we check the rootseek value to
  212. * find the first disk_entry of the root central directory. If we find
  213. * the correct PK-magic signature of a disk_entry over there then we
  214. * assume we are done and we are going to return a pointer to that label.
  215. *
  216. * The return value is a pointer to the first zzip_disk_entry being checked
  217. * to be within the bounds of the file area specified by the arguments. If
  218. * no disk_trailer was found then null is returned, and likewise we only
  219. * accept a disk_trailer with a seekvalue that points to a disk_entry and
  220. * both parts have valid PK-magic parts. Beyond some sanity check we try to
  221. * catch a common brokeness with zip archives that still allows us to find
  222. * the start of the zip central directory.
  223. */
  224. zzip__new__ ZZIP_ENTRY *
  225. zzip_entry_findfirst(FILE * disk)
  226. {
  227. if (! disk)
  228. return 0;
  229. if (fseeko(disk, 0, SEEK_END) == -1)
  230. return 0;
  231. ___ zzip_off_t disksize = ftello(disk);
  232. if (disksize < (zzip_off_t) sizeof(struct zzip_disk_trailer))
  233. return 0;
  234. /* we read out chunks of 8 KiB in the hope to match disk granularity */
  235. ___ zzip_off_t pagesize = PAGESIZE; /* getpagesize() */
  236. ___ ZZIP_ENTRY *entry = malloc(sizeof(*entry));
  237. if (! entry)
  238. return 0;
  239. ___ unsigned char *buffer = malloc(pagesize);
  240. if (! buffer)
  241. goto nomem;
  242. assert(pagesize / 2 > (zzip_off_t) sizeof(struct zzip_disk_trailer));
  243. /* at each step, we will fread a pagesize block which overlaps with the
  244. * previous read by means of pagesize/2 step at the end of the while(1) */
  245. ___ zzip_off_t mapoffs = disksize & ~(pagesize - 1);
  246. ___ zzip_off_t mapsize = disksize - mapoffs;
  247. if (mapoffs && mapsize < pagesize / 2)
  248. {
  249. mapoffs -= pagesize / 2;
  250. mapsize += pagesize / 2;
  251. }
  252. assert(mapsize < 3*8192);
  253. while (1)
  254. {
  255. if (fseeko(disk, mapoffs, SEEK_SET) == -1)
  256. goto error;
  257. if (fread(buffer, 1, mapsize, disk) != (zzip_size_t)mapsize)
  258. goto error;
  259. ___ unsigned char *p =
  260. buffer + mapsize - sizeof(struct zzip_disk_trailer);
  261. for (; p >= buffer; p--)
  262. {
  263. zzip_off_t root; /* (struct zzip_disk_entry*) */
  264. if (zzip_disk_trailer_check_magic(p))
  265. {
  266. root = zzip_disk_trailer_rootseek((struct zzip_disk_trailer *)
  267. p);
  268. if (root > disksize - (long) sizeof(struct zzip_disk_trailer))
  269. {
  270. /* first disk_entry is after the disk_trailer? can't be! */
  271. struct zzip_disk_trailer *trailer =
  272. (struct zzip_disk_trailer *) p;
  273. zzip_off_t rootsize = zzip_disk_trailer_rootsize(trailer);
  274. if (rootsize > mapoffs)
  275. continue;
  276. /* a common brokeness that can be fixed: we just assume the
  277. * central directory was written directly before : */
  278. root = mapoffs - rootsize;
  279. }
  280. } else if (zzip_disk64_trailer_check_magic(p))
  281. {
  282. struct zzip_disk64_trailer *trailer =
  283. (struct zzip_disk64_trailer *) p;
  284. if (sizeof(zzip_off_t) < 8)
  285. return 0;
  286. root = zzip_disk64_trailer_rootseek(trailer);
  287. } else
  288. continue;
  289. assert(0 <= root && root < mapsize);
  290. if (fseeko(disk, root, SEEK_SET) == -1)
  291. goto error;
  292. if (fread(disk_(entry), 1, sizeof(*disk_(entry)), disk)
  293. != sizeof(*disk_(entry))) goto error;
  294. if (zzip_disk_entry_check_magic(entry))
  295. {
  296. free(buffer);
  297. entry->headseek = root;
  298. entry->diskfile = disk;
  299. entry->disksize = disksize;
  300. if (prescan_entry(entry))
  301. goto nomem;
  302. return entry;
  303. }
  304. }
  305. ____;
  306. if (! mapoffs)
  307. break;
  308. assert(mapsize >= pagesize / 2);
  309. mapoffs -= pagesize / 2; /* mapsize += pagesize/2; */
  310. mapsize = pagesize; /* if (mapsize > pagesize) ... */
  311. if (disksize - mapoffs > 64 * 1024)
  312. break;
  313. }
  314. error:
  315. free(buffer);
  316. nomem:
  317. free(entry);
  318. ____;
  319. ____;
  320. ____;
  321. ____;
  322. ____;
  323. ____;
  324. return 0;
  325. }
  326. /** => zzip_entry_findfile
  327. *
  328. * This function takes an existing "entry" in the central root directory
  329. * (e.g. from zzip_entry_findfirst) and moves it to point to the next entry.
  330. * On error it returns 0, otherwise the old entry. If no further match is
  331. * found then null is returned and the entry already free()d. If you want
  332. * to stop searching for matches before that case then please call
  333. * => zzip_entry_free on the cursor struct ZZIP_ENTRY.
  334. */
  335. zzip__new__ ZZIP_ENTRY *
  336. zzip_entry_findnext(ZZIP_ENTRY * _zzip_restrict entry)
  337. {
  338. if (! entry)
  339. return entry;
  340. if (! zzip_disk_entry_check_magic(entry))
  341. goto err;
  342. ___ zzip_off_t seek =
  343. entry->headseek + zzip_disk_entry_sizeto_end(disk_(entry));
  344. if (seek + (zzip_off_t) sizeof(*disk_(entry)) > entry->disksize)
  345. goto err;
  346. if (fseeko(entry->diskfile, seek, SEEK_SET) == -1)
  347. goto err;
  348. if (fread(disk_(entry), 1, sizeof(*disk_(entry)), entry->diskfile)
  349. != sizeof(*disk_(entry))) goto err;
  350. entry->headseek = seek;
  351. if (! zzip_disk_entry_check_magic(entry))
  352. goto err;
  353. if (prescan_entry(entry))
  354. goto err;
  355. return entry;
  356. err:
  357. zzip_entry_free(entry);
  358. return 0;
  359. ____;
  360. }
  361. /** => zzip_entry_findfile
  362. * this function releases the malloc()ed areas needed for zzip_entry, the
  363. * pointer is invalid afterwards. This function has #define synonyms of
  364. * zzip_entry_findlast(), zzip_entry_findlastfile(), zzip_entry_findlastmatch()
  365. */
  366. int
  367. zzip_entry_free(ZZIP_ENTRY * entry)
  368. {
  369. if (! entry)
  370. return 0;
  371. prescan_clear(entry);
  372. free(entry);
  373. return 1;
  374. }
  375. /** search for files in the (fseeko) zip central directory
  376. *
  377. * This function is given a filename as an additional argument, to find the
  378. * disk_entry matching a given filename. The compare-function is usually
  379. * strcmp or strcasecmp or perhaps strcoll, if null then strcmp is used.
  380. * - use null as argument for "old"-entry when searching the first
  381. * matching entry, otherwise the last returned value if you look for other
  382. * entries with a special "compare" function (if null then a doubled search
  383. * is rather useless with this variant of _findfile). If no further entry is
  384. * found then null is returned and any "old"-entry gets already free()d.
  385. */
  386. zzip__new__ ZZIP_ENTRY *
  387. zzip_entry_findfile(FILE * disk, char *filename,
  388. ZZIP_ENTRY * _zzip_restrict entry, zzip_strcmp_fn_t compare)
  389. {
  390. if (! filename || ! disk)
  391. return 0;
  392. if (! entry)
  393. entry = zzip_entry_findfirst(disk);
  394. else
  395. entry = zzip_entry_findnext(entry);
  396. if (! compare)
  397. compare = (zzip_strcmp_fn_t) (strcmp);
  398. for (; entry; entry = zzip_entry_findnext(entry))
  399. {
  400. /* filenames within zip files are often not null-terminated! */
  401. char *realname = zzip_entry_strdup_name(entry);
  402. if (! realname)
  403. continue;
  404. if (! compare(filename, realname))
  405. {
  406. free(realname);
  407. return entry;
  408. } else
  409. {
  410. free(realname);
  411. continue;
  412. }
  413. }
  414. return 0;
  415. }
  416. /** => zzip_entry_findfile
  417. *
  418. * This function uses a compare-function with an additional argument
  419. * and it is called just like fnmatch(3) from POSIX.2 AD:1993), i.e.
  420. * the argument filespec first and the ziplocal filename second with
  421. * the integer-flags put in as third to the indirect call. If the
  422. * platform has fnmatch available then null-compare will use that one
  423. * and otherwise we fall back to mere strcmp, so if you need fnmatch
  424. * searching then please provide an implementation somewhere else.
  425. * - use null as argument for "after"-entry when searching the first
  426. * matching entry, or the last disk_entry return-value to find the
  427. * next entry matching the given filespec. If no further entry is
  428. * found then null is returned and any "old"-entry gets already free()d.
  429. */
  430. zzip__new__ ZZIP_ENTRY *
  431. zzip_entry_findmatch(FILE * disk, char *filespec,
  432. ZZIP_ENTRY * _zzip_restrict entry,
  433. zzip_fnmatch_fn_t compare, int flags)
  434. {
  435. if (! filespec || ! disk)
  436. return 0;
  437. if (! entry)
  438. entry = zzip_entry_findfirst(disk);
  439. else
  440. entry = zzip_entry_findnext(entry);
  441. if (! compare)
  442. compare = (zzip_fnmatch_fn_t) _zzip_fnmatch;
  443. for (; entry; entry = zzip_entry_findnext(entry))
  444. {
  445. /* filenames within zip files are often not null-terminated! */
  446. char *realname = zzip_entry_strdup_name(entry);
  447. if (! realname)
  448. continue;
  449. if (! compare(filespec, realname, flags))
  450. {
  451. free(realname);
  452. return entry;
  453. } else
  454. {
  455. free(realname);
  456. continue;
  457. }
  458. }
  459. return 0;
  460. }
  461. /* ====================================================================== */
  462. /**
  463. * typedef struct zzip_disk_file ZZIP_ENTRY_FILE;
  464. */
  465. struct zzip_entry_file /* : zzip_file_header */
  466. {
  467. struct zzip_file_header header; /* fopen detected header */
  468. ZZIP_ENTRY *entry; /* fopen entry */
  469. zzip_off_t data; /* for stored blocks */
  470. zzip_size_t avail; /* memorized for checks on EOF */
  471. zzip_size_t compressed; /* compressed flag and datasize */
  472. zzip_size_t dataoff; /* offset from data start */
  473. z_stream zlib; /* for inflated blocks */
  474. unsigned char buffer[PAGESIZE]; /* work buffer for inflate algorithm */
  475. };
  476. /** open a file within a zip disk for reading
  477. *
  478. * This function does take an "entry" argument and copies it (or just takes
  479. * it over as owner) to a new ZZIP_ENTRY_FILE handle structure. That
  480. * structure contains also a zlib buffer for decoding. This function does
  481. * seek to the file_header of the given "entry" and validates it for the
  482. * data buffer following it. We do also prefetch some data from the data
  483. * buffer thereby trying to match the disk pagesize for faster access later.
  484. * The => zzip_entry_fread will then read in chunks of pagesizes which is
  485. * the size of the internal readahead buffer. If an error occurs then null
  486. * is returned.
  487. */
  488. zzip__new__ ZZIP_ENTRY_FILE *
  489. zzip_entry_fopen(ZZIP_ENTRY * entry, int takeover)
  490. {
  491. if (! entry)
  492. return 0;
  493. if (! takeover)
  494. {
  495. ZZIP_ENTRY *found = malloc(sizeof(*entry));
  496. if (! found)
  497. return 0;
  498. memcpy(found, entry, sizeof(*entry)); /* prescan_copy */
  499. found->tail = malloc(found->tailalloc);
  500. if (! found->tail)
  501. { free (found); return 0; }
  502. memcpy(found->tail, entry->tail, entry->tailalloc);
  503. entry = found;
  504. }
  505. ___ ZZIP_ENTRY_FILE *file = malloc(sizeof(*file));
  506. if (! file)
  507. goto fail1;
  508. file->entry = entry;
  509. if (! zzip_entry_fread_file_header(entry, &file->header))
  510. goto fail2;
  511. file->avail = zzip_file_header_usize(&file->header);
  512. file->data = zzip_entry_data_offset(entry);
  513. file->dataoff = 0;
  514. if (! file->avail || zzip_file_header_data_stored(&file->header))
  515. { file->compressed = 0; return file; }
  516. file->compressed = zzip_file_header_csize(&file->header);
  517. file->zlib.opaque = 0;
  518. file->zlib.zalloc = Z_NULL;
  519. file->zlib.zfree = Z_NULL;
  520. ___ zzip_off_t seek = file->data;
  521. seek += sizeof(file->buffer);
  522. seek -= seek & (sizeof(file->buffer) - 1);
  523. assert(file->data < seek); /* pre-read to next PAGESIZE boundary... */
  524. if (fseeko(file->entry->diskfile, file->data + file->dataoff, SEEK_SET) == -1)
  525. goto fail2;
  526. file->zlib.next_in = file->buffer;
  527. file->zlib.avail_in = fread(file->buffer, 1, seek - file->data,
  528. file->entry->diskfile);
  529. file->dataoff += file->zlib.avail_in;
  530. ____;
  531. if (! zzip_file_header_data_deflated(&file->header)
  532. || inflateInit2(&file->zlib, -MAX_WBITS) != Z_OK)
  533. goto fail2;
  534. return file;
  535. fail2:
  536. free(file);
  537. fail1:
  538. zzip_entry_free(entry);
  539. return 0;
  540. ____;
  541. }
  542. /** => zzip_entry_fopen
  543. *
  544. * This function opens a file found by name, so it does a search into
  545. * the zip central directory with => zzip_entry_findfile and whatever
  546. * is found first is given to => zzip_entry_fopen
  547. */
  548. zzip__new__ ZZIP_ENTRY_FILE *
  549. zzip_entry_ffile(FILE * disk, char *filename)
  550. {
  551. ZZIP_ENTRY *entry = zzip_entry_findfile(disk, filename, 0, 0);
  552. if (! entry)
  553. return 0;
  554. return zzip_entry_fopen(entry, 1);
  555. }
  556. /** => zzip_entry_fopen
  557. *
  558. * This function reads more bytes into the output buffer specified as
  559. * arguments. The return value is null on eof or error, the stdio-like
  560. * interface can not distinguish between these so you need to check
  561. * with => zzip_entry_feof for the difference.
  562. */
  563. zzip_size_t
  564. zzip_entry_fread(void *ptr, zzip_size_t sized, zzip_size_t nmemb,
  565. ZZIP_ENTRY_FILE * file)
  566. {
  567. if (! file)
  568. return 0;
  569. ___ zzip_size_t size = sized * nmemb;
  570. if (! file->compressed)
  571. {
  572. if (size > file->avail)
  573. size = file->avail;
  574. if (fread(ptr, 1, size, file->entry->diskfile) != size) return 0;
  575. file->dataoff += size;
  576. file->avail -= size;
  577. return size;
  578. }
  579. file->zlib.avail_out = size;
  580. file->zlib.next_out = ptr;
  581. ___ zzip_size_t total_old = file->zlib.total_out;
  582. while (1)
  583. {
  584. if (! file->zlib.avail_in)
  585. {
  586. size = file->compressed - file->dataoff;
  587. if (size > sizeof(file->buffer))
  588. size = sizeof(file->buffer);
  589. /* fseek (file->data + file->dataoff, file->entry->diskfile); */
  590. file->zlib.avail_in = fread(file->buffer, 1, size,
  591. file->entry->diskfile);
  592. file->zlib.next_in = file->buffer;
  593. file->dataoff += file->zlib.avail_in;
  594. }
  595. if (! file->zlib.avail_in)
  596. return 0;
  597. ___ int err = inflate(&file->zlib, Z_NO_FLUSH);
  598. if (err == Z_STREAM_END)
  599. file->avail = 0;
  600. else if (err == Z_OK)
  601. file->avail -= file->zlib.total_out - total_old;
  602. else
  603. return 0;
  604. ____;
  605. if (file->zlib.avail_out && ! file->zlib.avail_in)
  606. continue;
  607. return file->zlib.total_out - total_old;
  608. }
  609. ____;
  610. ____;
  611. }
  612. /** => zzip_entry_fopen
  613. * This function releases any zlib decoder info needed for decompression
  614. * and dumps the ZZIP_ENTRY_FILE struct then.
  615. */
  616. int
  617. zzip_entry_fclose(ZZIP_ENTRY_FILE * file)
  618. {
  619. if (! file)
  620. return 0;
  621. if (file->compressed)
  622. inflateEnd(&file->zlib);
  623. zzip_entry_free(file->entry);
  624. free(file);
  625. return 0;
  626. }
  627. /** => zzip_entry_fopen
  628. *
  629. * This function allows to distinguish an error from an eof condition.
  630. * Actually, if we found an error but we did already reach eof then we
  631. * just keep on saying that it was an eof, so the app can just continue.
  632. */
  633. int
  634. zzip_entry_feof(ZZIP_ENTRY_FILE * file)
  635. {
  636. return ! file || ! file->avail;
  637. }