unzip.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. // Copyright (C) 2004-2025 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include <string.h>
  24. #include <limits.h>
  25. #include "z-imp.h"
  26. #if !defined (INT32_MAX)
  27. #define INT32_MAX 2147483647L
  28. #endif
  29. #define ZIP_LOCAL_FILE_SIG 0x04034b50
  30. #define ZIP_DATA_DESC_SIG 0x08074b50
  31. #define ZIP_CENTRAL_DIRECTORY_SIG 0x02014b50
  32. #define ZIP_END_OF_CENTRAL_DIRECTORY_SIG 0x06054b50
  33. #define ZIP_UP_SIG 0x7075
  34. #define ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG 0x07064b50
  35. #define ZIP64_END_OF_CENTRAL_DIRECTORY_SIG 0x06064b50
  36. #define ZIP64_EXTRA_FIELD_SIG 0x0001
  37. #define ZIP_ENCRYPTED_FLAG 0x1
  38. typedef struct
  39. {
  40. char *name;
  41. uint64_t offset, csize, usize;
  42. } zip_entry;
  43. typedef struct
  44. {
  45. fz_archive super;
  46. int count;
  47. zip_entry *entries;
  48. } fz_zip_archive;
  49. static void drop_zip_archive(fz_context *ctx, fz_archive *arch)
  50. {
  51. fz_zip_archive *zip = (fz_zip_archive *) arch;
  52. int i;
  53. for (i = 0; i < zip->count; ++i)
  54. fz_free(ctx, zip->entries[i].name);
  55. fz_free(ctx, zip->entries);
  56. }
  57. static int ishex(char c)
  58. {
  59. if (c >= '0' && c <= '9')
  60. return 1;
  61. if (c >= 'a' && c <= 'f')
  62. return 1;
  63. if (c >= 'A' && c <= 'F')
  64. return 1;
  65. return 0;
  66. }
  67. static int unhex(char c)
  68. {
  69. if (c >= '0' && c <= '9')
  70. return c-'0';
  71. if (c >= 'a' && c <= 'f')
  72. return c-'a'+10;
  73. return c - 'A'+10;
  74. }
  75. /* This is to cope with the #Uffff and #Lffffff escaping scheme
  76. * used by info-zip when encoding files into zipfiles on
  77. * non-utf8-native platforms, like Windows. Although this isn't
  78. * strictly part of the zip standard, info-zip has been doing
  79. * this since 2008 at least, and it's ubiquitous. We shouldn't
  80. * get '#' chars in filenames otherwise, so it's pretty safe.
  81. */
  82. static unsigned char *unescape(fz_context *ctx, unsigned char *name)
  83. {
  84. unsigned char *newname;
  85. unsigned char *d;
  86. unsigned char *s = name;
  87. unsigned char c;
  88. size_t z = 1;
  89. /* Count the target length */
  90. while ((c = *s++) != 0)
  91. {
  92. if (c == '#' && s[0] == 'U' &&
  93. ishex(s[1]) && ishex(s[2]) && ishex(s[3]) && ishex(s[4]))
  94. {
  95. int uni = (unhex(s[1])<<12)+(unhex(s[2])<<8)+(unhex(s[3])<<4)+unhex(s[4]);
  96. if (uni < 0x80)
  97. {
  98. /* Unlikely, cos why would it have been escaped? */
  99. z++;
  100. }
  101. else if (uni < (1<<11))
  102. {
  103. z += 2;
  104. }
  105. else
  106. {
  107. z += 3;
  108. }
  109. s += 5;
  110. }
  111. else if (c == '#' && s[0] == 'L' &&
  112. ishex(s[1]) && ishex(s[2]) && ishex(s[3]) && ishex(s[4]) && ishex(s[5]) && ishex(s[6]))
  113. {
  114. int uni = (unhex(s[1])<<20)+(unhex(s[2])<<16)+(unhex(s[3])<<12)+(unhex(s[4])<<8)+(unhex(s[5])<<4)+unhex(s[6]);
  115. if (uni < 0x80)
  116. {
  117. /* Unlikely, cos why would it have been escaped? */
  118. z++;
  119. }
  120. else if (uni < (1<<11))
  121. {
  122. /* Unlikely, cos why wouldn't it be #U? */
  123. z += 2;
  124. }
  125. else if (uni < (1<<16))
  126. {
  127. /* Unlikely, cos why wouldn't it be #U? */
  128. z += 3;
  129. }
  130. else if (uni <= 0x10FFFF)
  131. {
  132. z += 4;
  133. }
  134. else
  135. {
  136. /* Illegal char for utf-8 encoding. */
  137. /* Leave escaped! */
  138. z += 8;
  139. }
  140. s += 7;
  141. }
  142. else if (c >= 0x80)
  143. {
  144. /* Why wasn't this byte escaped? Encode it to utf-8, best we can do. */
  145. z += 2;
  146. }
  147. else
  148. z++;
  149. }
  150. newname = Memento_label(fz_malloc(ctx, z), "zip_name");
  151. d = newname;
  152. s = name;
  153. /* Now rewrite the name */
  154. while ((c = *s++) != 0)
  155. {
  156. if (c == '#' && s[0] == 'U' &&
  157. ishex(s[1]) && ishex(s[2]) && ishex(s[3]) && ishex(s[4]))
  158. {
  159. int uni = (unhex(s[1])<<12)+(unhex(s[2])<<8)+(unhex(s[3])<<4)+unhex(s[4]);
  160. if (uni < 0x80)
  161. {
  162. /* Unlikely, cos why would it have been escaped? */
  163. *d++ = uni;
  164. }
  165. else if (uni < (1<<11))
  166. {
  167. *d++ = 0xC0+(uni>>6); /* 5 bits */
  168. *d++ = 0x80+(uni & 0x3f); /* 6 bits */
  169. }
  170. else
  171. {
  172. *d++ = 0xE0+(uni>>12); /* 4 bits */
  173. *d++ = 0x80+((uni>>6) & 0x3f); /* 6 bits */
  174. *d++ = 0x80+(uni & 0x3f); /* 6 bits */
  175. }
  176. s += 5;
  177. }
  178. else if (c == '#' && s[0] == 'L' &&
  179. ishex(s[1]) && ishex(s[2]) && ishex(s[3]) && ishex(s[4]) && ishex(s[5]) && ishex(s[6]))
  180. {
  181. int uni = (unhex(s[1])<<20)+(unhex(s[2])<<16)+(unhex(s[3])<<12)+(unhex(s[4])<<8)+(unhex(s[5])<<4)+unhex(s[6]);
  182. if (uni < 0x80)
  183. {
  184. /* Unlikely, cos why would it have been escaped? */
  185. *d++ = uni;
  186. }
  187. else if (uni < (1<<11))
  188. {
  189. /* Unlikely, cos why wouldn't it be #U? */
  190. *d++ = 0xC0+(uni>>6); /* 5 bits */
  191. *d++ = 0x80+(uni & 0x3f); /* 6 bits */
  192. }
  193. else if (uni < (1<<16))
  194. {
  195. /* Unlikely, cos why wouldn't it be #U? */
  196. *d++ = 0xE0+(uni>>12); /* 4 bits */
  197. *d++ = 0x80+((uni>>6) & 0x3f); /* 6 bits */
  198. *d++ = 0x80+(uni & 0x3f); /* 6 bits */
  199. }
  200. else if (uni <= 0x10FFFF)
  201. {
  202. *d++ = 0xF0+(uni>>18); /* 3 bits */
  203. *d++ = 0x80+((uni>>12) & 0x3f); /* 6 bits */
  204. *d++ = 0x80+((uni>>6) & 0x3f); /* 6 bits */
  205. *d++ = 0x80+(uni & 0x3f); /* 6 bits */
  206. }
  207. else
  208. {
  209. /* Illegal char for utf-8 encoding. */
  210. /* Leave escaped! */
  211. memcpy(d, s-1, 8);
  212. d += 8;
  213. }
  214. s += 7;
  215. }
  216. else if (c >= 0x80)
  217. {
  218. /* Why wasn't this byte escaped? Encode it to utf-8, best we can do. */
  219. *d++ = 0xC0+(c>>6); /* 5 bits */
  220. *d++ = 0x80+(c & 0x3f); /* 6 bits */
  221. }
  222. else
  223. *d++ = c;
  224. }
  225. *d = 0;
  226. fz_free(ctx, name);
  227. return newname;
  228. }
  229. static void read_zip_dir_imp(fz_context *ctx, fz_zip_archive *zip, int64_t start_offset)
  230. {
  231. fz_stream *file = zip->super.file;
  232. uint32_t sig;
  233. int i;
  234. int namesize, metasize, commentsize;
  235. uint64_t count, offset;
  236. uint64_t csize, usize;
  237. char *name = NULL;
  238. size_t n;
  239. int gp;
  240. int utf8 = 0;
  241. fz_var(name);
  242. zip->count = 0;
  243. fz_seek(ctx, file, start_offset, 0);
  244. sig = fz_read_uint32_le(ctx, file);
  245. if (sig != ZIP_END_OF_CENTRAL_DIRECTORY_SIG)
  246. fz_throw(ctx, FZ_ERROR_FORMAT, "wrong zip end of central directory signature (0x%x)", sig);
  247. (void) fz_read_uint16_le(ctx, file); /* this disk */
  248. (void) fz_read_uint16_le(ctx, file); /* start disk */
  249. (void) fz_read_uint16_le(ctx, file); /* entries in this disk */
  250. count = fz_read_uint16_le(ctx, file); /* entries in central directory disk */
  251. (void) fz_read_uint32_le(ctx, file); /* size of central directory */
  252. offset = fz_read_uint32_le(ctx, file); /* offset to central directory */
  253. /* ZIP64 */
  254. if (count == 0xFFFF || offset == 0xFFFFFFFF)
  255. {
  256. int64_t offset64, count64;
  257. fz_seek(ctx, file, start_offset - 20, 0);
  258. sig = fz_read_uint32_le(ctx, file);
  259. if (sig != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG)
  260. fz_throw(ctx, FZ_ERROR_FORMAT, "wrong zip64 end of central directory locator signature (0x%x)", sig);
  261. (void) fz_read_uint32_le(ctx, file); /* start disk */
  262. offset64 = fz_read_uint64_le(ctx, file); /* offset to end of central directory record */
  263. fz_seek(ctx, file, offset64, 0);
  264. sig = fz_read_uint32_le(ctx, file);
  265. if (sig != ZIP64_END_OF_CENTRAL_DIRECTORY_SIG)
  266. fz_throw(ctx, FZ_ERROR_FORMAT, "wrong zip64 end of central directory signature (0x%x)", sig);
  267. (void) fz_read_uint64_le(ctx, file); /* size of record */
  268. (void) fz_read_uint16_le(ctx, file); /* version made by */
  269. (void) fz_read_uint16_le(ctx, file); /* version to extract */
  270. (void) fz_read_uint32_le(ctx, file); /* disk number */
  271. (void) fz_read_uint32_le(ctx, file); /* disk number start */
  272. count64 = fz_read_uint64_le(ctx, file); /* entries in central directory disk */
  273. (void) fz_read_uint64_le(ctx, file); /* entries in central directory */
  274. (void) fz_read_uint64_le(ctx, file); /* size of central directory */
  275. offset64 = fz_read_uint64_le(ctx, file); /* offset to central directory */
  276. if (count == 0xFFFF)
  277. {
  278. count = count64;
  279. }
  280. if (offset == 0xFFFFFFFF)
  281. {
  282. offset = offset64;
  283. }
  284. }
  285. fz_seek(ctx, file, offset, 0);
  286. fz_try(ctx)
  287. {
  288. if (count > INT_MAX)
  289. count = INT_MAX;
  290. for (i = 0; i < (int)count; i++)
  291. {
  292. sig = fz_read_uint32_le(ctx, file);
  293. if (sig != ZIP_CENTRAL_DIRECTORY_SIG)
  294. fz_throw(ctx, FZ_ERROR_FORMAT, "wrong zip central directory signature (0x%x)", sig);
  295. (void) fz_read_uint16_le(ctx, file); /* version made by */
  296. (void) fz_read_uint16_le(ctx, file); /* version to extract */
  297. gp = fz_read_uint16_le(ctx, file); /* general */
  298. utf8 = !!(gp & (1<<11));
  299. (void) fz_read_uint16_le(ctx, file); /* method */
  300. (void) fz_read_uint16_le(ctx, file); /* last mod file time */
  301. (void) fz_read_uint16_le(ctx, file); /* last mod file date */
  302. (void) fz_read_uint32_le(ctx, file); /* crc-32 */
  303. csize = fz_read_uint32_le(ctx, file);
  304. usize = fz_read_uint32_le(ctx, file);
  305. namesize = fz_read_uint16_le(ctx, file);
  306. metasize = fz_read_uint16_le(ctx, file);
  307. commentsize = fz_read_uint16_le(ctx, file);
  308. (void) fz_read_uint16_le(ctx, file); /* disk number start */
  309. (void) fz_read_uint16_le(ctx, file); /* int file atts */
  310. (void) fz_read_uint32_le(ctx, file); /* ext file atts */
  311. offset = fz_read_uint32_le(ctx, file);
  312. name = Memento_label(fz_malloc(ctx, namesize + 1), "zip_name");
  313. n = fz_read(ctx, file, (unsigned char*)name, namesize);
  314. if (n < (size_t)namesize)
  315. fz_throw(ctx, FZ_ERROR_FORMAT, "premature end of data in zip entry name");
  316. name[namesize] = '\0';
  317. if (!utf8)
  318. name = (char *)unescape(ctx, (unsigned char *)name);
  319. while (metasize > 0)
  320. {
  321. int type = fz_read_uint16_le(ctx, file);
  322. int size = fz_read_uint16_le(ctx, file);
  323. if (type == ZIP64_EXTRA_FIELD_SIG)
  324. {
  325. int sizeleft = size;
  326. if (usize == 0xFFFFFFFF && sizeleft >= 8)
  327. {
  328. usize = fz_read_uint64_le(ctx, file);
  329. sizeleft -= 8;
  330. }
  331. if (csize == 0xFFFFFFFF && sizeleft >= 8)
  332. {
  333. csize = fz_read_uint64_le(ctx, file);
  334. sizeleft -= 8;
  335. }
  336. if (offset == 0xFFFFFFFF && sizeleft >= 8)
  337. {
  338. offset = fz_read_uint64_le(ctx, file);
  339. sizeleft -= 8;
  340. }
  341. fz_seek(ctx, file, sizeleft - size, 1);
  342. }
  343. if (type == ZIP_UP_SIG && size > 5)
  344. {
  345. int sizeleft = size - 1;
  346. if (fz_read_byte(ctx, file) == 1)
  347. {
  348. /* Version 1 */
  349. (void) fz_read_uint32(ctx, file); /* Skip the CRC */
  350. sizeleft -= 4;
  351. fz_free(ctx, name);
  352. name = NULL;
  353. name = Memento_label(fz_malloc(ctx, sizeleft + 1), "zip_name");
  354. fz_read(ctx, file, (unsigned char *)name, sizeleft);
  355. name[sizeleft] = 0;
  356. sizeleft = 0;
  357. }
  358. fz_seek(ctx, file, sizeleft - size, 1);
  359. }
  360. fz_seek(ctx, file, size, 1);
  361. metasize -= 4 + size;
  362. }
  363. if (usize > INT32_MAX || csize > INT32_MAX)
  364. fz_throw(ctx, FZ_ERROR_FORMAT, "zip archive entry larger than 2 GB");
  365. fz_seek(ctx, file, commentsize, 1);
  366. zip->entries = Memento_label(fz_realloc_array(ctx, zip->entries, zip->count + 1, zip_entry), "zip_entries");
  367. zip->entries[zip->count].offset = offset;
  368. zip->entries[zip->count].csize = csize;
  369. zip->entries[zip->count].usize = usize;
  370. zip->entries[zip->count].name = name;
  371. name = NULL;
  372. zip->count++;
  373. }
  374. }
  375. fz_always(ctx)
  376. fz_free(ctx, name);
  377. fz_catch(ctx)
  378. fz_rethrow(ctx);
  379. }
  380. static int read_zip_entry_header(fz_context *ctx, fz_zip_archive *zip, zip_entry *ent)
  381. {
  382. fz_stream *file = zip->super.file;
  383. uint32_t sig;
  384. int general, method, namelength, extralength;
  385. fz_seek(ctx, file, ent->offset, 0);
  386. sig = fz_read_uint32_le(ctx, file);
  387. if (sig != ZIP_LOCAL_FILE_SIG)
  388. fz_throw(ctx, FZ_ERROR_FORMAT, "wrong zip local file signature (0x%x)", sig);
  389. (void) fz_read_uint16_le(ctx, file); /* version */
  390. general = fz_read_uint16_le(ctx, file); /* general */
  391. if (general & ZIP_ENCRYPTED_FLAG)
  392. fz_throw(ctx, FZ_ERROR_FORMAT, "zip content is encrypted");
  393. method = fz_read_uint16_le(ctx, file);
  394. (void) fz_read_uint16_le(ctx, file); /* file time */
  395. (void) fz_read_uint16_le(ctx, file); /* file date */
  396. (void) fz_read_uint32_le(ctx, file); /* crc-32 */
  397. (void) fz_read_uint32_le(ctx, file); /* csize */
  398. (void) fz_read_uint32_le(ctx, file); /* usize */
  399. namelength = fz_read_uint16_le(ctx, file);
  400. extralength = fz_read_uint16_le(ctx, file);
  401. fz_seek(ctx, file, namelength + extralength, 1);
  402. return method;
  403. }
  404. static void ensure_zip_entries(fz_context *ctx, fz_zip_archive *zip)
  405. {
  406. fz_stream *file = zip->super.file;
  407. unsigned char buf[512];
  408. size_t size, back, maxback;
  409. size_t i, n;
  410. fz_seek(ctx, file, 0, SEEK_END);
  411. size = fz_tell(ctx, file);
  412. maxback = fz_minz(size, 0xFFFF + sizeof buf);
  413. back = fz_minz(maxback, sizeof buf);
  414. while (back <= maxback)
  415. {
  416. fz_seek(ctx, file, (int64_t)(size - back), 0);
  417. n = fz_read(ctx, file, buf, sizeof buf);
  418. if (n < 4)
  419. break;
  420. for (i = n - 4; i > 0; i--)
  421. if (!memcmp(buf + i, "PK\5\6", 4))
  422. {
  423. read_zip_dir_imp(ctx, zip, size - back + i);
  424. return;
  425. }
  426. back += sizeof buf - 4;
  427. }
  428. fz_throw(ctx, FZ_ERROR_FORMAT, "cannot find end of central directory");
  429. }
  430. static zip_entry *lookup_zip_entry(fz_context *ctx, fz_zip_archive *zip, const char *name)
  431. {
  432. int i;
  433. if (name[0] == '/')
  434. ++name;
  435. for (i = 0; i < zip->count; i++)
  436. if (!fz_strcasecmp(name, zip->entries[i].name))
  437. return &zip->entries[i];
  438. return NULL;
  439. }
  440. static fz_stream *open_zip_entry(fz_context *ctx, fz_archive *arch, const char *name)
  441. {
  442. fz_zip_archive *zip = (fz_zip_archive *) arch;
  443. fz_stream *file = zip->super.file;
  444. int method;
  445. zip_entry *ent;
  446. ent = lookup_zip_entry(ctx, zip, name);
  447. if (!ent)
  448. return NULL;
  449. method = read_zip_entry_header(ctx, zip, ent);
  450. if (method == 0)
  451. return fz_open_null_filter(ctx, file, ent->usize, fz_tell(ctx, file));
  452. if (method == 8)
  453. return fz_open_flated(ctx, file, -15);
  454. fz_throw(ctx, FZ_ERROR_FORMAT, "unknown zip method: %d", method);
  455. }
  456. static fz_buffer *read_zip_entry(fz_context *ctx, fz_archive *arch, const char *name)
  457. {
  458. fz_zip_archive *zip = (fz_zip_archive *) arch;
  459. fz_stream *file = zip->super.file;
  460. fz_buffer *ubuf;
  461. unsigned char *cbuf = NULL;
  462. int method;
  463. z_stream z;
  464. int code;
  465. uint64_t len;
  466. zip_entry *ent;
  467. fz_var(cbuf);
  468. ent = lookup_zip_entry(ctx, zip, name);
  469. if (!ent)
  470. return NULL;
  471. method = read_zip_entry_header(ctx, zip, ent);
  472. ubuf = fz_new_buffer(ctx, ent->usize + 1); /* +1 because many callers will add a terminating zero */
  473. if (method == 0)
  474. {
  475. fz_try(ctx)
  476. {
  477. ubuf->len = fz_read(ctx, file, ubuf->data, ent->usize);
  478. if (ubuf->len < (size_t)ent->usize)
  479. fz_warn(ctx, "premature end of data in stored zip archive entry");
  480. }
  481. fz_catch(ctx)
  482. {
  483. fz_drop_buffer(ctx, ubuf);
  484. fz_rethrow(ctx);
  485. }
  486. return ubuf;
  487. }
  488. else if (method == 8)
  489. {
  490. fz_try(ctx)
  491. {
  492. cbuf = fz_malloc(ctx, ent->csize);
  493. z.zalloc = fz_zlib_alloc;
  494. z.zfree = fz_zlib_free;
  495. z.opaque = ctx;
  496. z.next_out = ubuf->data;
  497. z.avail_out = ent->usize;
  498. z.next_in = cbuf;
  499. z.avail_in = (uInt)fz_read(ctx, file, cbuf, ent->csize);
  500. if (z.avail_in < ent->csize)
  501. fz_warn(ctx, "premature end of compressed data for compressed archive entry");
  502. code = inflateInit2(&z, -15);
  503. if (code != Z_OK)
  504. {
  505. fz_throw(ctx, FZ_ERROR_LIBRARY, "zlib inflateInit2 error: %s", z.msg);
  506. }
  507. code = inflate(&z, Z_FINISH);
  508. if (code != Z_STREAM_END)
  509. {
  510. inflateEnd(&z);
  511. fz_throw(ctx, FZ_ERROR_LIBRARY, "zlib inflate error: %s", z.msg);
  512. }
  513. code = inflateEnd(&z);
  514. if (code != Z_OK)
  515. {
  516. fz_throw(ctx, FZ_ERROR_LIBRARY, "zlib inflateEnd error: %s", z.msg);
  517. }
  518. len = ent->usize - z.avail_out;
  519. if (len < ent->usize)
  520. fz_warn(ctx, "premature end of data in compressed archive entry");
  521. ubuf->len = len;
  522. }
  523. fz_always(ctx)
  524. {
  525. fz_free(ctx, cbuf);
  526. }
  527. fz_catch(ctx)
  528. {
  529. fz_drop_buffer(ctx, ubuf);
  530. fz_rethrow(ctx);
  531. }
  532. return ubuf;
  533. }
  534. fz_drop_buffer(ctx, ubuf);
  535. fz_throw(ctx, FZ_ERROR_FORMAT, "unknown zip method: %d", method);
  536. }
  537. static int has_zip_entry(fz_context *ctx, fz_archive *arch, const char *name)
  538. {
  539. fz_zip_archive *zip = (fz_zip_archive *) arch;
  540. zip_entry *ent = lookup_zip_entry(ctx, zip, name);
  541. return ent != NULL;
  542. }
  543. static const char *list_zip_entry(fz_context *ctx, fz_archive *arch, int idx)
  544. {
  545. fz_zip_archive *zip = (fz_zip_archive *) arch;
  546. if (idx < 0 || idx >= zip->count)
  547. return NULL;
  548. return zip->entries[idx].name;
  549. }
  550. static int count_zip_entries(fz_context *ctx, fz_archive *arch)
  551. {
  552. fz_zip_archive *zip = (fz_zip_archive *) arch;
  553. return zip->count;
  554. }
  555. int
  556. fz_is_zip_archive(fz_context *ctx, fz_stream *file)
  557. {
  558. const unsigned char signature[4] = { 'P', 'K', 0x03, 0x04 };
  559. unsigned char data[4];
  560. size_t n;
  561. if (file == NULL)
  562. return 0;
  563. fz_seek(ctx, file, 0, 0);
  564. n = fz_read(ctx, file, data, nelem(data));
  565. if (n != nelem(signature))
  566. return 0;
  567. if (memcmp(data, signature, nelem(signature)))
  568. return 0;
  569. return 1;
  570. }
  571. fz_archive *
  572. fz_open_zip_archive_with_stream(fz_context *ctx, fz_stream *file)
  573. {
  574. fz_zip_archive *zip;
  575. if (!fz_is_zip_archive(ctx, file))
  576. fz_throw(ctx, FZ_ERROR_FORMAT, "cannot recognize zip archive");
  577. zip = fz_new_derived_archive(ctx, file, fz_zip_archive);
  578. zip->super.format = "zip";
  579. zip->super.count_entries = count_zip_entries;
  580. zip->super.list_entry = list_zip_entry;
  581. zip->super.has_entry = has_zip_entry;
  582. zip->super.read_entry = read_zip_entry;
  583. zip->super.open_entry = open_zip_entry;
  584. zip->super.drop_archive = drop_zip_archive;
  585. fz_try(ctx)
  586. {
  587. ensure_zip_entries(ctx, zip);
  588. }
  589. fz_catch(ctx)
  590. {
  591. fz_drop_archive(ctx, &zip->super);
  592. fz_rethrow(ctx);
  593. }
  594. return &zip->super;
  595. }
  596. fz_archive *
  597. fz_open_zip_archive(fz_context *ctx, const char *filename)
  598. {
  599. fz_archive *zip = NULL;
  600. fz_stream *file;
  601. file = fz_open_file(ctx, filename);
  602. fz_var(zip);
  603. fz_try(ctx)
  604. zip = fz_open_zip_archive_with_stream(ctx, file);
  605. fz_always(ctx)
  606. fz_drop_stream(ctx, file);
  607. fz_catch(ctx)
  608. fz_rethrow(ctx);
  609. return zip;
  610. }