archiver_zip.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431
  1. /*
  2. * ZIP support routines for PhysicsFS.
  3. *
  4. * Please see the file LICENSE.txt in the source's root directory.
  5. *
  6. * This file written by Ryan C. Gordon, with some peeking at "unzip.c"
  7. * by Gilles Vollant.
  8. */
  9. #if (defined PHYSFS_SUPPORTS_ZIP)
  10. #include <errno.h>
  11. #include <time.h>
  12. #define __PHYSICSFS_INTERNAL__
  13. #include "physfs_internal.h"
  14. #define USE_MINIZ 1
  15. #if USE_MINIZ
  16. #include "physfs_miniz.h"
  17. #else
  18. #include <zlib.h>
  19. #endif
  20. /*
  21. * A buffer of ZIP_READBUFSIZE is allocated for each compressed file opened,
  22. * and is freed when you close the file; compressed data is read into
  23. * this buffer, and then is decompressed into the buffer passed to
  24. * PHYSFS_read().
  25. *
  26. * Uncompressed entries in a zipfile do not allocate this buffer; they just
  27. * read data directly into the buffer passed to PHYSFS_read().
  28. *
  29. * Depending on your speed and memory requirements, you should tweak this
  30. * value.
  31. */
  32. #define ZIP_READBUFSIZE (16 * 1024)
  33. /*
  34. * Entries are "unresolved" until they are first opened. At that time,
  35. * local file headers parsed/validated, data offsets will be updated to look
  36. * at the actual file data instead of the header, and symlinks will be
  37. * followed and optimized. This means that we don't seek and read around the
  38. * archive until forced to do so, and after the first time, we had to do
  39. * less reading and parsing, which is very CD-ROM friendly.
  40. */
  41. typedef enum
  42. {
  43. ZIP_UNRESOLVED_FILE,
  44. ZIP_UNRESOLVED_SYMLINK,
  45. ZIP_RESOLVING,
  46. ZIP_RESOLVED,
  47. ZIP_BROKEN_FILE,
  48. ZIP_BROKEN_SYMLINK
  49. } ZipResolveType;
  50. /*
  51. * One ZIPentry is kept for each file in an open ZIP archive.
  52. */
  53. typedef struct _ZIPentry
  54. {
  55. char *name; /* Name of file in archive */
  56. struct _ZIPentry *symlink; /* NULL or file we symlink to */
  57. ZipResolveType resolved; /* Have we resolved file/symlink? */
  58. PHYSFS_uint32 offset; /* offset of data in archive */
  59. PHYSFS_uint16 version; /* version made by */
  60. PHYSFS_uint16 version_needed; /* version needed to extract */
  61. PHYSFS_uint16 compression_method; /* compression method */
  62. PHYSFS_uint32 crc; /* crc-32 */
  63. PHYSFS_uint32 compressed_size; /* compressed size */
  64. PHYSFS_uint32 uncompressed_size; /* uncompressed size */
  65. PHYSFS_sint64 last_mod_time; /* last file mod time */
  66. } ZIPentry;
  67. /*
  68. * One ZIPinfo is kept for each open ZIP archive.
  69. */
  70. typedef struct
  71. {
  72. PHYSFS_Io *io;
  73. PHYSFS_uint16 entryCount; /* Number of files in ZIP. */
  74. ZIPentry *entries; /* info on all files in ZIP. */
  75. } ZIPinfo;
  76. /*
  77. * One ZIPfileinfo is kept for each open file in a ZIP archive.
  78. */
  79. typedef struct
  80. {
  81. ZIPentry *entry; /* Info on file. */
  82. PHYSFS_Io *io; /* physical file handle. */
  83. PHYSFS_uint32 compressed_position; /* offset in compressed data. */
  84. PHYSFS_uint32 uncompressed_position; /* tell() position. */
  85. PHYSFS_uint8 *buffer; /* decompression buffer. */
  86. z_stream stream; /* zlib stream state. */
  87. } ZIPfileinfo;
  88. /* Magic numbers... */
  89. #define ZIP_LOCAL_FILE_SIG 0x04034b50
  90. #define ZIP_CENTRAL_DIR_SIG 0x02014b50
  91. #define ZIP_END_OF_CENTRAL_DIR_SIG 0x06054b50
  92. /* compression methods... */
  93. #define COMPMETH_NONE 0
  94. /* ...and others... */
  95. #define UNIX_FILETYPE_MASK 0170000
  96. #define UNIX_FILETYPE_SYMLINK 0120000
  97. /*
  98. * Bridge physfs allocation functions to zlib's format...
  99. */
  100. static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size)
  101. {
  102. return ((PHYSFS_Allocator *) opaque)->Malloc(items * size);
  103. } /* zlibPhysfsAlloc */
  104. /*
  105. * Bridge physfs allocation functions to zlib's format...
  106. */
  107. static void zlibPhysfsFree(voidpf opaque, voidpf address)
  108. {
  109. ((PHYSFS_Allocator *) opaque)->Free(address);
  110. } /* zlibPhysfsFree */
  111. /*
  112. * Construct a new z_stream to a sane state.
  113. */
  114. static void initializeZStream(z_stream *pstr)
  115. {
  116. memset(pstr, '\0', sizeof (z_stream));
  117. pstr->zalloc = zlibPhysfsAlloc;
  118. pstr->zfree = zlibPhysfsFree;
  119. pstr->opaque = &allocator;
  120. } /* initializeZStream */
  121. static const char *zlib_error_string(int rc)
  122. {
  123. switch (rc)
  124. {
  125. case Z_OK: return NULL; /* not an error. */
  126. case Z_STREAM_END: return NULL; /* not an error. */
  127. case Z_ERRNO: return ERR_IO_ERROR;
  128. case Z_NEED_DICT: return ERR_NEED_DICT;
  129. case Z_DATA_ERROR: return ERR_DATA_ERROR;
  130. case Z_MEM_ERROR: return ERR_MEMORY_ERROR;
  131. case Z_BUF_ERROR: return ERR_BUFFER_ERROR;
  132. case Z_VERSION_ERROR: return ERR_VERSION_ERROR;
  133. default: return ERR_UNKNOWN_ERROR;
  134. } /* switch */
  135. } /* zlib_error_string */
  136. /*
  137. * Wrap all zlib calls in this, so the physfs error state is set appropriately.
  138. */
  139. static int zlib_err(int rc)
  140. {
  141. const char *str = zlib_error_string(rc);
  142. if (str != NULL)
  143. __PHYSFS_setError(str);
  144. return rc;
  145. } /* zlib_err */
  146. /*
  147. * Read an unsigned 32-bit int and swap to native byte order.
  148. */
  149. static int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
  150. {
  151. PHYSFS_uint32 v;
  152. BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), NULL, 0);
  153. *val = PHYSFS_swapULE32(v);
  154. return 1;
  155. } /* readui32 */
  156. /*
  157. * Read an unsigned 16-bit int and swap to native byte order.
  158. */
  159. static int readui16(PHYSFS_Io *io, PHYSFS_uint16 *val)
  160. {
  161. PHYSFS_uint16 v;
  162. BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), NULL, 0);
  163. *val = PHYSFS_swapULE16(v);
  164. return 1;
  165. } /* readui16 */
  166. static PHYSFS_sint64 ZIP_read(PHYSFS_Io *_io, void *buf, PHYSFS_uint64 len)
  167. {
  168. ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
  169. PHYSFS_Io *io = finfo->io;
  170. ZIPentry *entry = finfo->entry;
  171. PHYSFS_sint64 retval = 0;
  172. PHYSFS_sint64 maxread = (PHYSFS_sint64) len;
  173. PHYSFS_sint64 avail = entry->uncompressed_size -
  174. finfo->uncompressed_position;
  175. if (avail < maxread)
  176. maxread = avail;
  177. BAIL_IF_MACRO(maxread == 0, NULL, 0); /* quick rejection. */
  178. if (entry->compression_method == COMPMETH_NONE)
  179. retval = io->read(io, buf, maxread);
  180. else
  181. {
  182. finfo->stream.next_out = buf;
  183. finfo->stream.avail_out = (uInt) maxread;
  184. while (retval < maxread)
  185. {
  186. PHYSFS_uint32 before = finfo->stream.total_out;
  187. int rc;
  188. if (finfo->stream.avail_in == 0)
  189. {
  190. PHYSFS_sint64 br;
  191. br = entry->compressed_size - finfo->compressed_position;
  192. if (br > 0)
  193. {
  194. if (br > ZIP_READBUFSIZE)
  195. br = ZIP_READBUFSIZE;
  196. br = io->read(io, finfo->buffer, (PHYSFS_uint64) br);
  197. if (br <= 0)
  198. break;
  199. finfo->compressed_position += (PHYSFS_uint32) br;
  200. finfo->stream.next_in = finfo->buffer;
  201. finfo->stream.avail_in = (PHYSFS_uint32) br;
  202. } /* if */
  203. } /* if */
  204. rc = zlib_err(inflate(&finfo->stream, Z_SYNC_FLUSH));
  205. retval += (finfo->stream.total_out - before);
  206. if (rc != Z_OK)
  207. break;
  208. } /* while */
  209. } /* else */
  210. if (retval > 0)
  211. finfo->uncompressed_position += (PHYSFS_uint32) retval;
  212. return retval;
  213. } /* ZIP_read */
  214. static PHYSFS_sint64 ZIP_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
  215. {
  216. BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
  217. } /* ZIP_write */
  218. static PHYSFS_sint64 ZIP_tell(PHYSFS_Io *io)
  219. {
  220. return ((ZIPfileinfo *) io->opaque)->uncompressed_position;
  221. } /* ZIP_tell */
  222. static int ZIP_seek(PHYSFS_Io *_io, PHYSFS_uint64 offset)
  223. {
  224. ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
  225. ZIPentry *entry = finfo->entry;
  226. PHYSFS_Io *io = finfo->io;
  227. BAIL_IF_MACRO(offset > entry->uncompressed_size, ERR_PAST_EOF, 0);
  228. if (entry->compression_method == COMPMETH_NONE)
  229. {
  230. const PHYSFS_sint64 newpos = offset + entry->offset;
  231. BAIL_IF_MACRO(!io->seek(io, newpos), NULL, 0);
  232. finfo->uncompressed_position = (PHYSFS_uint32) offset;
  233. } /* if */
  234. else
  235. {
  236. /*
  237. * If seeking backwards, we need to redecode the file
  238. * from the start and throw away the compressed bits until we hit
  239. * the offset we need. If seeking forward, we still need to
  240. * decode, but we don't rewind first.
  241. */
  242. if (offset < finfo->uncompressed_position)
  243. {
  244. /* we do a copy so state is sane if inflateInit2() fails. */
  245. z_stream str;
  246. initializeZStream(&str);
  247. if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
  248. return 0;
  249. if (!io->seek(io, entry->offset))
  250. return 0;
  251. inflateEnd(&finfo->stream);
  252. memcpy(&finfo->stream, &str, sizeof (z_stream));
  253. finfo->uncompressed_position = finfo->compressed_position = 0;
  254. } /* if */
  255. while (finfo->uncompressed_position != offset)
  256. {
  257. PHYSFS_uint8 buf[512];
  258. PHYSFS_uint32 maxread;
  259. maxread = (PHYSFS_uint32) (offset - finfo->uncompressed_position);
  260. if (maxread > sizeof (buf))
  261. maxread = sizeof (buf);
  262. if (ZIP_read(_io, buf, maxread) != maxread)
  263. return 0;
  264. } /* while */
  265. } /* else */
  266. return 1;
  267. } /* ZIP_seek */
  268. static PHYSFS_sint64 ZIP_length(PHYSFS_Io *io)
  269. {
  270. const ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
  271. return finfo->entry->uncompressed_size;
  272. } /* ZIP_length */
  273. static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry);
  274. static PHYSFS_Io *ZIP_duplicate(PHYSFS_Io *io)
  275. {
  276. ZIPfileinfo *origfinfo = (ZIPfileinfo *) io->opaque;
  277. PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
  278. ZIPfileinfo *finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
  279. GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, ZIP_duplicate_failed);
  280. GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, ZIP_duplicate_failed);
  281. memset(finfo, '\0', sizeof (*finfo));
  282. finfo->entry = origfinfo->entry;
  283. finfo->io = zip_get_io(origfinfo->io, NULL, finfo->entry);
  284. GOTO_IF_MACRO(finfo->io == NULL, NULL, ZIP_duplicate_failed);
  285. if (finfo->entry->compression_method != COMPMETH_NONE)
  286. {
  287. finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
  288. GOTO_IF_MACRO(!finfo->buffer, ERR_OUT_OF_MEMORY, ZIP_duplicate_failed);
  289. if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
  290. goto ZIP_duplicate_failed;
  291. } /* if */
  292. memcpy(retval, io, sizeof (PHYSFS_Io));
  293. retval->opaque = finfo;
  294. return retval;
  295. ZIP_duplicate_failed:
  296. if (finfo != NULL)
  297. {
  298. if (finfo->io != NULL)
  299. finfo->io->destroy(finfo->io);
  300. if (finfo->buffer != NULL)
  301. {
  302. allocator.Free(finfo->buffer);
  303. inflateEnd(&finfo->stream);
  304. } /* if */
  305. allocator.Free(finfo);
  306. } /* if */
  307. if (retval != NULL)
  308. allocator.Free(retval);
  309. return NULL;
  310. } /* ZIP_duplicate */
  311. static int ZIP_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
  312. static void ZIP_destroy(PHYSFS_Io *io)
  313. {
  314. ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
  315. finfo->io->destroy(finfo->io);
  316. if (finfo->entry->compression_method != COMPMETH_NONE)
  317. inflateEnd(&finfo->stream);
  318. if (finfo->buffer != NULL)
  319. allocator.Free(finfo->buffer);
  320. allocator.Free(finfo);
  321. allocator.Free(io);
  322. } /* ZIP_destroy */
  323. static const PHYSFS_Io ZIP_Io =
  324. {
  325. ZIP_read,
  326. ZIP_write,
  327. ZIP_seek,
  328. ZIP_tell,
  329. ZIP_length,
  330. ZIP_duplicate,
  331. ZIP_flush,
  332. ZIP_destroy,
  333. NULL
  334. };
  335. static PHYSFS_sint64 zip_find_end_of_central_dir(PHYSFS_Io *io, PHYSFS_sint64 *len)
  336. {
  337. PHYSFS_uint8 buf[256];
  338. PHYSFS_uint8 extra[4] = { 0, 0, 0, 0 };
  339. PHYSFS_sint32 i = 0;
  340. PHYSFS_sint64 filelen;
  341. PHYSFS_sint64 filepos;
  342. PHYSFS_sint32 maxread;
  343. PHYSFS_sint32 totalread = 0;
  344. int found = 0;
  345. filelen = io->length(io);
  346. BAIL_IF_MACRO(filelen == -1, NULL, 0); /* !!! FIXME: unlocalized string */
  347. BAIL_IF_MACRO(filelen > 0xFFFFFFFF, "ZIP bigger than 4 gigs?!", 0);
  348. /*
  349. * Jump to the end of the file and start reading backwards.
  350. * The last thing in the file is the zipfile comment, which is variable
  351. * length, and the field that specifies its size is before it in the
  352. * file (argh!)...this means that we need to scan backwards until we
  353. * hit the end-of-central-dir signature. We can then sanity check that
  354. * the comment was as big as it should be to make sure we're in the
  355. * right place. The comment length field is 16 bits, so we can stop
  356. * searching for that signature after a little more than 64k at most,
  357. * and call it a corrupted zipfile.
  358. */
  359. if (sizeof (buf) < filelen)
  360. {
  361. filepos = filelen - sizeof (buf);
  362. maxread = sizeof (buf);
  363. } /* if */
  364. else
  365. {
  366. filepos = 0;
  367. maxread = (PHYSFS_uint32) filelen;
  368. } /* else */
  369. while ((totalread < filelen) && (totalread < 65557))
  370. {
  371. BAIL_IF_MACRO(!io->seek(io, filepos), NULL, -1);
  372. /* make sure we catch a signature between buffers. */
  373. if (totalread != 0)
  374. {
  375. if (!__PHYSFS_readAll(io, buf, maxread - 4))
  376. return -1;
  377. memcpy(&buf[maxread - 4], &extra, sizeof (extra));
  378. totalread += maxread - 4;
  379. } /* if */
  380. else
  381. {
  382. if (!__PHYSFS_readAll(io, buf, maxread))
  383. return -1;
  384. totalread += maxread;
  385. } /* else */
  386. memcpy(&extra, buf, sizeof (extra));
  387. for (i = maxread - 4; i > 0; i--)
  388. {
  389. if ((buf[i + 0] == 0x50) &&
  390. (buf[i + 1] == 0x4B) &&
  391. (buf[i + 2] == 0x05) &&
  392. (buf[i + 3] == 0x06) )
  393. {
  394. found = 1; /* that's the signature! */
  395. break;
  396. } /* if */
  397. } /* for */
  398. if (found)
  399. break;
  400. filepos -= (maxread - 4);
  401. if (filepos < 0)
  402. filepos = 0;
  403. } /* while */
  404. BAIL_IF_MACRO(!found, ERR_NOT_AN_ARCHIVE, -1);
  405. if (len != NULL)
  406. *len = filelen;
  407. return (filepos + i);
  408. } /* zip_find_end_of_central_dir */
  409. static int isZip(PHYSFS_Io *io)
  410. {
  411. PHYSFS_uint32 sig = 0;
  412. int retval = 0;
  413. /*
  414. * The first thing in a zip file might be the signature of the
  415. * first local file record, so it makes for a quick determination.
  416. */
  417. if (readui32(io, &sig))
  418. {
  419. retval = (sig == ZIP_LOCAL_FILE_SIG);
  420. if (!retval)
  421. {
  422. /*
  423. * No sig...might be a ZIP with data at the start
  424. * (a self-extracting executable, etc), so we'll have to do
  425. * it the hard way...
  426. */
  427. retval = (zip_find_end_of_central_dir(io, NULL) != -1);
  428. } /* if */
  429. } /* if */
  430. return retval;
  431. } /* isZip */
  432. static void zip_free_entries(ZIPentry *entries, PHYSFS_uint32 max)
  433. {
  434. PHYSFS_uint32 i;
  435. for (i = 0; i < max; i++)
  436. {
  437. ZIPentry *entry = &entries[i];
  438. if (entry->name != NULL)
  439. allocator.Free(entry->name);
  440. } /* for */
  441. allocator.Free(entries);
  442. } /* zip_free_entries */
  443. /*
  444. * This will find the ZIPentry associated with a path in platform-independent
  445. * notation. Directories don't have ZIPentries associated with them, but
  446. * (*isDir) will be set to non-zero if a dir was hit.
  447. */
  448. static ZIPentry *zip_find_entry(const ZIPinfo *info, const char *path,
  449. int *isDir)
  450. {
  451. ZIPentry *a = info->entries;
  452. PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path);
  453. PHYSFS_sint32 lo = 0;
  454. PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
  455. PHYSFS_sint32 middle;
  456. const char *thispath = NULL;
  457. int rc;
  458. while (lo <= hi)
  459. {
  460. middle = lo + ((hi - lo) / 2);
  461. thispath = a[middle].name;
  462. rc = strncmp(path, thispath, pathlen);
  463. if (rc > 0)
  464. lo = middle + 1;
  465. else if (rc < 0)
  466. hi = middle - 1;
  467. else /* substring match...might be dir or entry or nothing. */
  468. {
  469. if (isDir != NULL)
  470. {
  471. *isDir = (thispath[pathlen] == '/');
  472. if (*isDir)
  473. return NULL;
  474. } /* if */
  475. if (thispath[pathlen] == '\0') /* found entry? */
  476. return &a[middle];
  477. /* adjust search params, try again. */
  478. else if (thispath[pathlen] > '/')
  479. hi = middle - 1;
  480. else
  481. lo = middle + 1;
  482. } /* if */
  483. } /* while */
  484. if (isDir != NULL)
  485. *isDir = 0;
  486. BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
  487. } /* zip_find_entry */
  488. /* Convert paths from old, buggy DOS zippers... */
  489. static void zip_convert_dos_path(ZIPentry *entry, char *path)
  490. {
  491. PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((entry->version >> 8) & 0xFF);
  492. if (hosttype == 0) /* FS_FAT_ */
  493. {
  494. while (*path)
  495. {
  496. if (*path == '\\')
  497. *path = '/';
  498. path++;
  499. } /* while */
  500. } /* if */
  501. } /* zip_convert_dos_path */
  502. static void zip_expand_symlink_path(char *path)
  503. {
  504. char *ptr = path;
  505. char *prevptr = path;
  506. while (1)
  507. {
  508. ptr = strchr(ptr, '/');
  509. if (ptr == NULL)
  510. break;
  511. if (*(ptr + 1) == '.')
  512. {
  513. if (*(ptr + 2) == '/')
  514. {
  515. /* current dir in middle of string: ditch it. */
  516. memmove(ptr, ptr + 2, strlen(ptr + 2) + 1);
  517. } /* else if */
  518. else if (*(ptr + 2) == '\0')
  519. {
  520. /* current dir at end of string: ditch it. */
  521. *ptr = '\0';
  522. } /* else if */
  523. else if (*(ptr + 2) == '.')
  524. {
  525. if (*(ptr + 3) == '/')
  526. {
  527. /* parent dir in middle: move back one, if possible. */
  528. memmove(prevptr, ptr + 4, strlen(ptr + 4) + 1);
  529. ptr = prevptr;
  530. while (prevptr != path)
  531. {
  532. prevptr--;
  533. if (*prevptr == '/')
  534. {
  535. prevptr++;
  536. break;
  537. } /* if */
  538. } /* while */
  539. } /* if */
  540. if (*(ptr + 3) == '\0')
  541. {
  542. /* parent dir at end: move back one, if possible. */
  543. *prevptr = '\0';
  544. } /* if */
  545. } /* if */
  546. } /* if */
  547. else
  548. {
  549. prevptr = ptr;
  550. ptr++;
  551. } /* else */
  552. } /* while */
  553. } /* zip_expand_symlink_path */
  554. /* (forward reference: zip_follow_symlink and zip_resolve call each other.) */
  555. static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry);
  556. /*
  557. * Look for the entry named by (path). If it exists, resolve it, and return
  558. * a pointer to that entry. If it's another symlink, keep resolving until you
  559. * hit a real file and then return a pointer to the final non-symlink entry.
  560. * If there's a problem, return NULL. (path) is always free()'d by this
  561. * function.
  562. */
  563. static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path)
  564. {
  565. ZIPentry *entry;
  566. zip_expand_symlink_path(path);
  567. entry = zip_find_entry(info, path, NULL);
  568. if (entry != NULL)
  569. {
  570. if (!zip_resolve(io, info, entry)) /* recursive! */
  571. entry = NULL;
  572. else
  573. {
  574. if (entry->symlink != NULL)
  575. entry = entry->symlink;
  576. } /* else */
  577. } /* if */
  578. allocator.Free(path);
  579. return entry;
  580. } /* zip_follow_symlink */
  581. static int zip_resolve_symlink(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
  582. {
  583. char *path;
  584. const PHYSFS_uint32 size = entry->uncompressed_size;
  585. int rc = 0;
  586. /*
  587. * We've already parsed the local file header of the symlink at this
  588. * point. Now we need to read the actual link from the file data and
  589. * follow it.
  590. */
  591. BAIL_IF_MACRO(!io->seek(io, entry->offset), NULL, 0);
  592. path = (char *) allocator.Malloc(size + 1);
  593. BAIL_IF_MACRO(path == NULL, ERR_OUT_OF_MEMORY, 0);
  594. if (entry->compression_method == COMPMETH_NONE)
  595. rc = __PHYSFS_readAll(io, path, size);
  596. else /* symlink target path is compressed... */
  597. {
  598. z_stream stream;
  599. const PHYSFS_uint32 complen = entry->compressed_size;
  600. PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen);
  601. if (compressed != NULL)
  602. {
  603. if (__PHYSFS_readAll(io, compressed, complen))
  604. {
  605. initializeZStream(&stream);
  606. stream.next_in = compressed;
  607. stream.avail_in = complen;
  608. stream.next_out = (unsigned char *) path;
  609. stream.avail_out = size;
  610. if (zlib_err(inflateInit2(&stream, -MAX_WBITS)) == Z_OK)
  611. {
  612. rc = zlib_err(inflate(&stream, Z_FINISH));
  613. inflateEnd(&stream);
  614. /* both are acceptable outcomes... */
  615. rc = ((rc == Z_OK) || (rc == Z_STREAM_END));
  616. } /* if */
  617. } /* if */
  618. __PHYSFS_smallFree(compressed);
  619. } /* if */
  620. } /* else */
  621. if (!rc)
  622. allocator.Free(path);
  623. else
  624. {
  625. path[entry->uncompressed_size] = '\0'; /* null-terminate it. */
  626. zip_convert_dos_path(entry, path);
  627. entry->symlink = zip_follow_symlink(io, info, path);
  628. } /* else */
  629. return (entry->symlink != NULL);
  630. } /* zip_resolve_symlink */
  631. /*
  632. * Parse the local file header of an entry, and update entry->offset.
  633. */
  634. static int zip_parse_local(PHYSFS_Io *io, ZIPentry *entry)
  635. {
  636. PHYSFS_uint32 ui32;
  637. PHYSFS_uint16 ui16;
  638. PHYSFS_uint16 fnamelen;
  639. PHYSFS_uint16 extralen;
  640. /*
  641. * crc and (un)compressed_size are always zero if this is a "JAR"
  642. * archive created with Sun's Java tools, apparently. We only
  643. * consider this archive corrupted if those entries don't match and
  644. * aren't zero. That seems to work well.
  645. */
  646. BAIL_IF_MACRO(!io->seek(io, entry->offset), NULL, 0);
  647. BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
  648. BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, ERR_CORRUPTED, 0);
  649. BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
  650. BAIL_IF_MACRO(ui16 != entry->version_needed, ERR_CORRUPTED, 0);
  651. BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* general bits. */
  652. BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
  653. BAIL_IF_MACRO(ui16 != entry->compression_method, ERR_CORRUPTED, 0);
  654. BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0); /* date/time */
  655. BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
  656. BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), ERR_CORRUPTED, 0);
  657. BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
  658. BAIL_IF_MACRO(ui32 && (ui32 != entry->compressed_size), ERR_CORRUPTED, 0);
  659. BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
  660. BAIL_IF_MACRO(ui32 && (ui32 != entry->uncompressed_size),ERR_CORRUPTED,0);
  661. BAIL_IF_MACRO(!readui16(io, &fnamelen), NULL, 0);
  662. BAIL_IF_MACRO(!readui16(io, &extralen), NULL, 0);
  663. entry->offset += fnamelen + extralen + 30;
  664. return 1;
  665. } /* zip_parse_local */
  666. static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
  667. {
  668. int retval = 1;
  669. ZipResolveType resolve_type = entry->resolved;
  670. /* Don't bother if we've failed to resolve this entry before. */
  671. BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, ERR_CORRUPTED, 0);
  672. BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, ERR_CORRUPTED, 0);
  673. /* uhoh...infinite symlink loop! */
  674. BAIL_IF_MACRO(resolve_type == ZIP_RESOLVING, ERR_SYMLINK_LOOP, 0);
  675. /*
  676. * We fix up the offset to point to the actual data on the
  677. * first open, since we don't want to seek across the whole file on
  678. * archive open (can be SLOW on large, CD-stored files), but we
  679. * need to check the local file header...not just for corruption,
  680. * but since it stores offset info the central directory does not.
  681. */
  682. if (resolve_type != ZIP_RESOLVED)
  683. {
  684. entry->resolved = ZIP_RESOLVING;
  685. retval = zip_parse_local(io, entry);
  686. if (retval)
  687. {
  688. /*
  689. * If it's a symlink, find the original file. This will cause
  690. * resolution of other entries (other symlinks and, eventually,
  691. * the real file) if all goes well.
  692. */
  693. if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
  694. retval = zip_resolve_symlink(io, info, entry);
  695. } /* if */
  696. if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
  697. entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_SYMLINK);
  698. else if (resolve_type == ZIP_UNRESOLVED_FILE)
  699. entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);
  700. } /* if */
  701. return retval;
  702. } /* zip_resolve */
  703. static int zip_version_does_symlinks(PHYSFS_uint32 version)
  704. {
  705. int retval = 0;
  706. PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((version >> 8) & 0xFF);
  707. switch (hosttype)
  708. {
  709. /*
  710. * These are the platforms that can NOT build an archive with
  711. * symlinks, according to the Info-ZIP project.
  712. */
  713. case 0: /* FS_FAT_ */
  714. case 1: /* AMIGA_ */
  715. case 2: /* VMS_ */
  716. case 4: /* VM_CSM_ */
  717. case 6: /* FS_HPFS_ */
  718. case 11: /* FS_NTFS_ */
  719. case 14: /* FS_VFAT_ */
  720. case 13: /* ACORN_ */
  721. case 15: /* MVS_ */
  722. case 18: /* THEOS_ */
  723. break; /* do nothing. */
  724. default: /* assume the rest to be unix-like. */
  725. retval = 1;
  726. break;
  727. } /* switch */
  728. return retval;
  729. } /* zip_version_does_symlinks */
  730. static int zip_entry_is_symlink(const ZIPentry *entry)
  731. {
  732. return ((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
  733. (entry->resolved == ZIP_BROKEN_SYMLINK) ||
  734. (entry->symlink));
  735. } /* zip_entry_is_symlink */
  736. static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
  737. {
  738. PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
  739. return ( (zip_version_does_symlinks(entry->version)) &&
  740. (entry->uncompressed_size > 0) &&
  741. ((xattr & UNIX_FILETYPE_MASK) == UNIX_FILETYPE_SYMLINK) );
  742. } /* zip_has_symlink_attr */
  743. static PHYSFS_sint64 zip_dos_time_to_physfs_time(PHYSFS_uint32 dostime)
  744. {
  745. PHYSFS_uint32 dosdate;
  746. struct tm unixtime;
  747. memset(&unixtime, '\0', sizeof (unixtime));
  748. dosdate = (PHYSFS_uint32) ((dostime >> 16) & 0xFFFF);
  749. dostime &= 0xFFFF;
  750. /* dissect date */
  751. unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80;
  752. unixtime.tm_mon = ((dosdate >> 5) & 0x0F) - 1;
  753. unixtime.tm_mday = ((dosdate ) & 0x1F);
  754. /* dissect time */
  755. unixtime.tm_hour = ((dostime >> 11) & 0x1F);
  756. unixtime.tm_min = ((dostime >> 5) & 0x3F);
  757. unixtime.tm_sec = ((dostime << 1) & 0x3E);
  758. /* let mktime calculate daylight savings time. */
  759. unixtime.tm_isdst = -1;
  760. return ((PHYSFS_sint64) mktime(&unixtime));
  761. } /* zip_dos_time_to_physfs_time */
  762. static int zip_load_entry(PHYSFS_Io *io, ZIPentry *entry, PHYSFS_uint32 ofs_fixup)
  763. {
  764. PHYSFS_uint16 fnamelen, extralen, commentlen;
  765. PHYSFS_uint32 external_attr;
  766. PHYSFS_uint16 ui16;
  767. PHYSFS_uint32 ui32;
  768. PHYSFS_sint64 si64;
  769. /* sanity check with central directory signature... */
  770. BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
  771. BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, ERR_CORRUPTED, 0);
  772. /* Get the pertinent parts of the record... */
  773. BAIL_IF_MACRO(!readui16(io, &entry->version), NULL, 0);
  774. BAIL_IF_MACRO(!readui16(io, &entry->version_needed), NULL, 0);
  775. BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* general bits */
  776. BAIL_IF_MACRO(!readui16(io, &entry->compression_method), NULL, 0);
  777. BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
  778. entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
  779. BAIL_IF_MACRO(!readui32(io, &entry->crc), NULL, 0);
  780. BAIL_IF_MACRO(!readui32(io, &entry->compressed_size), NULL, 0);
  781. BAIL_IF_MACRO(!readui32(io, &entry->uncompressed_size), NULL, 0);
  782. BAIL_IF_MACRO(!readui16(io, &fnamelen), NULL, 0);
  783. BAIL_IF_MACRO(!readui16(io, &extralen), NULL, 0);
  784. BAIL_IF_MACRO(!readui16(io, &commentlen), NULL, 0);
  785. BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* disk number start */
  786. BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* internal file attribs */
  787. BAIL_IF_MACRO(!readui32(io, &external_attr), NULL, 0);
  788. BAIL_IF_MACRO(!readui32(io, &entry->offset), NULL, 0);
  789. entry->offset += ofs_fixup;
  790. entry->symlink = NULL; /* will be resolved later, if necessary. */
  791. entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ?
  792. ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;
  793. entry->name = (char *) allocator.Malloc(fnamelen + 1);
  794. BAIL_IF_MACRO(entry->name == NULL, ERR_OUT_OF_MEMORY, 0);
  795. if (!__PHYSFS_readAll(io, entry->name, fnamelen))
  796. goto zip_load_entry_puked;
  797. entry->name[fnamelen] = '\0'; /* null-terminate the filename. */
  798. zip_convert_dos_path(entry, entry->name);
  799. si64 = io->tell(io);
  800. if (si64 == -1)
  801. goto zip_load_entry_puked;
  802. /* seek to the start of the next entry in the central directory... */
  803. if (!io->seek(io, si64 + extralen + commentlen))
  804. goto zip_load_entry_puked;
  805. return 1; /* success. */
  806. zip_load_entry_puked:
  807. allocator.Free(entry->name);
  808. return 0; /* failure. */
  809. } /* zip_load_entry */
  810. static int zip_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
  811. {
  812. if (one != two)
  813. {
  814. const ZIPentry *a = (const ZIPentry *) _a;
  815. return strcmp(a[one].name, a[two].name);
  816. } /* if */
  817. return 0;
  818. } /* zip_entry_cmp */
  819. static void zip_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
  820. {
  821. if (one != two)
  822. {
  823. ZIPentry tmp;
  824. ZIPentry *first = &(((ZIPentry *) _a)[one]);
  825. ZIPentry *second = &(((ZIPentry *) _a)[two]);
  826. memcpy(&tmp, first, sizeof (ZIPentry));
  827. memcpy(first, second, sizeof (ZIPentry));
  828. memcpy(second, &tmp, sizeof (ZIPentry));
  829. } /* if */
  830. } /* zip_entry_swap */
  831. static int zip_load_entries(PHYSFS_Io *io, ZIPinfo *info,
  832. PHYSFS_uint32 data_ofs, PHYSFS_uint32 central_ofs)
  833. {
  834. PHYSFS_uint32 max = info->entryCount;
  835. PHYSFS_uint32 i;
  836. BAIL_IF_MACRO(!io->seek(io, central_ofs), NULL, 0);
  837. info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max);
  838. BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
  839. for (i = 0; i < max; i++)
  840. {
  841. if (!zip_load_entry(io, &info->entries[i], data_ofs))
  842. {
  843. zip_free_entries(info->entries, i);
  844. return 0;
  845. } /* if */
  846. } /* for */
  847. __PHYSFS_sort(info->entries, max, zip_entry_cmp, zip_entry_swap);
  848. return 1;
  849. } /* zip_load_entries */
  850. static int zip_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
  851. PHYSFS_uint32 *data_start,
  852. PHYSFS_uint32 *central_dir_ofs)
  853. {
  854. PHYSFS_uint32 ui32;
  855. PHYSFS_uint16 ui16;
  856. PHYSFS_sint64 len;
  857. PHYSFS_sint64 pos;
  858. /* find the end-of-central-dir record, and seek to it. */
  859. pos = zip_find_end_of_central_dir(io, &len);
  860. BAIL_IF_MACRO(pos == -1, NULL, 0);
  861. BAIL_IF_MACRO(!io->seek(io, pos), NULL, 0);
  862. /* check signature again, just in case. */
  863. BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
  864. BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, ERR_NOT_AN_ARCHIVE, 0);
  865. /* number of this disk */
  866. BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
  867. BAIL_IF_MACRO(ui16 != 0, ERR_UNSUPPORTED_ARCHIVE, 0);
  868. /* number of the disk with the start of the central directory */
  869. BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
  870. BAIL_IF_MACRO(ui16 != 0, ERR_UNSUPPORTED_ARCHIVE, 0);
  871. /* total number of entries in the central dir on this disk */
  872. BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
  873. /* total number of entries in the central dir */
  874. BAIL_IF_MACRO(!readui16(io, &info->entryCount), NULL, 0);
  875. BAIL_IF_MACRO(ui16 != info->entryCount, ERR_UNSUPPORTED_ARCHIVE, 0);
  876. /* size of the central directory */
  877. BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
  878. /* offset of central directory */
  879. BAIL_IF_MACRO(!readui32(io, central_dir_ofs), NULL, 0);
  880. BAIL_IF_MACRO(pos < *central_dir_ofs + ui32, ERR_UNSUPPORTED_ARCHIVE, 0);
  881. /*
  882. * For self-extracting archives, etc, there's crapola in the file
  883. * before the zipfile records; we calculate how much data there is
  884. * prepended by determining how far the central directory offset is
  885. * from where it is supposed to be (start of end-of-central-dir minus
  886. * sizeof central dir)...the difference in bytes is how much arbitrary
  887. * data is at the start of the physical file.
  888. */
  889. *data_start = (PHYSFS_uint32) (pos - (*central_dir_ofs + ui32));
  890. /* Now that we know the difference, fix up the central dir offset... */
  891. *central_dir_ofs += *data_start;
  892. /* zipfile comment length */
  893. BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
  894. /*
  895. * Make sure that the comment length matches to the end of file...
  896. * If it doesn't, we're either in the wrong part of the file, or the
  897. * file is corrupted, but we give up either way.
  898. */
  899. BAIL_IF_MACRO((pos + 22 + ui16) != len, ERR_UNSUPPORTED_ARCHIVE, 0);
  900. return 1; /* made it. */
  901. } /* zip_parse_end_of_central_dir */
  902. static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
  903. {
  904. ZIPinfo *info = NULL;
  905. PHYSFS_uint32 data_start;
  906. PHYSFS_uint32 cent_dir_ofs;
  907. assert(io != NULL); /* shouldn't ever happen. */
  908. BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
  909. BAIL_IF_MACRO(!isZip(io), NULL, NULL);
  910. info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
  911. BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
  912. memset(info, '\0', sizeof (ZIPinfo));
  913. info->io = io;
  914. if (!zip_parse_end_of_central_dir(io, info, &data_start, &cent_dir_ofs))
  915. goto ZIP_openarchive_failed;
  916. if (!zip_load_entries(io, info, data_start, cent_dir_ofs))
  917. goto ZIP_openarchive_failed;
  918. return info;
  919. ZIP_openarchive_failed:
  920. if (info != NULL)
  921. allocator.Free(info);
  922. return NULL;
  923. } /* ZIP_openArchive */
  924. static PHYSFS_sint32 zip_find_start_of_dir(ZIPinfo *info, const char *path,
  925. int stop_on_first_find)
  926. {
  927. PHYSFS_sint32 lo = 0;
  928. PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
  929. PHYSFS_sint32 middle;
  930. PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path);
  931. PHYSFS_sint32 retval = -1;
  932. const char *name;
  933. int rc;
  934. if (*path == '\0') /* root dir? */
  935. return 0;
  936. if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
  937. dlen--;
  938. while (lo <= hi)
  939. {
  940. middle = lo + ((hi - lo) / 2);
  941. name = info->entries[middle].name;
  942. rc = strncmp(path, name, dlen);
  943. if (rc == 0)
  944. {
  945. char ch = name[dlen];
  946. if ('/' < ch) /* make sure this isn't just a substr match. */
  947. rc = -1;
  948. else if ('/' > ch)
  949. rc = 1;
  950. else
  951. {
  952. if (stop_on_first_find) /* Just checking dir's existance? */
  953. return middle;
  954. if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
  955. return (middle + 1);
  956. /* there might be more entries earlier in the list. */
  957. retval = middle;
  958. hi = middle - 1;
  959. } /* else */
  960. } /* if */
  961. if (rc > 0)
  962. lo = middle + 1;
  963. else
  964. hi = middle - 1;
  965. } /* while */
  966. return retval;
  967. } /* zip_find_start_of_dir */
  968. /*
  969. * Moved to seperate function so we can use alloca then immediately throw
  970. * away the allocated stack space...
  971. */
  972. static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
  973. const char *odir, const char *str, PHYSFS_sint32 ln)
  974. {
  975. char *newstr = __PHYSFS_smallAlloc(ln + 1);
  976. if (newstr == NULL)
  977. return;
  978. memcpy(newstr, str, ln);
  979. newstr[ln] = '\0';
  980. cb(callbackdata, odir, newstr);
  981. __PHYSFS_smallFree(newstr);
  982. } /* doEnumCallback */
  983. static void ZIP_enumerateFiles(dvoid *opaque, const char *dname,
  984. int omitSymLinks, PHYSFS_EnumFilesCallback cb,
  985. const char *origdir, void *callbackdata)
  986. {
  987. ZIPinfo *info = ((ZIPinfo *) opaque);
  988. PHYSFS_sint32 dlen, dlen_inc, max, i;
  989. i = zip_find_start_of_dir(info, dname, 0);
  990. if (i == -1) /* no such directory. */
  991. return;
  992. dlen = (PHYSFS_sint32) strlen(dname);
  993. if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
  994. dlen--;
  995. dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
  996. max = (PHYSFS_sint32) info->entryCount;
  997. while (i < max)
  998. {
  999. char *e = info->entries[i].name;
  1000. if ((dlen) && ((strncmp(e, dname, dlen) != 0) || (e[dlen] != '/')))
  1001. break; /* past end of this dir; we're done. */
  1002. if ((omitSymLinks) && (zip_entry_is_symlink(&info->entries[i])))
  1003. i++;
  1004. else
  1005. {
  1006. char *add = e + dlen_inc;
  1007. char *ptr = strchr(add, '/');
  1008. PHYSFS_sint32 ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
  1009. doEnumCallback(cb, callbackdata, origdir, add, ln);
  1010. ln += dlen_inc; /* point past entry to children... */
  1011. /* increment counter and skip children of subdirs... */
  1012. while ((++i < max) && (ptr != NULL))
  1013. {
  1014. char *e_new = info->entries[i].name;
  1015. if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
  1016. break;
  1017. } /* while */
  1018. } /* else */
  1019. } /* while */
  1020. } /* ZIP_enumerateFiles */
  1021. static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry)
  1022. {
  1023. int success;
  1024. PHYSFS_Io *retval = io->duplicate(io);
  1025. BAIL_IF_MACRO(retval == NULL, NULL, NULL);
  1026. /* (inf) can be NULL if we already resolved. */
  1027. success = (inf == NULL) || zip_resolve(retval, inf, entry);
  1028. if (success)
  1029. {
  1030. PHYSFS_sint64 offset;
  1031. offset = ((entry->symlink) ? entry->symlink->offset : entry->offset);
  1032. success = retval->seek(retval, offset);
  1033. } /* if */
  1034. if (!success)
  1035. {
  1036. retval->destroy(retval);
  1037. retval = NULL;
  1038. } /* if */
  1039. return retval;
  1040. } /* zip_get_io */
  1041. static PHYSFS_Io *ZIP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
  1042. {
  1043. PHYSFS_Io *retval = NULL;
  1044. ZIPinfo *info = (ZIPinfo *) opaque;
  1045. ZIPentry *entry = zip_find_entry(info, fnm, NULL);
  1046. ZIPfileinfo *finfo = NULL;
  1047. *fileExists = (entry != NULL);
  1048. BAIL_IF_MACRO(entry == NULL, NULL, NULL);
  1049. retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
  1050. GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1051. finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
  1052. GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1053. memset(finfo, '\0', sizeof (ZIPfileinfo));
  1054. finfo->io = zip_get_io(info->io, info, entry);
  1055. GOTO_IF_MACRO(finfo->io == NULL, NULL, ZIP_openRead_failed);
  1056. finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
  1057. initializeZStream(&finfo->stream);
  1058. if (finfo->entry->compression_method != COMPMETH_NONE)
  1059. {
  1060. finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
  1061. GOTO_IF_MACRO(!finfo->buffer, ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
  1062. if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
  1063. goto ZIP_openRead_failed;
  1064. } /* if */
  1065. memcpy(retval, &ZIP_Io, sizeof (PHYSFS_Io));
  1066. retval->opaque = finfo;
  1067. return retval;
  1068. ZIP_openRead_failed:
  1069. if (finfo != NULL)
  1070. {
  1071. if (finfo->io != NULL)
  1072. finfo->io->destroy(finfo->io);
  1073. if (finfo->buffer != NULL)
  1074. {
  1075. allocator.Free(finfo->buffer);
  1076. inflateEnd(&finfo->stream);
  1077. } /* if */
  1078. allocator.Free(finfo);
  1079. } /* if */
  1080. if (retval != NULL)
  1081. allocator.Free(retval);
  1082. return NULL;
  1083. } /* ZIP_openRead */
  1084. static PHYSFS_Io *ZIP_openWrite(dvoid *opaque, const char *filename)
  1085. {
  1086. BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
  1087. } /* ZIP_openWrite */
  1088. static PHYSFS_Io *ZIP_openAppend(dvoid *opaque, const char *filename)
  1089. {
  1090. BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
  1091. } /* ZIP_openAppend */
  1092. static void ZIP_dirClose(dvoid *opaque)
  1093. {
  1094. ZIPinfo *zi = (ZIPinfo *) (opaque);
  1095. zi->io->destroy(zi->io);
  1096. zip_free_entries(zi->entries, zi->entryCount);
  1097. allocator.Free(zi);
  1098. } /* ZIP_dirClose */
  1099. static int ZIP_remove(dvoid *opaque, const char *name)
  1100. {
  1101. BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
  1102. } /* ZIP_remove */
  1103. static int ZIP_mkdir(dvoid *opaque, const char *name)
  1104. {
  1105. BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
  1106. } /* ZIP_mkdir */
  1107. static int ZIP_stat(dvoid *opaque, const char *filename, int *exists,
  1108. PHYSFS_Stat *stat)
  1109. {
  1110. int isDir = 0;
  1111. const ZIPinfo *info = (const ZIPinfo *) opaque;
  1112. const ZIPentry *entry = zip_find_entry(info, filename, &isDir);
  1113. /* !!! FIXME: does this need to resolve entries here? */
  1114. *exists = isDir || (entry != 0);
  1115. if (!*exists)
  1116. return 0;
  1117. if (isDir)
  1118. {
  1119. stat->filesize = 0;
  1120. stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
  1121. } /* if */
  1122. else if (zip_entry_is_symlink(entry))
  1123. {
  1124. stat->filesize = 0;
  1125. stat->filetype = PHYSFS_FILETYPE_SYMLINK;
  1126. } /* else if */
  1127. else
  1128. {
  1129. stat->filesize = entry->uncompressed_size;
  1130. stat->filetype = PHYSFS_FILETYPE_REGULAR;
  1131. } /* else */
  1132. stat->modtime = ((entry) ? entry->last_mod_time : 0);
  1133. stat->createtime = stat->modtime;
  1134. stat->accesstime = 0;
  1135. stat->readonly = 1; /* .zip files are always read only */
  1136. return 1;
  1137. } /* ZIP_stat */
  1138. const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP =
  1139. {
  1140. "ZIP",
  1141. ZIP_ARCHIVE_DESCRIPTION,
  1142. "Ryan C. Gordon <icculus@icculus.org>",
  1143. "http://icculus.org/physfs/",
  1144. };
  1145. const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
  1146. {
  1147. &__PHYSFS_ArchiveInfo_ZIP,
  1148. ZIP_openArchive, /* openArchive() method */
  1149. ZIP_enumerateFiles, /* enumerateFiles() method */
  1150. ZIP_openRead, /* openRead() method */
  1151. ZIP_openWrite, /* openWrite() method */
  1152. ZIP_openAppend, /* openAppend() method */
  1153. ZIP_remove, /* remove() method */
  1154. ZIP_mkdir, /* mkdir() method */
  1155. ZIP_dirClose, /* dirClose() method */
  1156. ZIP_stat /* stat() method */
  1157. };
  1158. #endif /* defined PHYSFS_SUPPORTS_ZIP */
  1159. /* end of zip.c ... */