zip.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. /*
  2. * ZIP support routines for PhysicsFS.
  3. *
  4. * Please see the file LICENSE in the source's root directory.
  5. *
  6. * This file written by Ryan C. Gordon.
  7. */
  8. /*
  9. * !!! FIXME: overall design bugs.
  10. *
  11. * Maybe add a seekToStartOfCurrentFile() in unzip.c if complete seek
  12. * semantics are impossible.
  13. *
  14. * Could be more i/o efficient if we combined unzip.c and this file.
  15. * (and thus lose all the unzGoToNextFile() dummy loops.
  16. */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <assert.h>
  21. #include "physfs.h"
  22. #include "unzip.h"
  23. #define __PHYSICSFS_INTERNAL__
  24. #include "physfs_internal.h"
  25. #if (!defined PHYSFS_SUPPORTS_ZIP)
  26. #error PHYSFS_SUPPORTS_ZIP must be defined.
  27. #endif
  28. #define MAXZIPENTRYSIZE 256
  29. typedef struct
  30. {
  31. char *name;
  32. unz_file_info info;
  33. char *symlink;
  34. } ZIPentry;
  35. typedef struct
  36. {
  37. char *archiveName;
  38. unz_global_info global;
  39. ZIPentry *entries;
  40. } ZIPinfo;
  41. typedef struct
  42. {
  43. unzFile handle;
  44. } ZIPfileinfo;
  45. /* Number of symlinks to follow before we assume it's a recursive link... */
  46. #define SYMLINK_RECURSE_COUNT 20
  47. static PHYSFS_sint64 ZIP_read(FileHandle *handle, void *buffer,
  48. PHYSFS_uint32 objSize, PHYSFS_uint32 objCount);
  49. static int ZIP_eof(FileHandle *handle);
  50. static PHYSFS_sint64 ZIP_tell(FileHandle *handle);
  51. static int ZIP_seek(FileHandle *handle, PHYSFS_uint64 offset);
  52. static PHYSFS_sint64 ZIP_fileLength(FileHandle *handle);
  53. static int ZIP_fileClose(FileHandle *handle);
  54. static int ZIP_isArchive(const char *filename, int forWriting);
  55. static char *ZIP_realpath(unzFile fh, unz_file_info *info, ZIPentry *entry);
  56. static DirHandle *ZIP_openArchive(const char *name, int forWriting);
  57. static LinkedStringList *ZIP_enumerateFiles(DirHandle *h,
  58. const char *dirname,
  59. int omitSymLinks);
  60. static int ZIP_exists(DirHandle *h, const char *name);
  61. static int ZIP_isDirectory(DirHandle *h, const char *name);
  62. static int ZIP_isSymLink(DirHandle *h, const char *name);
  63. static FileHandle *ZIP_openRead(DirHandle *h, const char *filename);
  64. static void ZIP_dirClose(DirHandle *h);
  65. static const FileFunctions __PHYSFS_FileFunctions_ZIP =
  66. {
  67. ZIP_read, /* read() method */
  68. NULL, /* write() method */
  69. ZIP_eof, /* eof() method */
  70. ZIP_tell, /* tell() method */
  71. ZIP_seek, /* seek() method */
  72. ZIP_fileLength, /* fileLength() method */
  73. ZIP_fileClose /* fileClose() method */
  74. };
  75. const DirFunctions __PHYSFS_DirFunctions_ZIP =
  76. {
  77. ZIP_isArchive, /* isArchive() method */
  78. ZIP_openArchive, /* openArchive() method */
  79. ZIP_enumerateFiles, /* enumerateFiles() method */
  80. ZIP_exists, /* exists() method */
  81. ZIP_isDirectory, /* isDirectory() method */
  82. ZIP_isSymLink, /* isSymLink() method */
  83. ZIP_openRead, /* openRead() method */
  84. NULL, /* openWrite() method */
  85. NULL, /* openAppend() method */
  86. NULL, /* remove() method */
  87. NULL, /* mkdir() method */
  88. ZIP_dirClose /* dirClose() method */
  89. };
  90. const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP =
  91. {
  92. "ZIP",
  93. "PkZip/WinZip/Info-Zip compatible",
  94. "Ryan C. Gordon <icculus@clutteredmind.org>",
  95. "http://www.icculus.org/physfs/",
  96. };
  97. static PHYSFS_sint64 ZIP_read(FileHandle *handle, void *buffer,
  98. PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
  99. {
  100. unzFile fh = ((ZIPfileinfo *) (handle->opaque))->handle;
  101. int bytes = (int) (objSize * objCount); /* !!! FIXME: overflow? */
  102. PHYSFS_sint32 rc = unzReadCurrentFile(fh, buffer, bytes);
  103. if (rc < bytes)
  104. __PHYSFS_setError(ERR_PAST_EOF);
  105. else if (rc == UNZ_ERRNO)
  106. __PHYSFS_setError(ERR_IO_ERROR);
  107. else if (rc < 0)
  108. __PHYSFS_setError(ERR_COMPRESSION);
  109. return(rc / objSize);
  110. } /* ZIP_read */
  111. static int ZIP_eof(FileHandle *handle)
  112. {
  113. return(unzeof(((ZIPfileinfo *) (handle->opaque))->handle));
  114. } /* ZIP_eof */
  115. static PHYSFS_sint64 ZIP_tell(FileHandle *handle)
  116. {
  117. return(unztell(((ZIPfileinfo *) (handle->opaque))->handle));
  118. } /* ZIP_tell */
  119. static int ZIP_seek(FileHandle *handle, PHYSFS_uint64 offset)
  120. {
  121. /* !!! FIXME : this blows. */
  122. unzFile fh = ((ZIPfileinfo *) (handle->opaque))->handle;
  123. char *buf = NULL;
  124. PHYSFS_uint32 bufsize = 4096 * 2;
  125. BAIL_IF_MACRO(unztell(fh) == offset, NULL, 1);
  126. BAIL_IF_MACRO(ZIP_fileLength(handle) <= offset, ERR_PAST_EOF, 0);
  127. /* reset to the start of the zipfile. */
  128. unzCloseCurrentFile(fh);
  129. BAIL_IF_MACRO(unzOpenCurrentFile(fh) != UNZ_OK, ERR_IO_ERROR, 0);
  130. while ((buf == NULL) && (bufsize >= 512))
  131. {
  132. bufsize >>= 1; /* divides by two. */
  133. buf = (char *) malloc(bufsize);
  134. } /* while */
  135. BAIL_IF_MACRO(buf == NULL, ERR_OUT_OF_MEMORY, 0);
  136. while (offset > 0)
  137. {
  138. PHYSFS_uint32 chunk = (offset > bufsize) ? bufsize : (PHYSFS_uint32)offset;
  139. PHYSFS_sint32 rc = unzReadCurrentFile(fh, buf, chunk);
  140. BAIL_IF_MACRO(rc == 0, ERR_IO_ERROR, 0); /* shouldn't happen. */
  141. BAIL_IF_MACRO(rc == UNZ_ERRNO, ERR_IO_ERROR, 0);
  142. BAIL_IF_MACRO(rc < 0, ERR_COMPRESSION, 0);
  143. offset -= rc;
  144. } /* while */
  145. free(buf);
  146. return(offset == 0);
  147. } /* ZIP_seek */
  148. static PHYSFS_sint64 ZIP_fileLength(FileHandle *handle)
  149. {
  150. ZIPfileinfo *finfo = (ZIPfileinfo *) (handle->opaque);
  151. unz_file_info info;
  152. unzGetCurrentFileInfo(finfo->handle, &info, NULL, 0, NULL, 0, NULL, 0);
  153. return(info.uncompressed_size);
  154. } /* ZIP_fileLength */
  155. static int ZIP_fileClose(FileHandle *handle)
  156. {
  157. ZIPfileinfo *finfo = (ZIPfileinfo *) (handle->opaque);
  158. unzClose(finfo->handle);
  159. free(finfo);
  160. free(handle);
  161. return(1);
  162. } /* ZIP_fileClose */
  163. static int ZIP_isArchive(const char *filename, int forWriting)
  164. {
  165. int retval = 0;
  166. unzFile unz = unzOpen(filename);
  167. unz_global_info global;
  168. if (unz != NULL)
  169. {
  170. if (unzGetGlobalInfo(unz, &global) == UNZ_OK)
  171. retval = 1;
  172. unzClose(unz);
  173. } /* if */
  174. return(retval);
  175. } /* ZIP_isArchive */
  176. static void freeEntries(ZIPinfo *info, int count, const char *errmsg)
  177. {
  178. int i;
  179. for (i = 0; i < count; i++)
  180. {
  181. free(info->entries[i].name);
  182. if (info->entries[i].symlink != NULL)
  183. free(info->entries[i].symlink);
  184. } /* for */
  185. free(info->entries);
  186. if (errmsg != NULL)
  187. __PHYSFS_setError(errmsg);
  188. } /* freeEntries */
  189. /*
  190. * !!! FIXME: Really implement this.
  191. * !!! FIXME: symlinks in zipfiles can be relative paths, including
  192. * !!! FIXME: "." and ".." entries. These need to be parsed out.
  193. * !!! FIXME: For now, though, we're just copying the relative path. Oh well.
  194. */
  195. static char *expand_symlink_path(const char *path, ZIPentry *entry)
  196. {
  197. char *retval = (char *) malloc(strlen(path) + 1);
  198. BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
  199. strcpy(retval, path);
  200. return(retval);
  201. } /* expand_symlink_path */
  202. static char *ZIP_realpath(unzFile fh, unz_file_info *info, ZIPentry *entry)
  203. {
  204. char path[MAXZIPENTRYSIZE];
  205. int size = info->uncompressed_size;
  206. int rc;
  207. BAIL_IF_MACRO(size >= sizeof (path), ERR_IO_ERROR, NULL);
  208. BAIL_IF_MACRO(unzOpenCurrentFile(fh) != UNZ_OK, ERR_IO_ERROR, NULL);
  209. rc = unzReadCurrentFile(fh, path, size);
  210. unzCloseCurrentFile(fh);
  211. BAIL_IF_MACRO(rc != size, ERR_IO_ERROR, NULL);
  212. path[size] = '\0'; /* null terminate it. */
  213. return(expand_symlink_path(path, entry)); /* retval is malloc()'d. */
  214. } /* ZIP_realpath */
  215. static int version_does_symlinks(uLong version)
  216. {
  217. int retval = 0;
  218. PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((version >> 8) & 0xFF);
  219. /*
  220. * These are the platforms that can build an archive with symlinks,
  221. * according to the Info-ZIP project.
  222. */
  223. switch (hosttype)
  224. {
  225. case 3: /* Unix */
  226. case 16: /* BeOS */
  227. case 5: /* Atari */
  228. retval = 1;
  229. break;
  230. } /* switch */
  231. return(retval);
  232. } /* version_does_symlinks */
  233. static int entry_is_symlink(unz_file_info *info)
  234. {
  235. return (
  236. (version_does_symlinks(info->version)) &&
  237. (info->uncompressed_size > 0) &&
  238. (info->external_fa & 0x0120000) /* symlink flag. */
  239. );
  240. } /* entry_is_symlink */
  241. static int loadZipEntries(ZIPinfo *info, unzFile unz)
  242. {
  243. int i, max;
  244. BAIL_IF_MACRO(unzGetGlobalInfo(unz, &(info->global)) != UNZ_OK,
  245. ERR_IO_ERROR, 0);
  246. BAIL_IF_MACRO(unzGoToFirstFile(unz) != UNZ_OK, ERR_IO_ERROR, 0);
  247. max = info->global.number_entry;
  248. info->entries = (ZIPentry *) malloc(sizeof (ZIPentry) * max);
  249. BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
  250. for (i = 0; i < max; i++)
  251. {
  252. unz_file_info *d = &((info->entries[i]).info);
  253. if (unzGetCurrentFileInfo(unz, d, NULL, 0, NULL, 0, NULL, 0) != UNZ_OK)
  254. {
  255. freeEntries(info, i, ERR_IO_ERROR);
  256. return(0);
  257. } /* if */
  258. (info->entries[i]).name = (char *) malloc(d->size_filename + 1);
  259. if ((info->entries[i]).name == NULL)
  260. {
  261. freeEntries(info, i, ERR_OUT_OF_MEMORY);
  262. return(0);
  263. } /* if */
  264. info->entries[i].symlink = NULL;
  265. if (unzGetCurrentFileInfo(unz, NULL, (info->entries[i]).name,
  266. d->size_filename + 1, NULL, 0,
  267. NULL, 0) != UNZ_OK)
  268. {
  269. freeEntries(info, i + 1, ERR_IO_ERROR);
  270. return(0);
  271. } /* if */
  272. if (entry_is_symlink(d))
  273. {
  274. info->entries[i].symlink = ZIP_realpath(unz, d, &info->entries[i]);
  275. if (info->entries[i].symlink == NULL)
  276. {
  277. freeEntries(info, i + 1, NULL);
  278. return(0);
  279. } /* if */
  280. } /* if */
  281. if ((unzGoToNextFile(unz) != UNZ_OK) && (i + 1 < max))
  282. {
  283. freeEntries(info, i + 1, ERR_IO_ERROR);
  284. return(0);
  285. } /* if */
  286. } /* for */
  287. return(1);
  288. } /* loadZipEntries */
  289. static DirHandle *ZIP_openArchive(const char *name, int forWriting)
  290. {
  291. unzFile unz = NULL;
  292. DirHandle *retval = NULL;
  293. BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
  294. retval = malloc(sizeof (DirHandle));
  295. BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
  296. unz = unzOpen(name);
  297. if (unz == NULL)
  298. {
  299. free(retval);
  300. BAIL_IF_MACRO(1, ERR_UNSUPPORTED_ARCHIVE, NULL);
  301. } /* if */
  302. retval->opaque = malloc(sizeof (ZIPinfo));
  303. if (retval->opaque == NULL)
  304. {
  305. free(retval);
  306. unzClose(unz);
  307. BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
  308. } /* if */
  309. ((ZIPinfo *) (retval->opaque))->archiveName = malloc(strlen(name) + 1);
  310. if ( (((ZIPinfo *) (retval->opaque))->archiveName == NULL) ||
  311. (!loadZipEntries( (ZIPinfo *) (retval->opaque), unz)) )
  312. {
  313. if (((ZIPinfo *) (retval->opaque))->archiveName != NULL)
  314. free(((ZIPinfo *) (retval->opaque))->archiveName);
  315. free(retval->opaque);
  316. free(retval);
  317. unzClose(unz);
  318. BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
  319. } /* if */
  320. unzClose(unz);
  321. strcpy(((ZIPinfo *) (retval->opaque))->archiveName, name);
  322. retval->funcs = &__PHYSFS_DirFunctions_ZIP;
  323. return(retval);
  324. } /* ZIP_openArchive */
  325. /* !!! This is seriously ugly. */
  326. static LinkedStringList *ZIP_enumerateFiles(DirHandle *h,
  327. const char *dirname,
  328. int omitSymLinks)
  329. {
  330. ZIPinfo *zi = (ZIPinfo *) (h->opaque);
  331. unsigned int i;
  332. int dlen;
  333. LinkedStringList *retval = NULL;
  334. LinkedStringList *l = NULL;
  335. LinkedStringList *prev = NULL;
  336. char *d;
  337. ZIPentry *entry;
  338. char buf[MAXZIPENTRYSIZE];
  339. dlen = strlen(dirname);
  340. d = malloc(dlen + 1);
  341. BAIL_IF_MACRO(d == NULL, ERR_OUT_OF_MEMORY, NULL);
  342. strcpy(d, dirname);
  343. if ((dlen > 0) && (d[dlen - 1] == '/')) /* no trailing slash. */
  344. {
  345. dlen--;
  346. d[dlen] = '\0';
  347. } /* if */
  348. for (i = 0, entry = zi->entries; i < zi->global.number_entry; i++, entry++)
  349. {
  350. char *ptr;
  351. char *add_file;
  352. int this_dlen;
  353. if ((omitSymLinks) && (entry->symlink != NULL))
  354. continue;
  355. this_dlen = strlen(entry->name);
  356. if (this_dlen + 1 > MAXZIPENTRYSIZE)
  357. continue; /* ugh. */
  358. strcpy(buf, entry->name);
  359. if ((this_dlen > 0) && (buf[this_dlen - 1] == '/')) /* no trailing slash. */
  360. {
  361. this_dlen--;
  362. buf[this_dlen] = '\0';
  363. } /* if */
  364. if (this_dlen <= dlen) /* not in this dir. */
  365. continue;
  366. if (*d == '\0')
  367. add_file = buf;
  368. else
  369. {
  370. if (buf[dlen] != '/') /* can't be in same directory? */
  371. continue;
  372. buf[dlen] = '\0';
  373. if (__PHYSFS_platformStricmp(d, buf) != 0) /* not same directory? */
  374. continue;
  375. add_file = buf + dlen + 1;
  376. } /* else */
  377. /* handle subdirectories... */
  378. ptr = strchr(add_file, '/');
  379. if (ptr != NULL)
  380. {
  381. LinkedStringList *j;
  382. *ptr = '\0';
  383. for (j = retval; j != NULL; j = j->next)
  384. {
  385. if (__PHYSFS_platformStricmp(j->str, ptr) == 0)
  386. break;
  387. } /* for */
  388. if (j != NULL)
  389. continue;
  390. } /* if */
  391. l = (LinkedStringList *) malloc(sizeof (LinkedStringList));
  392. if (l == NULL)
  393. break;
  394. l->str = (char *) malloc(strlen(add_file) + 1);
  395. if (l->str == NULL)
  396. {
  397. free(l);
  398. break;
  399. } /* if */
  400. strcpy(l->str, add_file);
  401. if (retval == NULL)
  402. retval = l;
  403. else
  404. prev->next = l;
  405. prev = l;
  406. l->next = NULL;
  407. } /* for */
  408. free(d);
  409. return(retval);
  410. } /* ZIP_enumerateFiles */
  411. /* !!! This is seriously ugly. */
  412. static int ZIP_exists_symcheck(DirHandle *h, const char *name, int follow)
  413. {
  414. char buf[MAXZIPENTRYSIZE];
  415. ZIPinfo *zi = (ZIPinfo *) (h->opaque);
  416. int dlen;
  417. char *d;
  418. unsigned int i;
  419. ZIPentry *entry;
  420. dlen = strlen(name);
  421. d = malloc(dlen + 1);
  422. BAIL_IF_MACRO(d == NULL, ERR_OUT_OF_MEMORY, -1);
  423. strcpy(d, name);
  424. if ((dlen > 0) && (d[dlen - 1] == '/')) /* no trailing slash. */
  425. {
  426. dlen--;
  427. d[dlen] = '\0';
  428. } /* if */
  429. for (i = 0, entry = zi->entries; i < zi->global.number_entry; i++, entry++)
  430. {
  431. int this_dlen = strlen(entry->name);
  432. if (this_dlen + 1 > MAXZIPENTRYSIZE)
  433. continue; /* ugh. */
  434. strcpy(buf, entry->name);
  435. if ((this_dlen > 0) && (buf[this_dlen - 1] == '/')) /* no trailing slash. */
  436. {
  437. this_dlen--;
  438. buf[this_dlen] = '\0';
  439. } /* if */
  440. if ( ((buf[dlen] == '/') || (buf[dlen] == '\0')) &&
  441. (strncmp(d, buf, dlen) == 0) )
  442. {
  443. int retval = i;
  444. free(d);
  445. if (follow) /* follow symlinks? */
  446. {
  447. if (entry->symlink != NULL)
  448. retval = ZIP_exists_symcheck(h, entry->symlink, follow-1);
  449. } /* if */
  450. return(retval);
  451. } /* if */
  452. } /* for */
  453. free(d);
  454. return(-1);
  455. } /* ZIP_exists_symcheck */
  456. static int ZIP_exists(DirHandle *h, const char *name)
  457. {
  458. int retval = ZIP_exists_symcheck(h, name, SYMLINK_RECURSE_COUNT);
  459. int is_sym;
  460. if (retval == -1)
  461. return(0);
  462. /* if it's a symlink, then we ran into a possible symlink loop. */
  463. is_sym = ( ((ZIPinfo *)(h->opaque))->entries[retval].symlink != NULL );
  464. BAIL_IF_MACRO(is_sym, ERR_TOO_MANY_SYMLINKS, 0);
  465. return(1);
  466. } /* ZIP_exists */
  467. static int ZIP_isDirectory(DirHandle *h, const char *name)
  468. {
  469. int dlen;
  470. int is_sym;
  471. int retval = ZIP_exists_symcheck(h, name, SYMLINK_RECURSE_COUNT);
  472. if (retval == -1)
  473. return(0);
  474. /* if it's a symlink, then we ran into a possible symlink loop. */
  475. is_sym = ( ((ZIPinfo *)(h->opaque))->entries[retval].symlink != NULL );
  476. BAIL_IF_MACRO(is_sym, ERR_TOO_MANY_SYMLINKS, 0);
  477. dlen = strlen(name);
  478. /* !!! yikes. Better way to check? */
  479. retval = (((ZIPinfo *)(h->opaque))->entries[retval].name[dlen] == '/');
  480. return(retval);
  481. } /* ZIP_isDirectory */
  482. static int ZIP_isSymLink(DirHandle *h, const char *name)
  483. {
  484. int retval = ZIP_exists_symcheck(h, name, 0);
  485. if (retval == -1)
  486. return(0);
  487. retval = ( ((ZIPinfo *)(h->opaque))->entries[retval].symlink != NULL );
  488. return(retval);
  489. } /* ZIP_isSymLink */
  490. static FileHandle *ZIP_openRead(DirHandle *h, const char *filename)
  491. {
  492. FileHandle *retval = NULL;
  493. ZIPinfo *zi = ((ZIPinfo *) (h->opaque));
  494. ZIPfileinfo *finfo = NULL;
  495. int pos = ZIP_exists_symcheck(h, filename, SYMLINK_RECURSE_COUNT);
  496. unzFile f;
  497. BAIL_IF_MACRO(pos == -1, ERR_NO_SUCH_FILE, NULL);
  498. f = unzOpen(zi->archiveName);
  499. BAIL_IF_MACRO(f == NULL, ERR_IO_ERROR, NULL);
  500. if (unzGoToFirstFile(f) != UNZ_OK)
  501. {
  502. unzClose(f);
  503. BAIL_IF_MACRO(1, ERR_IO_ERROR, NULL);
  504. } /* if */
  505. for (; pos > 0; pos--)
  506. {
  507. if (unzGoToNextFile(f) != UNZ_OK)
  508. {
  509. unzClose(f);
  510. BAIL_IF_MACRO(1, ERR_IO_ERROR, NULL);
  511. } /* if */
  512. } /* for */
  513. if ( (unzOpenCurrentFile(f) != UNZ_OK) ||
  514. ( (finfo = (ZIPfileinfo *) malloc(sizeof (ZIPfileinfo))) == NULL ) )
  515. {
  516. unzClose(f);
  517. BAIL_IF_MACRO(1, ERR_IO_ERROR, NULL);
  518. } /* if */
  519. if ( (!(retval = (FileHandle *) malloc(sizeof (FileHandle)))) ||
  520. (!(retval->opaque = (ZIPfileinfo *) malloc(sizeof (ZIPfileinfo)))) )
  521. {
  522. if (retval)
  523. free(retval);
  524. unzClose(f);
  525. BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
  526. } /* if */
  527. finfo->handle = f;
  528. retval->opaque = (void *) finfo;
  529. retval->funcs = &__PHYSFS_FileFunctions_ZIP;
  530. retval->dirHandle = h;
  531. return(retval);
  532. } /* ZIP_openRead */
  533. static void ZIP_dirClose(DirHandle *h)
  534. {
  535. ZIPinfo *zi = (ZIPinfo *) (h->opaque);
  536. freeEntries(zi, zi->global.number_entry, NULL);
  537. free(zi->archiveName);
  538. free(zi);
  539. free(h);
  540. } /* ZIP_dirClose */
  541. /* end of zip.c ... */