libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
Loading...
Searching...
No Matches
zip.c
1/*
2 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
5 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
6 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
7 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
8 * OTHER DEALINGS IN THE SOFTWARE.
9 */
10#define __STDC_WANT_LIB_EXT1__ 1
11
12#include <errno.h>
13#include <sys/stat.h>
14#include <time.h>
15
16#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
17 defined(__MINGW32__)
18/* Win32, DOS, MSVC, MSVS */
19#include <direct.h>
20
21#define HAS_DEVICE(P) \
22 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \
23 (P)[1] == ':')
24#define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0)
25
26#else
27
28#include <unistd.h> // needed for symlink()
29
30#endif
31
32#ifdef __MINGW32__
33#include <sys/types.h>
34#include <unistd.h>
35#endif
36
37#include "miniz.h"
38#include "zip.h"
39
40#ifdef _MSC_VER
41#include <io.h>
42
43#define ftruncate(fd, sz) (-(_chsize_s((fd), (sz)) != 0))
44#define fileno _fileno
45#endif
46
47#if defined(__TINYC__) && (defined(_WIN32) || defined(_WIN64))
48#include <io.h>
49
50#define ftruncate(fd, sz) (-(_chsize_s((fd), (sz)) != 0))
51#define fileno _fileno
52#endif
53
54#ifndef HAS_DEVICE
55#define HAS_DEVICE(P) 0
56#endif
57
58#ifndef FILESYSTEM_PREFIX_LEN
59#define FILESYSTEM_PREFIX_LEN(P) 0
60#endif
61
62#ifndef ISSLASH
63#define ISSLASH(C) ((C) == '/' || (C) == '\\')
64#endif
65
66#define CLEANUP(ptr) \
67 do { \
68 if (ptr) { \
69 free((void *)ptr); \
70 ptr = NULL; \
71 } \
72 } while (0)
73
74#define UNX_IFDIR 0040000 /* Unix directory */
75#define UNX_IFREG 0100000 /* Unix regular file */
76#define UNX_IFSOCK 0140000 /* Unix socket (BSD, not SysV or Amiga) */
77#define UNX_IFLNK 0120000 /* Unix symbolic link (not SysV, Amiga) */
78#define UNX_IFBLK 0060000 /* Unix block special (not Amiga) */
79#define UNX_IFCHR 0020000 /* Unix character special (not Amiga) */
80#define UNX_IFIFO 0010000 /* Unix fifo (BCC, not MSC or Amiga) */
81
83 ssize_t index;
84 char *name;
85 mz_uint64 uncomp_size;
86 mz_uint64 comp_size;
87 mz_uint32 uncomp_crc32;
88 mz_uint64 dir_offset;
89 mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
90 mz_uint64 header_offset;
91 mz_uint16 method;
94 mz_uint32 external_attr;
95 time_t m_time;
96};
97
98struct zip_t {
99 mz_zip_archive archive;
100 mz_uint level;
101 struct zip_entry_t entry;
102};
103
104enum zip_modify_t {
105 MZ_KEEP = 0,
106 MZ_DELETE = 1,
107 MZ_MOVE = 2,
108};
109
111 ssize_t file_index;
112 enum zip_modify_t type;
113 mz_uint64 m_local_header_ofs;
114 size_t lf_length;
115};
116
117static const char *const zip_errlist[33] = {
118 NULL,
119 "not initialized\0",
120 "invalid entry name\0",
121 "entry not found\0",
122 "invalid zip mode\0",
123 "invalid compression level\0",
124 "no zip 64 support\0",
125 "memset error\0",
126 "cannot write data to entry\0",
127 "cannot initialize tdefl compressor\0",
128 "invalid index\0",
129 "header not found\0",
130 "cannot flush tdefl buffer\0",
131 "cannot write entry header\0",
132 "cannot create entry header\0",
133 "cannot write to central dir\0",
134 "cannot open file\0",
135 "invalid entry type\0",
136 "extracting data using no memory allocation\0",
137 "file not found\0",
138 "no permission\0",
139 "out of memory\0",
140 "invalid zip archive name\0",
141 "make dir error\0",
142 "symlink error\0",
143 "close archive error\0",
144 "capacity size too small\0",
145 "fseek error\0",
146 "fread error\0",
147 "fwrite error\0",
148 "cannot initialize reader\0",
149 "cannot initialize writer\0",
150 "cannot initialize writer from reader\0",
151};
152
153const char *zip_strerror(int errnum) {
154 errnum = -errnum;
155 if (errnum <= 0 || errnum >= 33) {
156 return NULL;
157 }
158
159 return zip_errlist[errnum];
160}
161
162static const char *zip_basename(const char *name) {
163 char const *p;
164 char const *base = name += FILESYSTEM_PREFIX_LEN(name);
165 int all_slashes = 1;
166
167 for (p = name; *p; p++) {
168 if (ISSLASH(*p))
169 base = p + 1;
170 else
171 all_slashes = 0;
172 }
173
174 /* If NAME is all slashes, arrange to return `/'. */
175 if (*base == '\0' && ISSLASH(*name) && all_slashes)
176 --base;
177
178 return base;
179}
180
181static int zip_mkpath(char *path) {
182 char *p;
183 char npath[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE + 1];
184 int len = 0;
185 int has_device = HAS_DEVICE(path);
186
187 memset(npath, 0, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE + 1);
188 if (has_device) {
189 // only on windows
190 npath[0] = path[0];
191 npath[1] = path[1];
192 len = 2;
193 }
194 for (p = path + len; *p && len < MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE; p++) {
195 if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) {
196#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
197 defined(__MINGW32__)
198#else
199 if ('\\' == *p) {
200 *p = '/';
201 }
202#endif
203
204 if (MZ_MKDIR(npath) == -1) {
205 if (errno != EEXIST) {
206 return ZIP_EMKDIR;
207 }
208 }
209 }
210 npath[len++] = *p;
211 }
212
213 return 0;
214}
215
216static char *zip_strclone(const char *str, size_t n) {
217 char c;
218 size_t i;
219 char *rpl = (char *)calloc((1 + n), sizeof(char));
220 char *begin = rpl;
221 if (!rpl) {
222 return NULL;
223 }
224
225 for (i = 0; (i < n) && (c = *str++); ++i) {
226 *rpl++ = c;
227 }
228
229 return begin;
230}
231
232static char *zip_strrpl(const char *str, size_t n, char oldchar, char newchar) {
233 char c;
234 size_t i;
235 char *rpl = (char *)calloc((1 + n), sizeof(char));
236 char *begin = rpl;
237 if (!rpl) {
238 return NULL;
239 }
240
241 for (i = 0; (i < n) && (c = *str++); ++i) {
242 if (c == oldchar) {
243 c = newchar;
244 }
245 *rpl++ = c;
246 }
247
248 return begin;
249}
250
251static inline int zip_strchr_match(const char *const str, size_t len, char c) {
252 size_t i;
253 for (i = 0; i < len; ++i) {
254 if (str[i] != c) {
255 return 0;
256 }
257 }
258
259 return 1;
260}
261
262static char *zip_name_normalize(char *name, char *const nname, size_t len) {
263 size_t offn = 0, ncpy = 0;
264 char c;
265
266 if (name == NULL || nname == NULL || len <= 0) {
267 return NULL;
268 }
269 // skip trailing '/'
270 while (ISSLASH(*name)) {
271 name++;
272 }
273
274 while ((c = *name++)) {
275 if (ISSLASH(c)) {
276 if (ncpy > 0 && !zip_strchr_match(&nname[offn], ncpy, '.')) {
277 offn += ncpy;
278 nname[offn++] = c; // append '/'
279 }
280 ncpy = 0;
281 } else {
282 nname[offn + ncpy] = c;
283 if (c) {
284 ncpy++;
285 }
286 }
287 }
288
289 if (!zip_strchr_match(&nname[offn], ncpy, '.')) {
290 nname[offn + ncpy] = '\0';
291 } else {
292 nname[offn] = '\0';
293 }
294
295 return nname;
296}
297
298static int zip_archive_truncate(mz_zip_archive *pzip) {
299 mz_zip_internal_state *pState = pzip->m_pState;
300 mz_uint64 file_size = pzip->m_archive_size;
301 if ((pzip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) {
302 return 0;
303 }
304 if (pzip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED) {
305 if (pState->m_pFile) {
306 int fd = fileno(pState->m_pFile);
307 return ftruncate(fd, pState->m_file_archive_start_ofs + file_size);
308 }
309 }
310 return 0;
311}
312
313static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir,
314 int (*on_extract)(const char *filename,
315 void *arg),
316 void *arg) {
317 int err = 0;
318 mz_uint i, n;
319 char path[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE + 1];
320 char symlink_to[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE + 1];
322 size_t dirlen = 0, filename_size = MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE;
323 mz_uint32 xattr = 0;
324
325 memset(path, 0, sizeof(path));
326 memset(symlink_to, 0, sizeof(symlink_to));
327
328 dirlen = strlen(dir);
329 if (dirlen + 1 > MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE) {
330 return ZIP_EINVENTNAME;
331 }
332
333 memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat));
334
335#if defined(_MSC_VER)
336 strcpy_s(path, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE, dir);
337#else
338 strncpy(path, dir, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE);
339#endif
340
341 if (!ISSLASH(path[dirlen - 1])) {
342#if defined(_WIN32) || defined(__WIN32__)
343 path[dirlen] = '\\';
344#else
345 path[dirlen] = '/';
346#endif
347 ++dirlen;
348 }
349
350 if (filename_size > MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - dirlen) {
351 filename_size = MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - dirlen;
352 }
353 // Get and print information about each file in the archive.
354 n = mz_zip_reader_get_num_files(zip_archive);
355 for (i = 0; i < n; ++i) {
356 if (!mz_zip_reader_file_stat(zip_archive, i, &info)) {
357 // Cannot get information about zip archive;
358 err = ZIP_ENOENT;
359 goto out;
360 }
361
362 if (!zip_name_normalize(info.m_filename, info.m_filename,
363 strlen(info.m_filename))) {
364 // Cannot normalize file name;
365 err = ZIP_EINVENTNAME;
366 goto out;
367 }
368
369#if defined(_MSC_VER)
370 strncpy_s(&path[dirlen], filename_size, info.m_filename, filename_size);
371#else
372 strncpy(&path[dirlen], info.m_filename, filename_size);
373#endif
374 err = zip_mkpath(path);
375 if (err < 0) {
376 // Cannot make a path
377 goto out;
378 }
379
380 if ((((info.m_version_made_by >> 8) == 3) ||
381 ((info.m_version_made_by >> 8) ==
382 19)) // if zip is produced on Unix or macOS (3 and 19 from
383 // section 4.4.2.2 of zip standard)
384 && info.m_external_attr &
385 (0x20 << 24)) { // and has sym link attribute (0x80 is file,
386 // 0x40 is directory)
387#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
388 defined(__MINGW32__)
389#else
390 if (info.m_uncomp_size > MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE ||
391 !mz_zip_reader_extract_to_mem_no_alloc(
392 zip_archive, i, symlink_to, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE, 0,
393 NULL, 0)) {
394 err = ZIP_EMEMNOALLOC;
395 goto out;
396 }
397 symlink_to[info.m_uncomp_size] = '\0';
398 if (symlink(symlink_to, path) != 0) {
399 err = ZIP_ESYMLINK;
400 goto out;
401 }
402#endif
403 } else {
404 if (!mz_zip_reader_is_file_a_directory(zip_archive, i)) {
405 if (!mz_zip_reader_extract_to_file(zip_archive, i, path, 0)) {
406 // Cannot extract zip archive to file
407 err = ZIP_ENOFILE;
408 goto out;
409 }
410 }
411
412#if defined(_MSC_VER) || defined(PS4)
413 (void)xattr; // unused
414#else
415 xattr = (info.m_external_attr >> 16) & 0xFFFF;
416 if (xattr > 0 && xattr <= MZ_UINT16_MAX) {
417 if (CHMOD(path, (mode_t)xattr) < 0) {
418 err = ZIP_ENOPERM;
419 goto out;
420 }
421 }
422#endif
423 }
424
425 if (on_extract) {
426 if (on_extract(path, arg) < 0) {
427 goto out;
428 }
429 }
430 }
431
432out:
433 // Close the archive, freeing any resources it was using
434 if (!mz_zip_reader_end(zip_archive)) {
435 // Cannot end zip reader
436 err = ZIP_ECLSZIP;
437 }
438 return err;
439}
440
441static inline void zip_archive_finalize(mz_zip_archive *pzip) {
442 mz_zip_writer_finalize_archive(pzip);
443 zip_archive_truncate(pzip);
444}
445
446static ssize_t zip_entry_mark(struct zip_t *zip,
447 struct zip_entry_mark_t *entry_mark,
448 const ssize_t n, char *const entries[],
449 const size_t len) {
450 ssize_t i = 0;
451 ssize_t err = 0;
452 if (!zip || !entry_mark || !entries) {
453 return ZIP_ENOINIT;
454 }
455
456 mz_zip_archive_file_stat file_stat;
457 mz_uint64 d_pos = UINT64_MAX;
458 for (i = 0; i < n; ++i) {
459 if ((err = zip_entry_openbyindex(zip, i))) {
460 return (ssize_t)err;
461 }
462
463 mz_bool name_matches = MZ_FALSE;
464 {
465 size_t j;
466 for (j = 0; j < len; ++j) {
467 if (strcmp(zip->entry.name, entries[j]) == 0) {
468 name_matches = MZ_TRUE;
469 break;
470 }
471 }
472 }
473 if (name_matches) {
474 entry_mark[i].type = MZ_DELETE;
475 } else {
476 entry_mark[i].type = MZ_KEEP;
477 }
478
479 if (!mz_zip_reader_file_stat(&zip->archive, i, &file_stat)) {
480 return ZIP_ENOENT;
481 }
482
483 zip_entry_close(zip);
484
485 entry_mark[i].m_local_header_ofs = file_stat.m_local_header_ofs;
486 entry_mark[i].file_index = (ssize_t)-1;
487 entry_mark[i].lf_length = 0;
488 if ((entry_mark[i].type) == MZ_DELETE &&
489 (d_pos > entry_mark[i].m_local_header_ofs)) {
490 d_pos = entry_mark[i].m_local_header_ofs;
491 }
492 }
493
494 for (i = 0; i < n; ++i) {
495 if ((entry_mark[i].m_local_header_ofs > d_pos) &&
496 (entry_mark[i].type != MZ_DELETE)) {
497 entry_mark[i].type = MZ_MOVE;
498 }
499 }
500 return err;
501}
502
503static ssize_t zip_entry_markbyindex(struct zip_t *zip,
504 struct zip_entry_mark_t *entry_mark,
505 const ssize_t n, size_t entries[],
506 const size_t len) {
507 ssize_t i = 0;
508 ssize_t err = 0;
509 if (!zip || !entry_mark || !entries) {
510 return ZIP_ENOINIT;
511 }
512
513 mz_zip_archive_file_stat file_stat;
514 mz_uint64 d_pos = UINT64_MAX;
515 for (i = 0; i < n; ++i) {
516 if ((err = zip_entry_openbyindex(zip, i))) {
517 return (ssize_t)err;
518 }
519
520 mz_bool matches = MZ_FALSE;
521 {
522 size_t j;
523 for (j = 0; j < len; ++j) {
524 if ((size_t)i == entries[j]) {
525 matches = MZ_TRUE;
526 break;
527 }
528 }
529 }
530 if (matches) {
531 entry_mark[i].type = MZ_DELETE;
532 } else {
533 entry_mark[i].type = MZ_KEEP;
534 }
535
536 if (!mz_zip_reader_file_stat(&zip->archive, i, &file_stat)) {
537 return ZIP_ENOENT;
538 }
539
540 zip_entry_close(zip);
541
542 entry_mark[i].m_local_header_ofs = file_stat.m_local_header_ofs;
543 entry_mark[i].file_index = (ssize_t)-1;
544 entry_mark[i].lf_length = 0;
545 if ((entry_mark[i].type) == MZ_DELETE &&
546 (d_pos > entry_mark[i].m_local_header_ofs)) {
547 d_pos = entry_mark[i].m_local_header_ofs;
548 }
549 }
550
551 for (i = 0; i < n; ++i) {
552 if ((entry_mark[i].m_local_header_ofs > d_pos) &&
553 (entry_mark[i].type != MZ_DELETE)) {
554 entry_mark[i].type = MZ_MOVE;
555 }
556 }
557 return err;
558}
559static ssize_t zip_index_next(mz_uint64 *local_header_ofs_array,
560 ssize_t cur_index) {
561 ssize_t new_index = 0, i;
562 for (i = cur_index - 1; i >= 0; --i) {
563 if (local_header_ofs_array[cur_index] > local_header_ofs_array[i]) {
564 new_index = i + 1;
565 return new_index;
566 }
567 }
568 return new_index;
569}
570
571static ssize_t zip_sort(mz_uint64 *local_header_ofs_array, ssize_t cur_index) {
572 ssize_t nxt_index = zip_index_next(local_header_ofs_array, cur_index);
573
574 if (nxt_index != cur_index) {
575 mz_uint64 temp = local_header_ofs_array[cur_index];
576 ssize_t i;
577 for (i = cur_index; i > nxt_index; i--) {
578 local_header_ofs_array[i] = local_header_ofs_array[i - 1];
579 }
580 local_header_ofs_array[nxt_index] = temp;
581 }
582 return nxt_index;
583}
584
585static int zip_index_update(struct zip_entry_mark_t *entry_mark,
586 ssize_t last_index, ssize_t nxt_index) {
587 ssize_t j;
588 for (j = 0; j < last_index; j++) {
589 if (entry_mark[j].file_index >= nxt_index) {
590 entry_mark[j].file_index += 1;
591 }
592 }
593 entry_mark[nxt_index].file_index = last_index;
594 return 0;
595}
596
597static int zip_entry_finalize(struct zip_t *zip,
598 struct zip_entry_mark_t *entry_mark,
599 const ssize_t n) {
600 ssize_t i = 0;
601 mz_uint64 *local_header_ofs_array = (mz_uint64 *)calloc(n, sizeof(mz_uint64));
602 if (!local_header_ofs_array) {
603 return ZIP_EOOMEM;
604 }
605
606 for (i = 0; i < n; ++i) {
607 local_header_ofs_array[i] = entry_mark[i].m_local_header_ofs;
608 ssize_t index = zip_sort(local_header_ofs_array, i);
609
610 if (index != i) {
611 zip_index_update(entry_mark, i, index);
612 }
613 entry_mark[i].file_index = index;
614 }
615
616 size_t *length = (size_t *)calloc(n, sizeof(size_t));
617 if (!length) {
618 CLEANUP(local_header_ofs_array);
619 return ZIP_EOOMEM;
620 }
621 for (i = 0; i < n - 1; i++) {
622 length[i] =
623 (size_t)(local_header_ofs_array[i + 1] - local_header_ofs_array[i]);
624 }
625 length[n - 1] =
626 (size_t)(zip->archive.m_archive_size - local_header_ofs_array[n - 1]);
627
628 for (i = 0; i < n; i++) {
629 entry_mark[i].lf_length = length[entry_mark[i].file_index];
630 }
631
632 CLEANUP(length);
633 CLEANUP(local_header_ofs_array);
634 return 0;
635}
636
637static ssize_t zip_entry_set(struct zip_t *zip,
638 struct zip_entry_mark_t *entry_mark, ssize_t n,
639 char *const entries[], const size_t len) {
640 ssize_t err = 0;
641
642 if ((err = zip_entry_mark(zip, entry_mark, n, entries, len)) < 0) {
643 return err;
644 }
645 if ((err = zip_entry_finalize(zip, entry_mark, n)) < 0) {
646 return err;
647 }
648 return 0;
649}
650
651static ssize_t zip_entry_setbyindex(struct zip_t *zip,
652 struct zip_entry_mark_t *entry_mark,
653 ssize_t n, size_t entries[],
654 const size_t len) {
655 ssize_t err = 0;
656
657 if ((err = zip_entry_markbyindex(zip, entry_mark, n, entries, len)) < 0) {
658 return err;
659 }
660 if ((err = zip_entry_finalize(zip, entry_mark, n)) < 0) {
661 return err;
662 }
663 return 0;
664}
665
666static ssize_t zip_mem_move(void *pBuf, size_t bufSize, const mz_uint64 to,
667 const mz_uint64 from, const size_t length) {
668 uint8_t *dst = NULL, *src = NULL, *end = NULL;
669
670 if (!pBuf) {
671 return ZIP_EINVIDX;
672 }
673
674 end = (uint8_t *)pBuf + bufSize;
675
676 if (to > bufSize) {
677 return ZIP_EINVIDX;
678 }
679
680 if (from > bufSize) {
681 return ZIP_EINVIDX;
682 }
683
684 dst = (uint8_t *)pBuf + to;
685 src = (uint8_t *)pBuf + from;
686
687 if (((dst + length) > end) || ((src + length) > end)) {
688 return ZIP_EINVIDX;
689 }
690
691 memmove(dst, src, length);
692 return length;
693}
694
695static ssize_t zip_file_move(MZ_FILE *m_pFile, const mz_uint64 to,
696 const mz_uint64 from, const size_t length,
697 mz_uint8 *move_buf, const size_t capacity_size) {
698 if (length > capacity_size) {
699 return ZIP_ECAPSIZE;
700 }
701 if (MZ_FSEEK64(m_pFile, from, SEEK_SET)) {
702 return ZIP_EFSEEK;
703 }
704 if (fread(move_buf, 1, length, m_pFile) != length) {
705 return ZIP_EFREAD;
706 }
707 if (MZ_FSEEK64(m_pFile, to, SEEK_SET)) {
708 return ZIP_EFSEEK;
709 }
710 if (fwrite(move_buf, 1, length, m_pFile) != length) {
711 return ZIP_EFWRITE;
712 }
713 return (ssize_t)length;
714}
715
716static ssize_t zip_files_move(struct zip_t *zip, mz_uint64 writen_num,
717 mz_uint64 read_num, size_t length) {
718 ssize_t n = 0;
719 const size_t page_size = 1 << 12; // 4K
720 mz_zip_internal_state *pState = zip->archive.m_pState;
721
722 mz_uint8 *move_buf = (mz_uint8 *)calloc(1, page_size);
723 if (!move_buf) {
724 return ZIP_EOOMEM;
725 }
726
727 ssize_t moved_length = 0;
728 ssize_t move_count = 0;
729 while ((mz_int64)length > 0) {
730 move_count = (length >= page_size) ? page_size : length;
731
732 if (pState->m_pFile) {
733 n = zip_file_move(pState->m_pFile, writen_num, read_num, move_count,
734 move_buf, page_size);
735 } else if (pState->m_pMem) {
736 n = zip_mem_move(pState->m_pMem, pState->m_mem_size, writen_num, read_num,
737 move_count);
738 } else {
739 return ZIP_ENOFILE;
740 }
741
742 if (n < 0) {
743 moved_length = n;
744 goto cleanup;
745 }
746
747 if (n != move_count) {
748 goto cleanup;
749 }
750
751 writen_num += move_count;
752 read_num += move_count;
753 length -= move_count;
754 moved_length += move_count;
755 }
756
757cleanup:
758 CLEANUP(move_buf);
759 return moved_length;
760}
761
762static int zip_central_dir_move(mz_zip_internal_state *pState, int begin,
763 int end, int entry_num) {
764 if (begin == entry_num) {
765 return 0;
766 }
767
768 size_t l_size = 0;
769 size_t r_size = 0;
770 mz_uint32 d_size = 0;
771 mz_uint8 *next = NULL;
772 mz_uint8 *deleted = &MZ_ZIP_ARRAY_ELEMENT(
773 &pState->m_central_dir, mz_uint8,
774 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, begin));
775 l_size = (size_t)(deleted - (mz_uint8 *)(pState->m_central_dir.m_p));
776 if (end == entry_num) {
777 r_size = 0;
778 } else {
779 next = &MZ_ZIP_ARRAY_ELEMENT(
780 &pState->m_central_dir, mz_uint8,
781 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, end));
782 r_size = pState->m_central_dir.m_size -
783 (mz_uint32)(next - (mz_uint8 *)(pState->m_central_dir.m_p));
784 d_size = (mz_uint32)(next - deleted);
785 }
786
787 if (next && l_size == 0) {
788 memmove(pState->m_central_dir.m_p, next, r_size);
789 pState->m_central_dir.m_p = MZ_REALLOC(pState->m_central_dir.m_p, r_size);
790 {
791 int i;
792 for (i = end; i < entry_num; i++) {
793 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i) -=
794 d_size;
795 }
796 }
797 }
798
799 if (next && l_size * r_size != 0) {
800 memmove(deleted, next, r_size);
801 {
802 int i;
803 for (i = end; i < entry_num; i++) {
804 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i) -=
805 d_size;
806 }
807 }
808 }
809
810 pState->m_central_dir.m_size = l_size + r_size;
811 return 0;
812}
813
814static int zip_central_dir_delete(mz_zip_internal_state *pState,
815 int *deleted_entry_index_array,
816 int entry_num) {
817 int i = 0;
818 int begin = 0;
819 int end = 0;
820 int d_num = 0;
821 while (i < entry_num) {
822 while ((i < entry_num) && (!deleted_entry_index_array[i])) {
823 i++;
824 }
825 begin = i;
826
827 while ((i < entry_num) && (deleted_entry_index_array[i])) {
828 i++;
829 }
830 end = i;
831 zip_central_dir_move(pState, begin, end, entry_num);
832 }
833
834 i = 0;
835 while (i < entry_num) {
836 while ((i < entry_num) && (!deleted_entry_index_array[i])) {
837 i++;
838 }
839 begin = i;
840 if (begin == entry_num) {
841 break;
842 }
843 while ((i < entry_num) && (deleted_entry_index_array[i])) {
844 i++;
845 }
846 end = i;
847 int k = 0, j;
848 for (j = end; j < entry_num; j++) {
849 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32,
850 begin + k) =
851 (mz_uint32)MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets,
852 mz_uint32, j);
853 k++;
854 }
855 d_num += end - begin;
856 }
857
858 pState->m_central_dir_offsets.m_size =
859 sizeof(mz_uint32) * (entry_num - d_num);
860 return 0;
861}
862
863static ssize_t zip_entries_delete_mark(struct zip_t *zip,
864 struct zip_entry_mark_t *entry_mark,
865 int entry_num) {
866 mz_uint64 writen_num = 0;
867 mz_uint64 read_num = 0;
868 size_t deleted_length = 0;
869 size_t move_length = 0;
870 int i = 0;
871 size_t deleted_entry_num = 0;
872 ssize_t n = 0;
873
874 mz_bool *deleted_entry_flag_array =
875 (mz_bool *)calloc(entry_num, sizeof(mz_bool));
876 if (deleted_entry_flag_array == NULL) {
877 return ZIP_EOOMEM;
878 }
879
880 mz_zip_internal_state *pState = zip->archive.m_pState;
881 zip->archive.m_zip_mode = MZ_ZIP_MODE_WRITING;
882
883 if (pState->m_pFile) {
884 if (MZ_FSEEK64(pState->m_pFile, 0, SEEK_SET)) {
885 CLEANUP(deleted_entry_flag_array);
886 return ZIP_ENOENT;
887 }
888 }
889
890 while (i < entry_num) {
891 while ((i < entry_num) && (entry_mark[i].type == MZ_KEEP)) {
892 writen_num += entry_mark[i].lf_length;
893 read_num = writen_num;
894 i++;
895 }
896
897 while ((i < entry_num) && (entry_mark[i].type == MZ_DELETE)) {
898 deleted_entry_flag_array[i] = MZ_TRUE;
899 read_num += entry_mark[i].lf_length;
900 deleted_length += entry_mark[i].lf_length;
901 i++;
902 deleted_entry_num++;
903 }
904
905 while ((i < entry_num) && (entry_mark[i].type == MZ_MOVE)) {
906 move_length += entry_mark[i].lf_length;
907 mz_uint8 *p = &MZ_ZIP_ARRAY_ELEMENT(
908 &pState->m_central_dir, mz_uint8,
909 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i));
910 if (!p) {
911 CLEANUP(deleted_entry_flag_array);
912 return ZIP_ENOENT;
913 }
914 mz_uint32 offset = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
915 offset -= (mz_uint32)deleted_length;
916 MZ_WRITE_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS, offset);
917 i++;
918 }
919
920 n = zip_files_move(zip, writen_num, read_num, move_length);
921 if (n != (ssize_t)move_length) {
922 CLEANUP(deleted_entry_flag_array);
923 return n;
924 }
925 writen_num += move_length;
926 read_num += move_length;
927 }
928
929 zip->archive.m_archive_size -= (mz_uint64)deleted_length;
930 zip->archive.m_total_files =
931 (mz_uint32)entry_num - (mz_uint32)deleted_entry_num;
932
933 zip_central_dir_delete(pState, deleted_entry_flag_array, entry_num);
934 CLEANUP(deleted_entry_flag_array);
935
936 return (ssize_t)deleted_entry_num;
937}
938
939struct zip_t *zip_open(const char *zipname, int level, char mode) {
940 int errnum = 0;
941 return zip_openwitherror(zipname, level, mode, &errnum);
942}
943
944struct zip_t *zip_openwitherror(const char *zipname, int level, char mode,
945 int *errnum) {
946 struct zip_t *zip = NULL;
947 *errnum = 0;
948
949 if (!zipname || strlen(zipname) < 1) {
950 // zip_t archive name is empty or NULL
951 *errnum = ZIP_EINVZIPNAME;
952 goto cleanup;
953 }
954
955 if (level < 0)
956 level = MZ_DEFAULT_LEVEL;
957 if ((level & 0xF) > MZ_UBER_COMPRESSION) {
958 // Wrong compression level
959 *errnum = ZIP_EINVLVL;
960 goto cleanup;
961 }
962
963 zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
964 if (!zip) {
965 // out of memory
966 *errnum = ZIP_EOOMEM;
967 goto cleanup;
968 }
969
970 zip->level = (mz_uint)level;
971 zip->entry.index = -1;
972 switch (mode) {
973 case 'w':
974 // Create a new archive.
975 if (!mz_zip_writer_init_file_v2(&(zip->archive), zipname, 0,
976 MZ_ZIP_FLAG_WRITE_ZIP64)) {
977 // Cannot initialize zip_archive writer
978 *errnum = ZIP_EWINIT;
979 goto cleanup;
980 }
981 break;
982
983 case 'r':
984 if (!mz_zip_reader_init_file_v2(
985 &(zip->archive), zipname,
986 zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) {
987 // An archive file does not exist or cannot initialize
988 // zip_archive reader
989 *errnum = ZIP_ERINIT;
990 goto cleanup;
991 }
992 break;
993
994 case 'a':
995 case 'd': {
996 MZ_FILE *fp = MZ_FOPEN(zipname, "r+b");
997 if (!fp) {
998 *errnum = ZIP_EOPNFILE;
999 goto cleanup;
1000 }
1001 if (!mz_zip_reader_init_cfile(
1002 &(zip->archive), fp, 0,
1003 zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) {
1004 // An archive file does not exist or cannot initialize zip_archive
1005 // reader
1006 *errnum = ZIP_ERINIT;
1007 fclose(fp);
1008 goto cleanup;
1009 }
1010 if (!mz_zip_writer_init_from_reader_v2(&(zip->archive), zipname, 0)) {
1011 *errnum = ZIP_EWRINIT;
1012 fclose(fp);
1013 mz_zip_reader_end(&(zip->archive));
1014 goto cleanup;
1015 }
1016 // The file pointer is now owned by the archive object.
1017 zip->archive.m_zip_type = MZ_ZIP_TYPE_FILE;
1018 } break;
1019
1020 default:
1021 *errnum = ZIP_EINVMODE;
1022 goto cleanup;
1023 }
1024
1025 return zip;
1026
1027cleanup:
1028 CLEANUP(zip);
1029 return NULL;
1030}
1031
1032void zip_close(struct zip_t *zip) {
1033 if (zip) {
1034 mz_zip_archive *pZip = &(zip->archive);
1035 // Always finalize, even if adding failed for some reason, so we have a
1036 // valid central directory.
1037 if (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) {
1038 mz_zip_writer_finalize_archive(pZip);
1039 }
1040
1041 if (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING ||
1042 pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED) {
1043 zip_archive_truncate(pZip);
1044 mz_zip_writer_end(pZip);
1045 }
1046 if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) {
1047 mz_zip_reader_end(pZip);
1048 }
1049
1050 CLEANUP(zip);
1051 }
1052}
1053
1054int zip_is64(struct zip_t *zip) {
1055 if (!zip || !zip->archive.m_pState) {
1056 // zip_t handler or zip state is not initialized
1057 return ZIP_ENOINIT;
1058 }
1059
1060 return (int)zip->archive.m_pState->m_zip64;
1061}
1062
1063int zip_offset(struct zip_t *zip, uint64_t *offset) {
1064 if (!zip || !zip->archive.m_pState) {
1065 // zip_t handler or zip state is not initialized
1066 return ZIP_ENOINIT;
1067 }
1068
1069 *offset = mz_zip_get_archive_file_start_offset(&zip->archive);
1070 return 0;
1071}
1072
1073static int _zip_entry_open(struct zip_t *zip, const char *entryname,
1074 int case_sensitive) {
1075 size_t entrylen = 0;
1076 mz_zip_archive *pzip = NULL;
1077 mz_uint num_alignment_padding_bytes, level;
1079 int err = 0;
1080 mz_uint16 dos_time = 0, dos_date = 0;
1081 mz_uint32 extra_size = 0;
1082 mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
1083 mz_uint64 local_dir_header_ofs = 0;
1084
1085 if (!zip) {
1086 return ZIP_ENOINIT;
1087 }
1088
1089 local_dir_header_ofs = zip->archive.m_archive_size;
1090
1091 if (!entryname) {
1092 return ZIP_EINVENTNAME;
1093 }
1094
1095 entrylen = strlen(entryname);
1096 if (entrylen == 0) {
1097 return ZIP_EINVENTNAME;
1098 }
1099
1100 if (zip->entry.name) {
1101 CLEANUP(zip->entry.name);
1102 }
1103
1104 pzip = &(zip->archive);
1105 if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) {
1106 zip->entry.name = zip_strclone(entryname, entrylen);
1107 if (!zip->entry.name) {
1108 // Cannot parse zip entry name
1109 return ZIP_EINVENTNAME;
1110 }
1111
1112 zip->entry.index = (ssize_t)mz_zip_reader_locate_file(
1113 pzip, zip->entry.name, NULL,
1114 case_sensitive ? MZ_ZIP_FLAG_CASE_SENSITIVE : 0);
1115 if (zip->entry.index < (ssize_t)0) {
1116 err = ZIP_ENOENT;
1117 goto cleanup;
1118 }
1119
1120 if (!mz_zip_reader_file_stat(pzip, (mz_uint)zip->entry.index, &stats)) {
1121 err = ZIP_ENOENT;
1122 goto cleanup;
1123 }
1124
1125 zip->entry.comp_size = stats.m_comp_size;
1126 zip->entry.uncomp_size = stats.m_uncomp_size;
1127 zip->entry.uncomp_crc32 = stats.m_crc32;
1128 zip->entry.dir_offset = stats.m_central_dir_ofs;
1129 zip->entry.header_offset = stats.m_local_header_ofs;
1130 zip->entry.method = stats.m_method;
1131 zip->entry.external_attr = stats.m_external_attr;
1132#ifndef MINIZ_NO_TIME
1133 zip->entry.m_time = stats.m_time;
1134#endif
1135
1136 return 0;
1137 }
1138
1139 /*
1140 .ZIP File Format Specification Version: 6.3.3
1141
1142 4.4.17.1 The name of the file, with optional relative path.
1143 The path stored MUST not contain a drive or
1144 device letter, or a leading slash. All slashes
1145 MUST be forward slashes '/' as opposed to
1146 backwards slashes '\' for compatibility with Amiga
1147 and UNIX file systems etc. If input came from standard
1148 input, there is no file name field.
1149 */
1150 zip->entry.name = zip_strrpl(entryname, entrylen, '\\', '/');
1151 if (!zip->entry.name) {
1152 // Cannot parse zip entry name
1153 return ZIP_EINVENTNAME;
1154 }
1155
1156 level = zip->level & 0xF;
1157
1158 zip->entry.index = (ssize_t)zip->archive.m_total_files;
1159 zip->entry.comp_size = 0;
1160 zip->entry.uncomp_size = 0;
1161 zip->entry.uncomp_crc32 = MZ_CRC32_INIT;
1162 zip->entry.dir_offset = zip->archive.m_archive_size;
1163 zip->entry.header_offset = zip->archive.m_archive_size;
1164 memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
1165 zip->entry.method = level ? MZ_DEFLATED : 0;
1166
1167 // UNIX or APPLE
1168#if MZ_PLATFORM == 3 || MZ_PLATFORM == 19
1169 // regular file with rw-r--r-- permissions
1170 zip->entry.external_attr = (mz_uint32)(0100644) << 16;
1171#else
1172 zip->entry.external_attr = 0;
1173#endif
1174
1175 num_alignment_padding_bytes =
1176 mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
1177
1178 if (!pzip->m_pState || (pzip->m_zip_mode != MZ_ZIP_MODE_WRITING)) {
1179 // Invalid zip mode
1180 err = ZIP_EINVMODE;
1181 goto cleanup;
1182 }
1183 if (zip->level & MZ_ZIP_FLAG_COMPRESSED_DATA) {
1184 // Invalid zip compression level
1185 err = ZIP_EINVLVL;
1186 goto cleanup;
1187 }
1188
1189 if (!mz_zip_writer_write_zeros(pzip, zip->entry.dir_offset,
1190 num_alignment_padding_bytes)) {
1191 // Cannot memset zip entry header
1192 err = ZIP_EMEMSET;
1193 goto cleanup;
1194 }
1195 local_dir_header_ofs += num_alignment_padding_bytes;
1196
1197 zip->entry.m_time = time(NULL);
1198#ifndef MINIZ_NO_TIME
1199 mz_zip_time_t_to_dos_time(zip->entry.m_time, &dos_time, &dos_date);
1200#endif
1201
1202 // ZIP64 header with NULL sizes (sizes will be in the data descriptor, just
1203 // after file data)
1204 extra_size = mz_zip_writer_create_zip64_extra_data(
1205 extra_data, NULL, NULL,
1206 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
1207
1208 if (!mz_zip_writer_create_local_dir_header(
1209 pzip, zip->entry.header, entrylen, (mz_uint16)extra_size, 0, 0, 0,
1210 zip->entry.method,
1211 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 |
1212 MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR,
1213 dos_time, dos_date)) {
1214 // Cannot create zip entry header
1215 err = ZIP_EMEMSET;
1216 goto cleanup;
1217 }
1218
1219 zip->entry.header_offset =
1220 zip->entry.dir_offset + num_alignment_padding_bytes;
1221
1222 if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset,
1223 zip->entry.header,
1224 sizeof(zip->entry.header)) != sizeof(zip->entry.header)) {
1225 // Cannot write zip entry header
1226 err = ZIP_EMEMSET;
1227 goto cleanup;
1228 }
1229
1230 if (pzip->m_file_offset_alignment) {
1231 MZ_ASSERT(
1232 (zip->entry.header_offset & (pzip->m_file_offset_alignment - 1)) == 0);
1233 }
1234 zip->entry.dir_offset +=
1235 num_alignment_padding_bytes + sizeof(zip->entry.header);
1236
1237 if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, zip->entry.name,
1238 entrylen) != entrylen) {
1239 // Cannot write data to zip entry
1240 err = ZIP_EWRTENT;
1241 goto cleanup;
1242 }
1243
1244 zip->entry.dir_offset += entrylen;
1245
1246 if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, extra_data,
1247 extra_size) != extra_size) {
1248 // Cannot write ZIP64 data to zip entry
1249 err = ZIP_EWRTENT;
1250 goto cleanup;
1251 }
1252 zip->entry.dir_offset += extra_size;
1253
1254 if (level) {
1255 zip->entry.state.m_pZip = pzip;
1256 zip->entry.state.m_cur_archive_file_ofs = zip->entry.dir_offset;
1257 zip->entry.state.m_comp_size = 0;
1258
1259 if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback,
1260 &(zip->entry.state),
1261 (int)tdefl_create_comp_flags_from_zip_params(
1262 (int)level, -15, MZ_DEFAULT_STRATEGY)) !=
1263 TDEFL_STATUS_OKAY) {
1264 // Cannot initialize the zip compressor
1265 err = ZIP_ETDEFLINIT;
1266 goto cleanup;
1267 }
1268 }
1269
1270 return 0;
1271
1272cleanup:
1273 CLEANUP(zip->entry.name);
1274 return err;
1275}
1276
1277int zip_entry_open(struct zip_t *zip, const char *entryname) {
1278 return _zip_entry_open(zip, entryname, 0);
1279}
1280
1281int zip_entry_opencasesensitive(struct zip_t *zip, const char *entryname) {
1282 return _zip_entry_open(zip, entryname, 1);
1283}
1284
1285int zip_entry_openbyindex(struct zip_t *zip, size_t index) {
1286 mz_zip_archive *pZip = NULL;
1288 mz_uint namelen;
1289 const mz_uint8 *pHeader;
1290 const char *pFilename;
1291
1292 if (!zip) {
1293 // zip_t handler is not initialized
1294 return ZIP_ENOINIT;
1295 }
1296
1297 pZip = &(zip->archive);
1298 if (pZip->m_zip_mode != MZ_ZIP_MODE_READING) {
1299 // open by index requires readonly mode
1300 return ZIP_EINVMODE;
1301 }
1302
1303 if (index >= (size_t)pZip->m_total_files) {
1304 // index out of range
1305 return ZIP_EINVIDX;
1306 }
1307
1308 if (!(pHeader = &MZ_ZIP_ARRAY_ELEMENT(
1309 &pZip->m_pState->m_central_dir, mz_uint8,
1310 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets,
1311 mz_uint32, index)))) {
1312 // cannot find header in central directory
1313 return ZIP_ENOHDR;
1314 }
1315
1316 namelen = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
1317 pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
1318
1319 if (zip->entry.name) {
1320 CLEANUP(zip->entry.name);
1321 }
1322
1323 zip->entry.name = zip_strclone(pFilename, namelen);
1324 if (!zip->entry.name) {
1325 // local entry name is NULL
1326 return ZIP_EINVENTNAME;
1327 }
1328
1329 if (!mz_zip_reader_file_stat(pZip, (mz_uint)index, &stats)) {
1330 return ZIP_ENOENT;
1331 }
1332
1333 zip->entry.index = (ssize_t)index;
1334 zip->entry.comp_size = stats.m_comp_size;
1335 zip->entry.uncomp_size = stats.m_uncomp_size;
1336 zip->entry.uncomp_crc32 = stats.m_crc32;
1337 zip->entry.dir_offset = stats.m_central_dir_ofs;
1338 zip->entry.header_offset = stats.m_local_header_ofs;
1339 zip->entry.method = stats.m_method;
1340 zip->entry.external_attr = stats.m_external_attr;
1341#ifndef MINIZ_NO_TIME
1342 zip->entry.m_time = stats.m_time;
1343#endif
1344
1345 return 0;
1346}
1347
1348int zip_entry_close(struct zip_t *zip) {
1349 mz_zip_archive *pzip = NULL;
1350 mz_uint level;
1351 tdefl_status done;
1352 mz_uint16 entrylen;
1353 mz_uint16 dos_time = 0, dos_date = 0;
1354 int err = 0;
1355 mz_uint8 *pExtra_data = NULL;
1356 mz_uint32 extra_size = 0;
1357 mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
1358 mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
1359 mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
1360
1361 if (!zip) {
1362 // zip_t handler is not initialized
1363 err = ZIP_ENOINIT;
1364 goto cleanup;
1365 }
1366
1367 pzip = &(zip->archive);
1368 if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) {
1369 goto cleanup;
1370 }
1371
1372 level = zip->level & 0xF;
1373 if (level) {
1374 done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH);
1375 if (done != TDEFL_STATUS_DONE && done != TDEFL_STATUS_OKAY) {
1376 // Cannot flush compressed buffer
1377 err = ZIP_ETDEFLBUF;
1378 goto cleanup;
1379 }
1380 zip->entry.comp_size = zip->entry.state.m_comp_size;
1381 zip->entry.dir_offset = zip->entry.state.m_cur_archive_file_ofs;
1382 zip->entry.method = MZ_DEFLATED;
1383 }
1384
1385 entrylen = (mz_uint16)strlen(zip->entry.name);
1386#ifndef MINIZ_NO_TIME
1387 mz_zip_time_t_to_dos_time(zip->entry.m_time, &dos_time, &dos_date);
1388#endif
1389
1390 MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
1391 MZ_WRITE_LE32(local_dir_footer + 4, zip->entry.uncomp_crc32);
1392 MZ_WRITE_LE64(local_dir_footer + 8, zip->entry.comp_size);
1393 MZ_WRITE_LE64(local_dir_footer + 16, zip->entry.uncomp_size);
1394
1395 if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset,
1396 local_dir_footer,
1397 local_dir_footer_size) != local_dir_footer_size) {
1398 // Cannot write zip entry header
1399 err = ZIP_EWRTHDR;
1400 goto cleanup;
1401 }
1402 zip->entry.dir_offset += local_dir_footer_size;
1403
1404 pExtra_data = extra_data;
1405 extra_size = mz_zip_writer_create_zip64_extra_data(
1406 extra_data,
1407 (zip->entry.uncomp_size >= MZ_UINT32_MAX) ? &zip->entry.uncomp_size
1408 : NULL,
1409 (zip->entry.comp_size >= MZ_UINT32_MAX) ? &zip->entry.comp_size : NULL,
1410 (zip->entry.header_offset >= MZ_UINT32_MAX) ? &zip->entry.header_offset
1411 : NULL);
1412
1413 if ((entrylen) && ISSLASH(zip->entry.name[entrylen - 1]) &&
1414 !zip->entry.uncomp_size) {
1415 /* Set DOS Subdirectory attribute bit. */
1416 zip->entry.external_attr |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG;
1417 }
1418
1419 if (!mz_zip_writer_add_to_central_dir(
1420 pzip, zip->entry.name, entrylen, pExtra_data, (mz_uint16)extra_size,
1421 "", 0, zip->entry.uncomp_size, zip->entry.comp_size,
1422 zip->entry.uncomp_crc32, zip->entry.method,
1423 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 |
1424 MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR,
1425 dos_time, dos_date, zip->entry.header_offset,
1426 zip->entry.external_attr, NULL, 0)) {
1427 // Cannot write to zip central dir
1428 err = ZIP_EWRTDIR;
1429 goto cleanup;
1430 }
1431
1432 pzip->m_total_files++;
1433 pzip->m_archive_size = zip->entry.dir_offset;
1434
1435cleanup:
1436 if (zip) {
1437 zip->entry.m_time = 0;
1438 zip->entry.index = -1;
1439 CLEANUP(zip->entry.name);
1440 }
1441 return err;
1442}
1443
1444const char *zip_entry_name(struct zip_t *zip) {
1445 if (!zip) {
1446 // zip_t handler is not initialized
1447 return NULL;
1448 }
1449 return zip->entry.name;
1450}
1451
1452ssize_t zip_entry_index(struct zip_t *zip) {
1453 if (!zip) {
1454 // zip_t handler is not initialized
1455 return (ssize_t)ZIP_ENOINIT;
1456 }
1457
1458 return zip->entry.index;
1459}
1460
1461int zip_entry_isdir(struct zip_t *zip) {
1462 mz_uint16 entrylen;
1463 if (!zip) {
1464 // zip_t handler is not initialized
1465 return ZIP_ENOINIT;
1466 }
1467
1468 if (zip->entry.index < (ssize_t)0) {
1469 // zip entry is not opened
1470 return ZIP_EINVIDX;
1471 }
1472
1473 entrylen = (mz_uint16)strlen(zip->entry.name);
1474 return ISSLASH(zip->entry.name[entrylen - 1]);
1475}
1476
1477unsigned long long zip_entry_size(struct zip_t *zip) {
1478 return zip_entry_uncomp_size(zip);
1479}
1480
1481unsigned long long zip_entry_uncomp_size(struct zip_t *zip) {
1482 return zip ? zip->entry.uncomp_size : 0;
1483}
1484
1485unsigned long long zip_entry_comp_size(struct zip_t *zip) {
1486 return zip ? zip->entry.comp_size : 0;
1487}
1488
1489unsigned int zip_entry_crc32(struct zip_t *zip) {
1490 return zip ? zip->entry.uncomp_crc32 : 0;
1491}
1492
1493unsigned long long zip_entry_dir_offset(struct zip_t *zip) {
1494 return zip ? zip->entry.dir_offset : 0;
1495}
1496
1497unsigned long long zip_entry_header_offset(struct zip_t *zip) {
1498 return zip ? zip->entry.header_offset : 0;
1499}
1500
1501int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) {
1502 mz_uint level;
1503 mz_zip_archive *pzip = NULL;
1504 tdefl_status status;
1505
1506 if (!zip) {
1507 // zip_t handler is not initialized
1508 return ZIP_ENOINIT;
1509 }
1510
1511 pzip = &(zip->archive);
1512 if (buf && bufsize > 0) {
1513 zip->entry.uncomp_size += bufsize;
1514 zip->entry.uncomp_crc32 = (mz_uint32)mz_crc32(
1515 zip->entry.uncomp_crc32, (const mz_uint8 *)buf, bufsize);
1516
1517 level = zip->level & 0xF;
1518 if (!level) {
1519 if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, buf,
1520 bufsize) != bufsize)) {
1521 // Cannot write buffer
1522 return ZIP_EWRTENT;
1523 }
1524 zip->entry.dir_offset += bufsize;
1525 zip->entry.comp_size += bufsize;
1526 } else {
1527 status = tdefl_compress_buffer(&(zip->entry.comp), buf, bufsize,
1528 TDEFL_NO_FLUSH);
1529 if (status != TDEFL_STATUS_DONE && status != TDEFL_STATUS_OKAY) {
1530 // Cannot compress buffer
1531 return ZIP_ETDEFLBUF;
1532 }
1533 }
1534 }
1535
1536 return 0;
1537}
1538
1539int zip_entry_fwrite(struct zip_t *zip, const char *filename) {
1540 int err = 0;
1541 size_t n = 0;
1542 MZ_FILE *stream = NULL;
1543 mz_uint8 buf[MZ_ZIP_MAX_IO_BUF_SIZE];
1544 struct MZ_FILE_STAT_STRUCT file_stat;
1545 mz_uint16 modes;
1546
1547 if (!zip) {
1548 // zip_t handler is not initialized
1549 return ZIP_ENOINIT;
1550 }
1551
1552 memset(buf, 0, MZ_ZIP_MAX_IO_BUF_SIZE);
1553 memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT));
1554 if (MZ_FILE_STAT(filename, &file_stat) != 0) {
1555 // problem getting information - check errno
1556 return ZIP_ENOENT;
1557 }
1558
1559#if defined(_WIN32) || defined(__WIN32__) || defined(DJGPP)
1560 (void)modes; // unused
1561#else
1562 /* Initialize with permission bits--which are not implementation-optional */
1563 modes = file_stat.st_mode &
1564 (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
1565 if (S_ISDIR(file_stat.st_mode))
1566 modes |= UNX_IFDIR;
1567 if (S_ISREG(file_stat.st_mode))
1568 modes |= UNX_IFREG;
1569 if (S_ISLNK(file_stat.st_mode))
1570 modes |= UNX_IFLNK;
1571 if (S_ISBLK(file_stat.st_mode))
1572 modes |= UNX_IFBLK;
1573 if (S_ISCHR(file_stat.st_mode))
1574 modes |= UNX_IFCHR;
1575 if (S_ISFIFO(file_stat.st_mode))
1576 modes |= UNX_IFIFO;
1577 if (S_ISSOCK(file_stat.st_mode))
1578 modes |= UNX_IFSOCK;
1579 zip->entry.external_attr = (modes << 16) | !(file_stat.st_mode & S_IWUSR);
1580 if ((file_stat.st_mode & S_IFMT) == S_IFDIR) {
1581 zip->entry.external_attr |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG;
1582 }
1583#endif
1584
1585 zip->entry.m_time = file_stat.st_mtime;
1586
1587 if (!(stream = MZ_FOPEN(filename, "rb"))) {
1588 // Cannot open filename
1589 return ZIP_EOPNFILE;
1590 }
1591
1592 while ((n = fread(buf, sizeof(mz_uint8), MZ_ZIP_MAX_IO_BUF_SIZE, stream)) >
1593 0) {
1594 if (zip_entry_write(zip, buf, n) < 0) {
1595 err = ZIP_EWRTENT;
1596 break;
1597 }
1598 }
1599 fclose(stream);
1600
1601 return err;
1602}
1603
1604ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) {
1605 mz_zip_archive *pzip = NULL;
1606 mz_uint idx;
1607 size_t size = 0;
1608
1609 if (!zip) {
1610 // zip_t handler is not initialized
1611 return (ssize_t)ZIP_ENOINIT;
1612 }
1613
1614 pzip = &(zip->archive);
1615 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING ||
1616 zip->entry.index < (ssize_t)0) {
1617 // the entry is not found or we do not have read access
1618 return (ssize_t)ZIP_ENOENT;
1619 }
1620
1621 idx = (mz_uint)zip->entry.index;
1622 if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
1623 // the entry is a directory
1624 return (ssize_t)ZIP_EINVENTTYPE;
1625 }
1626
1627 *buf = mz_zip_reader_extract_to_heap(pzip, idx, &size, 0);
1628 if (*buf && bufsize) {
1629 *bufsize = size;
1630 }
1631 return (ssize_t)size;
1632}
1633
1634ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
1635 mz_zip_archive *pzip = NULL;
1636
1637 if (!zip) {
1638 // zip_t handler is not initialized
1639 return (ssize_t)ZIP_ENOINIT;
1640 }
1641
1642 pzip = &(zip->archive);
1643 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING ||
1644 zip->entry.index < (ssize_t)0) {
1645 // the entry is not found or we do not have read access
1646 return (ssize_t)ZIP_ENOENT;
1647 }
1648
1649 if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index,
1650 buf, bufsize, 0, NULL, 0)) {
1651 return (ssize_t)ZIP_EMEMNOALLOC;
1652 }
1653
1654 return (ssize_t)zip->entry.uncomp_size;
1655}
1656
1657int zip_entry_fread(struct zip_t *zip, const char *filename) {
1658 mz_zip_archive *pzip = NULL;
1659 mz_uint idx;
1660 mz_uint32 xattr = 0;
1662
1663 if (!zip) {
1664 // zip_t handler is not initialized
1665 return ZIP_ENOINIT;
1666 }
1667
1668 memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat));
1669 pzip = &(zip->archive);
1670 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING ||
1671 zip->entry.index < (ssize_t)0) {
1672 // the entry is not found or we do not have read access
1673 return ZIP_ENOENT;
1674 }
1675
1676 idx = (mz_uint)zip->entry.index;
1677 if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
1678 // the entry is a directory
1679 return ZIP_EINVENTTYPE;
1680 }
1681
1682 if (!mz_zip_reader_extract_to_file(pzip, idx, filename, 0)) {
1683 return ZIP_ENOFILE;
1684 }
1685
1686#if defined(_MSC_VER) || defined(PS4)
1687 (void)xattr; // unused
1688#else
1689 if (!mz_zip_reader_file_stat(pzip, idx, &info)) {
1690 // Cannot get information about zip archive;
1691 return ZIP_ENOFILE;
1692 }
1693
1694 xattr = (info.m_external_attr >> 16) & 0xFFFF;
1695 if (xattr > 0 && xattr <= MZ_UINT16_MAX) {
1696 if (CHMOD(filename, (mode_t)xattr) < 0) {
1697 return ZIP_ENOPERM;
1698 }
1699 }
1700#endif
1701
1702 return 0;
1703}
1704
1705int zip_entry_extract(struct zip_t *zip,
1706 size_t (*on_extract)(void *arg, uint64_t offset,
1707 const void *buf, size_t bufsize),
1708 void *arg) {
1709 mz_zip_archive *pzip = NULL;
1710 mz_uint idx;
1711
1712 if (!zip) {
1713 // zip_t handler is not initialized
1714 return ZIP_ENOINIT;
1715 }
1716
1717 pzip = &(zip->archive);
1718 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING ||
1719 zip->entry.index < (ssize_t)0) {
1720 // the entry is not found or we do not have read access
1721 return ZIP_ENOENT;
1722 }
1723
1724 idx = (mz_uint)zip->entry.index;
1725 return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0))
1726 ? 0
1727 : ZIP_EINVIDX;
1728}
1729
1730ssize_t zip_entries_total(struct zip_t *zip) {
1731 if (!zip) {
1732 // zip_t handler is not initialized
1733 return ZIP_ENOINIT;
1734 }
1735
1736 return (ssize_t)zip->archive.m_total_files;
1737}
1738
1739ssize_t zip_entries_delete(struct zip_t *zip, char *const entries[],
1740 size_t len) {
1741 ssize_t n = 0;
1742 ssize_t err = 0;
1743 struct zip_entry_mark_t *entry_mark = NULL;
1744
1745 if (zip == NULL || (entries == NULL && len != 0)) {
1746 return ZIP_ENOINIT;
1747 }
1748
1749 if (entries == NULL && len == 0) {
1750 return 0;
1751 }
1752
1753 n = zip_entries_total(zip);
1754
1755 entry_mark = (struct zip_entry_mark_t *)calloc(
1756 (size_t)n, sizeof(struct zip_entry_mark_t));
1757 if (!entry_mark) {
1758 return ZIP_EOOMEM;
1759 }
1760
1761 zip->archive.m_zip_mode = MZ_ZIP_MODE_READING;
1762
1763 err = zip_entry_set(zip, entry_mark, n, entries, len);
1764 if (err < 0) {
1765 CLEANUP(entry_mark);
1766 return err;
1767 }
1768
1769 err = zip_entries_delete_mark(zip, entry_mark, (int)n);
1770 CLEANUP(entry_mark);
1771 return err;
1772}
1773
1774ssize_t zip_entries_deletebyindex(struct zip_t *zip, size_t entries[],
1775 size_t len) {
1776 ssize_t n = 0;
1777 ssize_t err = 0;
1778 struct zip_entry_mark_t *entry_mark = NULL;
1779
1780 if (zip == NULL || (entries == NULL && len != 0)) {
1781 return ZIP_ENOINIT;
1782 }
1783
1784 if (entries == NULL && len == 0) {
1785 return 0;
1786 }
1787
1788 n = zip_entries_total(zip);
1789
1790 entry_mark = (struct zip_entry_mark_t *)calloc(
1791 (size_t)n, sizeof(struct zip_entry_mark_t));
1792 if (!entry_mark) {
1793 return ZIP_EOOMEM;
1794 }
1795
1796 zip->archive.m_zip_mode = MZ_ZIP_MODE_READING;
1797
1798 err = zip_entry_setbyindex(zip, entry_mark, n, entries, len);
1799 if (err < 0) {
1800 CLEANUP(entry_mark);
1801 return err;
1802 }
1803
1804 err = zip_entries_delete_mark(zip, entry_mark, (int)n);
1805 CLEANUP(entry_mark);
1806 return err;
1807}
1808
1809int zip_stream_extract(const char *stream, size_t size, const char *dir,
1810 int (*on_extract)(const char *filename, void *arg),
1811 void *arg) {
1812 mz_zip_archive zip_archive;
1813 if (!stream || !dir) {
1814 // Cannot parse zip archive stream
1815 return ZIP_ENOINIT;
1816 }
1817 if (!memset(&zip_archive, 0, sizeof(mz_zip_archive))) {
1818 // Cannot memset zip archive
1819 return ZIP_EMEMSET;
1820 }
1821 if (!mz_zip_reader_init_mem(&zip_archive, stream, size, 0)) {
1822 // Cannot initialize zip_archive reader
1823 return ZIP_ENOINIT;
1824 }
1825
1826 return zip_archive_extract(&zip_archive, dir, on_extract, arg);
1827}
1828
1829struct zip_t *zip_stream_open(const char *stream, size_t size, int level,
1830 char mode) {
1831 int errnum = 0;
1832 return zip_stream_openwitherror(stream, size, level, mode, &errnum);
1833}
1834
1835struct zip_t *zip_stream_openwitherror(const char *stream, size_t size,
1836 int level, char mode, int *errnum) {
1837 struct zip_t *zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
1838 if (!zip) {
1839 // out of memory
1840 *errnum = ZIP_EOOMEM;
1841 return NULL;
1842 }
1843
1844 if (level < 0) {
1845 level = MZ_DEFAULT_LEVEL;
1846 }
1847 if ((level & 0xF) > MZ_UBER_COMPRESSION) {
1848 // Wrong compression level
1849 *errnum = ZIP_EINVLVL;
1850 goto cleanup;
1851 }
1852 zip->level = (mz_uint)level;
1853
1854 if ((stream != NULL) && (size > 0) && (mode == 'r')) {
1855 if (!mz_zip_reader_init_mem(&(zip->archive), stream, size, 0)) {
1856 *errnum = ZIP_ERINIT;
1857 goto cleanup;
1858 }
1859 } else if ((stream == NULL) && (size == 0) && (mode == 'w')) {
1860 // Create a new archive.
1861 if (!mz_zip_writer_init_heap(&(zip->archive), 0, 1024)) {
1862 // Cannot initialize zip_archive writer
1863 *errnum = ZIP_EWINIT;
1864 goto cleanup;
1865 }
1866 } else {
1867 *errnum = ZIP_EINVMODE;
1868 goto cleanup;
1869 }
1870
1871 *errnum = 0;
1872 return zip;
1873
1874cleanup:
1875 CLEANUP(zip);
1876 return NULL;
1877}
1878
1879ssize_t zip_stream_copy(struct zip_t *zip, void **buf, size_t *bufsize) {
1880 size_t n;
1881
1882 if (!zip) {
1883 return (ssize_t)ZIP_ENOINIT;
1884 }
1885 zip_archive_finalize(&(zip->archive));
1886
1887 n = (size_t)zip->archive.m_archive_size;
1888 if (bufsize != NULL) {
1889 *bufsize = n;
1890 }
1891
1892 *buf = calloc(n, sizeof(unsigned char));
1893 memcpy(*buf, zip->archive.m_pState->m_pMem, n);
1894
1895 return (ssize_t)n;
1896}
1897
1898void zip_stream_close(struct zip_t *zip) {
1899 if (zip) {
1900 mz_zip_writer_end(&(zip->archive));
1901 mz_zip_reader_end(&(zip->archive));
1902 CLEANUP(zip);
1903 }
1904}
1905
1906struct zip_t *zip_cstream_open(FILE *stream, int level, char mode) {
1907 int errnum = 0;
1908 return zip_cstream_openwitherror(stream, level, mode, &errnum);
1909}
1910
1911struct zip_t *zip_cstream_openwitherror(FILE *stream, int level, char mode,
1912 int *errnum) {
1913 struct zip_t *zip = NULL;
1914 *errnum = 0;
1915 if (!stream) {
1916 // zip archive stream is NULL
1917 *errnum = ZIP_ENOFILE;
1918 goto cleanup;
1919 }
1920
1921 if (level < 0)
1922 level = MZ_DEFAULT_LEVEL;
1923 if ((level & 0xF) > MZ_UBER_COMPRESSION) {
1924 // Wrong compression level
1925 *errnum = ZIP_EINVLVL;
1926 goto cleanup;
1927 }
1928
1929 zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
1930 if (!zip) {
1931 // out of memory
1932 *errnum = ZIP_EOOMEM;
1933 goto cleanup;
1934 }
1935
1936 zip->level = (mz_uint)level;
1937 switch (mode) {
1938 case 'w':
1939 // Create a new archive.
1940 if (!mz_zip_writer_init_cfile(&(zip->archive), stream,
1941 MZ_ZIP_FLAG_WRITE_ZIP64)) {
1942 // Cannot initialize zip_archive writer
1943 *errnum = ZIP_EWINIT;
1944 goto cleanup;
1945 }
1946 break;
1947
1948 case 'r':
1949 if (!mz_zip_reader_init_cfile(
1950 &(zip->archive), stream, 0,
1951 zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) {
1952 // An archive file does not exist or cannot initialize
1953 // zip_archive reader
1954 *errnum = ZIP_ERINIT;
1955 goto cleanup;
1956 }
1957 break;
1958
1959 case 'a':
1960 case 'd':
1961 if (!mz_zip_reader_init_cfile(
1962 &(zip->archive), stream, 0,
1963 zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) {
1964 // An archive file does not exist or cannot initialize
1965 // zip_archive reader
1966 *errnum = ZIP_ERINIT;
1967 goto cleanup;
1968 }
1969 if ((mode == 'a' || mode == 'd')) {
1970 if (!mz_zip_writer_init_from_reader_v2(&(zip->archive), NULL, 0)) {
1971 *errnum = ZIP_EWRINIT;
1972 mz_zip_reader_end(&(zip->archive));
1973 goto cleanup;
1974 }
1975 }
1976 break;
1977
1978 default:
1979 *errnum = ZIP_EINVMODE;
1980 goto cleanup;
1981 }
1982
1983 return zip;
1984
1985cleanup:
1986 CLEANUP(zip);
1987 return NULL;
1988}
1989
1990void zip_cstream_close(struct zip_t *zip) { zip_close(zip); }
1991
1992int zip_create(const char *zipname, const char *filenames[], size_t len) {
1993 int err = 0;
1994 size_t i;
1995 mz_zip_archive zip_archive;
1996 struct MZ_FILE_STAT_STRUCT file_stat;
1997 mz_uint32 ext_attributes = 0;
1998 mz_uint16 modes;
1999
2000 if (!zipname || strlen(zipname) < 1) {
2001 // zip_t archive name is empty or NULL
2002 return ZIP_EINVZIPNAME;
2003 }
2004
2005 // Create a new archive.
2006 if (!memset(&(zip_archive), 0, sizeof(zip_archive))) {
2007 // Cannot memset zip archive
2008 return ZIP_EMEMSET;
2009 }
2010
2011 if (!mz_zip_writer_init_file(&zip_archive, zipname, 0)) {
2012 // Cannot initialize zip_archive writer
2013 return ZIP_ENOINIT;
2014 }
2015
2016 if (!memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT))) {
2017 return ZIP_EMEMSET;
2018 }
2019
2020 for (i = 0; i < len; ++i) {
2021 const char *name = filenames[i];
2022 if (!name) {
2023 err = ZIP_EINVENTNAME;
2024 break;
2025 }
2026
2027 if (MZ_FILE_STAT(name, &file_stat) != 0) {
2028 // problem getting information - check errno
2029 err = ZIP_ENOFILE;
2030 break;
2031 }
2032
2033#if defined(_WIN32) || defined(__WIN32__) || defined(DJGPP)
2034 (void)modes; // unused
2035#else
2036
2037 /* Initialize with permission bits--which are not implementation-optional */
2038 modes = file_stat.st_mode &
2039 (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
2040 if (S_ISDIR(file_stat.st_mode))
2041 modes |= UNX_IFDIR;
2042 if (S_ISREG(file_stat.st_mode))
2043 modes |= UNX_IFREG;
2044 if (S_ISLNK(file_stat.st_mode))
2045 modes |= UNX_IFLNK;
2046 if (S_ISBLK(file_stat.st_mode))
2047 modes |= UNX_IFBLK;
2048 if (S_ISCHR(file_stat.st_mode))
2049 modes |= UNX_IFCHR;
2050 if (S_ISFIFO(file_stat.st_mode))
2051 modes |= UNX_IFIFO;
2052 if (S_ISSOCK(file_stat.st_mode))
2053 modes |= UNX_IFSOCK;
2054 ext_attributes = (modes << 16) | !(file_stat.st_mode & S_IWUSR);
2055 if ((file_stat.st_mode & S_IFMT) == S_IFDIR) {
2056 ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG;
2057 }
2058#endif
2059
2060 if (!mz_zip_writer_add_file(&zip_archive, zip_basename(name), name, "", 0,
2062 ext_attributes)) {
2063 // Cannot add file to zip_archive
2064 err = ZIP_ENOFILE;
2065 break;
2066 }
2067 }
2068
2069 mz_zip_writer_finalize_archive(&zip_archive);
2070 mz_zip_writer_end(&zip_archive);
2071 return err;
2072}
2073
2074int zip_extract(const char *zipname, const char *dir,
2075 int (*on_extract)(const char *filename, void *arg), void *arg) {
2076 mz_zip_archive zip_archive;
2077
2078 if (!zipname || !dir) {
2079 // Cannot parse zip archive name
2080 return ZIP_EINVZIPNAME;
2081 }
2082
2083 if (!memset(&zip_archive, 0, sizeof(mz_zip_archive))) {
2084 // Cannot memset zip archive
2085 return ZIP_EMEMSET;
2086 }
2087
2088 // Now try to open the archive.
2089 if (!mz_zip_reader_init_file(&zip_archive, zipname, 0)) {
2090 // Cannot initialize zip_archive reader
2091 return ZIP_ENOINIT;
2092 }
2093
2094 return zip_archive_extract(&zip_archive, dir, on_extract, arg);
2095}
int zip_is64(struct zip_t *zip)
Definition zip.c:1054
struct zip_t * zip_openwitherror(const char *zipname, int level, char mode, int *errnum)
Definition zip.c:944
unsigned long long zip_entry_size(struct zip_t *zip)
Definition zip.c:1477
int zip_entry_isdir(struct zip_t *zip)
Definition zip.c:1461
ssize_t zip_entry_index(struct zip_t *zip)
Definition zip.c:1452
const char * zip_entry_name(struct zip_t *zip)
Definition zip.c:1444
struct zip_t * zip_open(const char *zipname, int level, char mode)
Definition zip.c:939
ssize_t zip_entries_deletebyindex(struct zip_t *zip, size_t entries[], size_t len)
Definition zip.c:1774
void zip_stream_close(struct zip_t *zip)
Definition zip.c:1898
int zip_entry_fread(struct zip_t *zip, const char *filename)
Definition zip.c:1657
struct zip_t * zip_stream_open(const char *stream, size_t size, int level, char mode)
Definition zip.c:1829
const char * zip_strerror(int errnum)
Definition zip.c:153
ssize_t zip_stream_copy(struct zip_t *zip, void **buf, size_t *bufsize)
Definition zip.c:1879
ssize_t zip_entries_delete(struct zip_t *zip, char *const entries[], size_t len)
Definition zip.c:1739
int zip_entry_fwrite(struct zip_t *zip, const char *filename)
Definition zip.c:1539
void zip_cstream_close(struct zip_t *zip)
Definition zip.c:1990
ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize)
Definition zip.c:1634
int zip_offset(struct zip_t *zip, uint64_t *offset)
Definition zip.c:1063
struct zip_t * zip_cstream_open(FILE *stream, int level, char mode)
Definition zip.c:1906
unsigned int zip_entry_crc32(struct zip_t *zip)
Definition zip.c:1489
unsigned long long zip_entry_uncomp_size(struct zip_t *zip)
Definition zip.c:1481
struct zip_t * zip_stream_openwitherror(const char *stream, size_t size, int level, char mode, int *errnum)
Definition zip.c:1835
#define ZIP_DEFAULT_COMPRESSION_LEVEL
Definition zip.h:62
int zip_create(const char *zipname, const char *filenames[], size_t len)
Definition zip.c:1992
void zip_close(struct zip_t *zip)
Definition zip.c:1032
int zip_entry_open(struct zip_t *zip, const char *entryname)
Definition zip.c:1277
int zip_entry_opencasesensitive(struct zip_t *zip, const char *entryname)
Definition zip.c:1281
int zip_extract(const char *zipname, const char *dir, int(*on_extract)(const char *filename, void *arg), void *arg)
Definition zip.c:2074
struct zip_t * zip_cstream_openwitherror(FILE *stream, int level, char mode, int *errnum)
Definition zip.c:1911
#define ZIP_ENOINIT
Definition zip.h:67
int zip_entry_close(struct zip_t *zip)
Definition zip.c:1348
unsigned long long zip_entry_header_offset(struct zip_t *zip)
Definition zip.c:1497
int zip_entry_openbyindex(struct zip_t *zip, size_t index)
Definition zip.c:1285
int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize)
Definition zip.c:1501
ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize)
Definition zip.c:1604
unsigned long long zip_entry_dir_offset(struct zip_t *zip)
Definition zip.c:1493
ssize_t zip_entries_total(struct zip_t *zip)
Definition zip.c:1730
int zip_stream_extract(const char *stream, size_t size, const char *dir, int(*on_extract)(const char *filename, void *arg), void *arg)
Definition zip.c:1809
unsigned long long zip_entry_comp_size(struct zip_t *zip)
Definition zip.c:1485
Definition zip.c:110
Definition zip.c:82
Definition zip.c:98