unzip.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. #include "unzip.h"
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <assert.h>
  6. #include <zlib.h>
  7. /* public globals */
  8. //int gUnzipQuiet = 0; /* flag controls error messages */
  9. #define ERROR_CORRUPT "The zipfile seems to be corrupt, please check it"
  10. #define ERROR_FILESYSTEM "Your filesystem seems to be corrupt, please check it"
  11. #define ERROR_UNSUPPORTED "The format of this zipfile is not supported, please recompress it"
  12. #define INFLATE_INPUT_BUFFER_MAX 16384
  13. #ifndef MIN
  14. #define MIN(x,y) ((x)<(y)?(x):(y))
  15. #endif
  16. // notaz
  17. #if 1 //def __DEBUG_PRINT
  18. #define logerror printf
  19. #define errormsg(str1,def,fname) printf("%s: " #def ": " str1 "\n", fname);
  20. #else
  21. #define logerror(x...)
  22. #define errormsg(x...)
  23. #endif
  24. /* Print a error message */
  25. //void errormsg(const char* extmsg, const char* usermsg, const char* zipname) {
  26. /* Output to the user with no internal detail */
  27. // if (!gUnzipQuiet)
  28. // printf("Error in zipfile %s\n%s\n", zipname, usermsg);
  29. /* Output to log file with all informations */
  30. // logerror("Error in zipfile %s: %s\n", zipname, extmsg);
  31. // printf("Error in zipfile %s: %s\n", zipname, extmsg);
  32. //}
  33. /* -------------------------------------------------------------------------
  34. Unzip support
  35. ------------------------------------------------------------------------- */
  36. /* Use these to avoid structure padding and byte-ordering problems */
  37. static UINT16 read_word (char *buf) {
  38. unsigned char *ubuf = (unsigned char *) buf;
  39. return ((UINT16)ubuf[1] << 8) | (UINT16)ubuf[0];
  40. }
  41. /* Use these to avoid structure padding and byte-ordering problems */
  42. static UINT32 read_dword (char *buf) {
  43. unsigned char *ubuf = (unsigned char *) buf;
  44. return ((UINT32)ubuf[3] << 24) | ((UINT32)ubuf[2] << 16) | ((UINT32)ubuf[1] << 8) | (UINT32)ubuf[0];
  45. }
  46. /* Locate end-of-central-dir sig in buffer and return offset
  47. out:
  48. *offset offset of cent dir start in buffer
  49. return:
  50. ==0 not found
  51. !=0 found, *offset valid
  52. */
  53. static int ecd_find_sig (char *buffer, int buflen, int *offset)
  54. {
  55. static char ecdsig[] = { 'P', 'K', 0x05, 0x06 };
  56. int i;
  57. for (i=buflen-22; i>=0; i--) {
  58. if (memcmp(buffer+i, ecdsig, 4) == 0) {
  59. *offset = i;
  60. return 1;
  61. }
  62. }
  63. return 0;
  64. }
  65. /* Read ecd data in zip structure
  66. in:
  67. zip->fp, zip->length zip file
  68. out:
  69. zip->ecd, zip->ecd_length ecd data
  70. */
  71. static int ecd_read(ZIP* zip) {
  72. char* buf;
  73. int buf_length = 1024; /* initial buffer length */
  74. while (1) {
  75. int offset;
  76. if (buf_length > zip->length)
  77. buf_length = zip->length;
  78. if (fseek(zip->fp, zip->length - buf_length, SEEK_SET) != 0) {
  79. return -1;
  80. }
  81. /* allocate buffer */
  82. buf = (char*)malloc( buf_length );
  83. if (!buf) {
  84. return -1;
  85. }
  86. if (fread( buf, buf_length, 1, zip->fp ) != 1) {
  87. free(buf);
  88. return -1;
  89. }
  90. if (ecd_find_sig(buf, buf_length, &offset)) {
  91. zip->ecd_length = buf_length - offset;
  92. zip->ecd = (char*)malloc( zip->ecd_length );
  93. if (!zip->ecd) {
  94. free(buf);
  95. return -1;
  96. }
  97. memcpy(zip->ecd, buf + offset, zip->ecd_length);
  98. free(buf);
  99. return 0;
  100. }
  101. free(buf);
  102. if (buf_length < zip->length) {
  103. /* double buffer */
  104. buf_length = 2*buf_length;
  105. logerror("Retry reading of zip ecd for %d bytes\n",buf_length);
  106. } else {
  107. return -1;
  108. }
  109. }
  110. }
  111. /* offsets in end of central directory structure */
  112. #define ZIPESIG 0x00
  113. #define ZIPEDSK 0x04
  114. #define ZIPECEN 0x06
  115. #define ZIPENUM 0x08
  116. #define ZIPECENN 0x0a
  117. #define ZIPECSZ 0x0c
  118. #define ZIPEOFST 0x10
  119. #define ZIPECOML 0x14
  120. #define ZIPECOM 0x16
  121. /* offsets in central directory entry structure */
  122. #define ZIPCENSIG 0x0
  123. #define ZIPCVER 0x4
  124. #define ZIPCOS 0x5
  125. #define ZIPCVXT 0x6
  126. #define ZIPCEXOS 0x7
  127. #define ZIPCFLG 0x8
  128. #define ZIPCMTHD 0xa
  129. #define ZIPCTIM 0xc
  130. #define ZIPCDAT 0xe
  131. #define ZIPCCRC 0x10
  132. #define ZIPCSIZ 0x14
  133. #define ZIPCUNC 0x18
  134. #define ZIPCFNL 0x1c
  135. #define ZIPCXTL 0x1e
  136. #define ZIPCCML 0x20
  137. #define ZIPDSK 0x22
  138. #define ZIPINT 0x24
  139. #define ZIPEXT 0x26
  140. #define ZIPOFST 0x2a
  141. #define ZIPCFN 0x2e
  142. /* offsets in local file header structure */
  143. #define ZIPLOCSIG 0x00
  144. #define ZIPVER 0x04
  145. #define ZIPGENFLG 0x06
  146. #define ZIPMTHD 0x08
  147. #define ZIPTIME 0x0a
  148. #define ZIPDATE 0x0c
  149. #define ZIPCRC 0x0e
  150. #define ZIPSIZE 0x12
  151. #define ZIPUNCMP 0x16
  152. #define ZIPFNLN 0x1a
  153. #define ZIPXTRALN 0x1c
  154. #define ZIPNAME 0x1e
  155. /* Opens a zip stream for reading
  156. return:
  157. !=0 success, zip stream
  158. ==0 error
  159. */
  160. ZIP* openzip(const char* zipfile) {
  161. /* allocate */
  162. ZIP* zip = (ZIP*)malloc( sizeof(ZIP) );
  163. if (!zip) {
  164. return 0;
  165. }
  166. /* open */
  167. zip->fp = fopen(zipfile, "rb");
  168. if (!zip->fp) {
  169. errormsg ("Opening for reading", ERROR_FILESYSTEM, zipfile);
  170. free(zip);
  171. return 0;
  172. }
  173. /* go to end */
  174. if (fseek(zip->fp, 0L, SEEK_END) != 0) {
  175. errormsg ("Seeking to end", ERROR_FILESYSTEM, zipfile);
  176. fclose(zip->fp);
  177. free(zip);
  178. return 0;
  179. }
  180. /* get length */
  181. zip->length = ftell(zip->fp);
  182. if (zip->length < 0) {
  183. errormsg ("Get file size", ERROR_FILESYSTEM, zipfile);
  184. fclose(zip->fp);
  185. free(zip);
  186. return 0;
  187. }
  188. if (zip->length == 0) {
  189. errormsg ("Empty file", ERROR_CORRUPT, zipfile);
  190. fclose(zip->fp);
  191. free(zip);
  192. return 0;
  193. }
  194. /* read ecd data */
  195. if (ecd_read(zip)!=0) {
  196. errormsg ("Reading ECD (end of central directory)", ERROR_CORRUPT, zipfile);
  197. fclose(zip->fp);
  198. free(zip);
  199. return 0;
  200. }
  201. /* compile ecd info */
  202. zip->end_of_cent_dir_sig = read_dword (zip->ecd+ZIPESIG);
  203. zip->number_of_this_disk = read_word (zip->ecd+ZIPEDSK);
  204. zip->number_of_disk_start_cent_dir = read_word (zip->ecd+ZIPECEN);
  205. zip->total_entries_cent_dir_this_disk = read_word (zip->ecd+ZIPENUM);
  206. zip->total_entries_cent_dir = read_word (zip->ecd+ZIPECENN);
  207. zip->size_of_cent_dir = read_dword (zip->ecd+ZIPECSZ);
  208. zip->offset_to_start_of_cent_dir = read_dword (zip->ecd+ZIPEOFST);
  209. zip->zipfile_comment_length = read_word (zip->ecd+ZIPECOML);
  210. zip->zipfile_comment = zip->ecd+ZIPECOM;
  211. /* verify that we can work with this zipfile (no disk spanning allowed) */
  212. if ((zip->number_of_this_disk != zip->number_of_disk_start_cent_dir) ||
  213. (zip->total_entries_cent_dir_this_disk != zip->total_entries_cent_dir) ||
  214. (zip->total_entries_cent_dir < 1)) {
  215. errormsg("Cannot span disks", ERROR_UNSUPPORTED, zipfile);
  216. free(zip->ecd);
  217. fclose(zip->fp);
  218. free(zip);
  219. return 0;
  220. }
  221. if (fseek(zip->fp, zip->offset_to_start_of_cent_dir, SEEK_SET)!=0) {
  222. errormsg ("Seeking to central directory", ERROR_CORRUPT, zipfile);
  223. free(zip->ecd);
  224. fclose(zip->fp);
  225. free(zip);
  226. return 0;
  227. }
  228. /* read from start of central directory */
  229. zip->cd = (char*)malloc( zip->size_of_cent_dir );
  230. if (!zip->cd) {
  231. free(zip->ecd);
  232. fclose(zip->fp);
  233. free(zip);
  234. return 0;
  235. }
  236. if (fread(zip->cd, zip->size_of_cent_dir, 1, zip->fp)!=1) {
  237. errormsg ("Reading central directory", ERROR_CORRUPT, zipfile);
  238. free(zip->cd);
  239. free(zip->ecd);
  240. fclose(zip->fp);
  241. free(zip);
  242. return 0;
  243. }
  244. /* reset ent */
  245. zip->ent.name = 0;
  246. /* rewind */
  247. zip->cd_pos = 0;
  248. /* file name */
  249. zip->zip = (char*)malloc(strlen(zipfile)+1);
  250. if (!zip->zip) {
  251. free(zip->cd);
  252. free(zip->ecd);
  253. fclose(zip->fp);
  254. free(zip);
  255. return 0;
  256. }
  257. strcpy(zip->zip, zipfile);
  258. return zip;
  259. }
  260. /* Reads the current entry from a zip stream
  261. in:
  262. zip opened zip
  263. return:
  264. !=0 success
  265. ==0 error
  266. */
  267. struct zipent* readzip(ZIP* zip) {
  268. /* end of directory */
  269. if (zip->cd_pos >= zip->size_of_cent_dir)
  270. return 0;
  271. /* compile zipent info */
  272. zip->ent.cent_file_header_sig = read_dword (zip->cd+zip->cd_pos+ZIPCENSIG);
  273. zip->ent.version_made_by = *(zip->cd+zip->cd_pos+ZIPCVER);
  274. zip->ent.host_os = *(zip->cd+zip->cd_pos+ZIPCOS);
  275. zip->ent.version_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCVXT);
  276. zip->ent.os_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCEXOS);
  277. zip->ent.general_purpose_bit_flag = read_word (zip->cd+zip->cd_pos+ZIPCFLG);
  278. zip->ent.compression_method = read_word (zip->cd+zip->cd_pos+ZIPCMTHD);
  279. zip->ent.last_mod_file_time = read_word (zip->cd+zip->cd_pos+ZIPCTIM);
  280. zip->ent.last_mod_file_date = read_word (zip->cd+zip->cd_pos+ZIPCDAT);
  281. zip->ent.crc32 = read_dword (zip->cd+zip->cd_pos+ZIPCCRC);
  282. zip->ent.compressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCSIZ);
  283. zip->ent.uncompressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCUNC);
  284. zip->ent.filename_length = read_word (zip->cd+zip->cd_pos+ZIPCFNL);
  285. zip->ent.extra_field_length = read_word (zip->cd+zip->cd_pos+ZIPCXTL);
  286. zip->ent.file_comment_length = read_word (zip->cd+zip->cd_pos+ZIPCCML);
  287. zip->ent.disk_number_start = read_word (zip->cd+zip->cd_pos+ZIPDSK);
  288. zip->ent.internal_file_attrib = read_word (zip->cd+zip->cd_pos+ZIPINT);
  289. zip->ent.external_file_attrib = read_dword (zip->cd+zip->cd_pos+ZIPEXT);
  290. zip->ent.offset_lcl_hdr_frm_frst_disk = read_dword (zip->cd+zip->cd_pos+ZIPOFST);
  291. /* check to see if filename length is illegally long (past the size of this directory
  292. entry) */
  293. if (zip->cd_pos + ZIPCFN + zip->ent.filename_length > zip->size_of_cent_dir)
  294. {
  295. errormsg("Invalid filename length in directory", ERROR_CORRUPT,zip->zip);
  296. return 0;
  297. }
  298. /* copy filename */
  299. free(zip->ent.name);
  300. zip->ent.name = (char*)malloc(zip->ent.filename_length + 1);
  301. memcpy(zip->ent.name, zip->cd+zip->cd_pos+ZIPCFN, zip->ent.filename_length);
  302. zip->ent.name[zip->ent.filename_length] = 0;
  303. /* skip to next entry in central dir */
  304. zip->cd_pos += ZIPCFN + zip->ent.filename_length + zip->ent.extra_field_length + zip->ent.file_comment_length;
  305. return &zip->ent;
  306. }
  307. /* Closes a zip stream */
  308. void closezip(ZIP* zip) {
  309. /* release all */
  310. free(zip->ent.name);
  311. free(zip->cd);
  312. free(zip->ecd);
  313. /* only if not suspended */
  314. if (zip->fp)
  315. fclose(zip->fp);
  316. free(zip->zip);
  317. free(zip);
  318. }
  319. /* Suspend access to a zip file (release file handler)
  320. in:
  321. zip opened zip
  322. note:
  323. A suspended zip is automatically reopened at first call of
  324. readuncompressd() or readcompressed() functions
  325. */
  326. void suspendzip(ZIP* zip) {
  327. if (zip->fp) {
  328. fclose(zip->fp);
  329. zip->fp = 0;
  330. }
  331. }
  332. /* Revive a suspended zip file (reopen file handler)
  333. in:
  334. zip suspended zip
  335. return:
  336. zip success
  337. ==0 error (zip must be closed with closezip)
  338. */
  339. static ZIP* revivezip(ZIP* zip) {
  340. if (!zip->fp) {
  341. zip->fp = fopen(zip->zip, "rb");
  342. if (!zip->fp) {
  343. return 0;
  344. }
  345. }
  346. return zip;
  347. }
  348. /* Reset a zip stream to the first entry
  349. in:
  350. zip opened zip
  351. note:
  352. ZIP file must be opened and not suspended
  353. */
  354. void rewindzip(ZIP* zip) {
  355. zip->cd_pos = 0;
  356. }
  357. /* Seek zip->fp to compressed data
  358. return:
  359. ==0 success
  360. <0 error
  361. */
  362. int seekcompresszip(ZIP* zip, struct zipent* ent) {
  363. char buf[ZIPNAME];
  364. long offset;
  365. if (!zip->fp) {
  366. if (!revivezip(zip))
  367. return -1;
  368. }
  369. if (fseek(zip->fp, ent->offset_lcl_hdr_frm_frst_disk, SEEK_SET)!=0) {
  370. errormsg ("Seeking to header", ERROR_CORRUPT, zip->zip);
  371. return -1;
  372. }
  373. if (fread(buf, ZIPNAME, 1, zip->fp)!=1) {
  374. errormsg ("Reading header", ERROR_CORRUPT, zip->zip);
  375. return -1;
  376. }
  377. {
  378. UINT16 filename_length = read_word (buf+ZIPFNLN);
  379. UINT16 extra_field_length = read_word (buf+ZIPXTRALN);
  380. /* calculate offset to data and fseek() there */
  381. offset = ent->offset_lcl_hdr_frm_frst_disk + ZIPNAME + filename_length + extra_field_length;
  382. if (fseek(zip->fp, offset, SEEK_SET) != 0) {
  383. errormsg ("Seeking to compressed data", ERROR_CORRUPT, zip->zip);
  384. return -1;
  385. }
  386. }
  387. return 0;
  388. }
  389. /* Inflate a file
  390. in:
  391. in_file stream to inflate
  392. in_size size of the compressed data to read
  393. out_size size of decompressed data
  394. out:
  395. out_data buffer for decompressed data
  396. return:
  397. ==0 ok
  398. 990525 rewritten for use with zlib MLR
  399. */
  400. static int inflate_file(FILE* in_file, unsigned in_size, unsigned char* out_data, unsigned out_size)
  401. {
  402. int err;
  403. unsigned char* in_buffer;
  404. z_stream d_stream; /* decompression stream */
  405. d_stream.zalloc = 0;
  406. d_stream.zfree = 0;
  407. d_stream.opaque = 0;
  408. d_stream.next_in = 0;
  409. d_stream.avail_in = 0;
  410. d_stream.next_out = out_data;
  411. d_stream.avail_out = out_size;
  412. err = inflateInit2(&d_stream, -MAX_WBITS);
  413. /* windowBits is passed < 0 to tell that there is no zlib header.
  414. * Note that in this case inflate *requires* an extra "dummy" byte
  415. * after the compressed stream in order to complete decompression and
  416. * return Z_STREAM_END.
  417. */
  418. if (err != Z_OK)
  419. {
  420. logerror("inflateInit error: %d\n", err);
  421. return -1;
  422. }
  423. in_buffer = (unsigned char*)malloc(INFLATE_INPUT_BUFFER_MAX+1);
  424. if (!in_buffer)
  425. return -1;
  426. for (;;)
  427. {
  428. if (in_size <= 0)
  429. {
  430. logerror("inflate error: compressed size too small\n");
  431. free (in_buffer);
  432. return -1;
  433. }
  434. d_stream.next_in = in_buffer;
  435. d_stream.avail_in = fread (in_buffer, 1, MIN(in_size, INFLATE_INPUT_BUFFER_MAX), in_file);
  436. in_size -= d_stream.avail_in;
  437. if (in_size == 0)
  438. d_stream.avail_in++; /* add dummy byte at end of compressed data */
  439. err = inflate(&d_stream, Z_NO_FLUSH);
  440. if (err == Z_STREAM_END)
  441. break;
  442. if (err != Z_OK)
  443. {
  444. logerror("inflate error: %d\n", err);
  445. free (in_buffer);
  446. return -1;
  447. }
  448. }
  449. err = inflateEnd(&d_stream);
  450. if (err != Z_OK)
  451. {
  452. logerror("inflateEnd error: %d\n", err);
  453. free (in_buffer);
  454. return -1;
  455. }
  456. free (in_buffer);
  457. if ((d_stream.avail_out > 0) || (in_size > 0))
  458. {
  459. logerror("zip size mismatch. %i\n", in_size);
  460. return -1;
  461. }
  462. return 0;
  463. }
  464. /* Read compressed data
  465. out:
  466. data compressed data read
  467. return:
  468. ==0 success
  469. <0 error
  470. */
  471. int readcompresszip(ZIP* zip, struct zipent* ent, char* data) {
  472. int err = seekcompresszip(zip,ent);
  473. if (err!=0)
  474. return err;
  475. if (fread(data, ent->compressed_size, 1, zip->fp)!=1) {
  476. errormsg ("Reading compressed data", ERROR_CORRUPT, zip->zip);
  477. return -1;
  478. }
  479. return 0;
  480. }
  481. /* Read UNcompressed data
  482. out:
  483. data UNcompressed data
  484. return:
  485. ==0 success
  486. <0 error
  487. */
  488. int readuncompresszip(ZIP* zip, struct zipent* ent, char* data) {
  489. if (ent->compression_method == 0x0000) {
  490. /* file is not compressed, simply stored */
  491. /* check if size are equal */
  492. if (ent->compressed_size != ent->uncompressed_size) {
  493. errormsg("Wrong uncompressed size in store compression", ERROR_CORRUPT,zip->zip);
  494. return -3;
  495. }
  496. return readcompresszip(zip,ent,data);
  497. } else if (ent->compression_method == 0x0008) {
  498. /* file is compressed using "Deflate" method */
  499. if (ent->version_needed_to_extract > 0x14) {
  500. errormsg("Version too new", ERROR_UNSUPPORTED,zip->zip);
  501. return -2;
  502. }
  503. if (ent->os_needed_to_extract != 0x00) {
  504. errormsg("OS not supported", ERROR_UNSUPPORTED,zip->zip);
  505. return -2;
  506. }
  507. if (ent->disk_number_start != zip->number_of_this_disk) {
  508. errormsg("Cannot span disks", ERROR_UNSUPPORTED,zip->zip);
  509. return -2;
  510. }
  511. /* read compressed data */
  512. if (seekcompresszip(zip,ent)!=0) {
  513. return -1;
  514. }
  515. /* configure inflate */
  516. if (inflate_file( zip->fp, ent->compressed_size, (unsigned char*)data, ent->uncompressed_size))
  517. {
  518. errormsg("Inflating compressed data", ERROR_CORRUPT, zip->zip);
  519. return -3;
  520. }
  521. return 0;
  522. } else {
  523. errormsg("Compression method unsupported", ERROR_UNSUPPORTED, zip->zip);
  524. return -2;
  525. }
  526. }