CSEngine
Loading...
Searching...
No Matches
zip.cpp
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__) || defined(MSVC_CMAKE)
18/* Win32, DOS, MSVC, MSVS */
19#include <direct.h>
20
21#define MKDIR(DIRNAME) _mkdir(DIRNAME)
22#define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL)
23#define HAS_DEVICE(P) \
24 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \
25 (P)[1] == ':')
26#define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0)
27
28#else
29
30#include <unistd.h> // needed for symlink()
31
32#define MKDIR(DIRNAME) mkdir(DIRNAME, 0755)
33#define STRCLONE(STR) ((STR) ? strdup(STR) : NULL)
34
35#endif
36
37#ifdef __MINGW32__
38#include <sys/types.h>
39#include <unistd.h>
40#endif
41
42#include "miniz.h"
43#include "zip.h"
44
45#ifdef _MSC_VER
46#include <io.h>
47
48#define ftruncate(fd, sz) (-(_chsize_s((fd), (sz)) != 0))
49#define fileno _fileno
50#endif
51
52#ifndef HAS_DEVICE
53#define HAS_DEVICE(P) 0
54#endif
55
56#ifndef FILESYSTEM_PREFIX_LEN
57#define FILESYSTEM_PREFIX_LEN(P) 0
58#endif
59
60#ifndef ISSLASH
61#define ISSLASH(C) ((C) == '/' || (C) == '\\')
62#endif
63
64#define CLEANUP(ptr) \
65 do { \
66 if (ptr) { \
67 free((void *)ptr); \
68 ptr = NULL; \
69 } \
70 } while (0)
71
73 int index;
74 char *name;
75 mz_uint64 uncomp_size;
76 mz_uint64 comp_size;
77 mz_uint32 uncomp_crc32;
78 mz_uint64 offset;
79 mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
80 mz_uint64 header_offset;
81 mz_uint16 method;
84 mz_uint32 external_attr;
85 time_t m_time;
86};
87
88struct zip_t {
89 mz_zip_archive archive;
90 mz_uint level;
91 struct zip_entry_t entry;
92};
93
94enum zip_modify_t {
95 MZ_KEEP = 0,
96 MZ_DELETE = 1,
97 MZ_MOVE = 2,
98};
99
101 int file_index;
102 enum zip_modify_t type;
103 mz_uint64 m_local_header_ofs;
104 mz_uint64 lf_length;
105};
106
107static const char *const zip_errlist[30] = {
108 NULL,
109 "not initialized\0",
110 "invalid entry name\0",
111 "entry not found\0",
112 "invalid zip mode\0",
113 "invalid compression level\0",
114 "no zip 64 support\0",
115 "memset error\0",
116 "cannot write data to entry\0",
117 "cannot initialize tdefl compressor\0",
118 "invalid index\0",
119 "header not found\0",
120 "cannot flush tdefl buffer\0",
121 "cannot write entry header\0",
122 "cannot create entry header\0",
123 "cannot write to central dir\0",
124 "cannot open file\0",
125 "invalid entry type\0",
126 "extracting data using no memory allocation\0",
127 "file not found\0",
128 "no permission\0",
129 "out of memory\0",
130 "invalid zip archive name\0",
131 "make dir error\0"
132 "symlink error\0"
133 "close archive error\0"
134 "capacity size too small\0",
135 "fseek error\0",
136 "fread error\0",
137 "fwrite error\0",
138};
139
140const char *zip_strerror(int errnum) {
141 errnum = -errnum;
142 if (errnum <= 0 || errnum >= 30) {
143 return NULL;
144 }
145
146 return zip_errlist[errnum];
147}
148
149static const char *zip_basename(const char *name) {
150 char const *p;
151 char const *base = name += FILESYSTEM_PREFIX_LEN(name);
152 int all_slashes = 1;
153
154 for (p = name; *p; p++) {
155 if (ISSLASH(*p))
156 base = p + 1;
157 else
158 all_slashes = 0;
159 }
160
161 /* If NAME is all slashes, arrange to return `/'. */
162 if (*base == '\0' && ISSLASH(*name) && all_slashes)
163 --base;
164
165 return base;
166}
167
168static int zip_mkpath(char *path) {
169 char *p;
170 char npath[MAX_PATH + 1];
171 int len = 0;
172 int has_device = HAS_DEVICE(path);
173
174 memset(npath, 0, MAX_PATH + 1);
175 if (has_device) {
176 // only on windows
177 npath[0] = path[0];
178 npath[1] = path[1];
179 len = 2;
180 }
181 for (p = path + len; *p && len < MAX_PATH; p++) {
182 if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) {
183#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
184 defined(__MINGW32__)
185#else
186 if ('\\' == *p) {
187 *p = '/';
188 }
189#endif
190
191 if (MKDIR(npath) == -1) {
192 if (errno != EEXIST) {
193 return ZIP_EMKDIR;
194 }
195 }
196 }
197 npath[len++] = *p;
198 }
199
200 return 0;
201}
202
203static char *zip_strrpl(const char *str, size_t n, char oldchar, char newchar) {
204 char c;
205 size_t i;
206 char *rpl = (char *)calloc((1 + n), sizeof(char));
207 char *begin = rpl;
208 if (!rpl) {
209 return NULL;
210 }
211
212 for (i = 0; (i < n) && (c = *str++); ++i) {
213 if (c == oldchar) {
214 c = newchar;
215 }
216 *rpl++ = c;
217 }
218
219 return begin;
220}
221
222static char *zip_name_normalize(char *name, char *const nname, size_t len) {
223 size_t offn = 0;
224 size_t offnn = 0, ncpy = 0;
225
226 if (name == NULL || nname == NULL || len <= 0) {
227 return NULL;
228 }
229 // skip trailing '/'
230 while (ISSLASH(*name))
231 name++;
232
233 for (; offn < len; offn++) {
234 if (ISSLASH(name[offn])) {
235 if (ncpy > 0 && strcmp(&nname[offnn], ".\0") &&
236 strcmp(&nname[offnn], "..\0")) {
237 offnn += ncpy;
238 nname[offnn++] = name[offn]; // append '/'
239 }
240 ncpy = 0;
241 } else {
242 nname[offnn + ncpy] = name[offn];
243 ncpy++;
244 }
245 }
246
247 // at the end, extra check what we've already copied
248 if (ncpy == 0 || !strcmp(&nname[offnn], ".\0") ||
249 !strcmp(&nname[offnn], "..\0")) {
250 nname[offnn] = 0;
251 }
252 return nname;
253}
254
255static mz_bool zip_name_match(const char *name1, const char *name2) {
256 int len2 = strlen(name2);
257 char *nname2 = zip_strrpl(name2, len2, '\\', '/');
258 if (!nname2) {
259 return MZ_FALSE;
260 }
261
262 mz_bool res = (strcmp(name1, nname2) == 0) ? MZ_TRUE : MZ_FALSE;
263 CLEANUP(nname2);
264 return res;
265}
266
267static int zip_archive_truncate(mz_zip_archive *pzip) {
268 mz_zip_internal_state *pState = pzip->m_pState;
269 mz_uint64 file_size = pzip->m_archive_size;
270 if ((pzip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) {
271 return 0;
272 }
273 if (pzip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED) {
274 if (pState->m_pFile) {
275 int fd = fileno(pState->m_pFile);
276 return ftruncate(fd, file_size);
277 }
278 }
279 return 0;
280}
281
282static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir,
283 int (*on_extract)(const char *filename,
284 void *arg),
285 void *arg) {
286 int err = 0;
287 mz_uint i, n;
288 char path[MAX_PATH + 1];
289 char symlink_to[MAX_PATH + 1];
291 size_t dirlen = 0;
292 mz_uint32 xattr = 0;
293
294 memset(path, 0, sizeof(path));
295 memset(symlink_to, 0, sizeof(symlink_to));
296
297 dirlen = strlen(dir);
298 if (dirlen + 1 > MAX_PATH) {
299 return ZIP_EINVENTNAME;
300 }
301
302 memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat));
303
304#if defined(_MSC_VER)
305 strcpy_s(path, MAX_PATH, dir);
306#else
307 strcpy(path, dir);
308#endif
309
310 if (!ISSLASH(path[dirlen - 1])) {
311#if defined(_WIN32) || defined(__WIN32__)
312 path[dirlen] = '\\';
313#else
314 path[dirlen] = '/';
315#endif
316 ++dirlen;
317 }
318
319 // Get and print information about each file in the archive.
320 n = mz_zip_reader_get_num_files(zip_archive);
321 for (i = 0; i < n; ++i) {
322 if (!mz_zip_reader_file_stat(zip_archive, i, &info)) {
323 // Cannot get information about zip archive;
324 err = ZIP_ENOENT;
325 goto out;
326 }
327
328 if (!zip_name_normalize(info.m_filename, info.m_filename,
329 strlen(info.m_filename))) {
330 // Cannot normalize file name;
331 err = ZIP_EINVENTNAME;
332 goto out;
333 }
334#if defined(_MSC_VER)
335 strncpy_s(&path[dirlen], MAX_PATH - dirlen, info.m_filename,
336 MAX_PATH - dirlen);
337#else
338 strncpy(&path[dirlen], info.m_filename, MAX_PATH - dirlen);
339#endif
340 err = zip_mkpath(path);
341 if (err < 0) {
342 // Cannot make a path
343 goto out;
344 }
345
346 if ((((info.m_version_made_by >> 8) == 3) ||
347 ((info.m_version_made_by >> 8) ==
348 19)) // if zip is produced on Unix or macOS (3 and 19 from
349 // section 4.4.2.2 of zip standard)
350 && info.m_external_attr &
351 (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40
352 // is directory)
353#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
354 defined(__MINGW32__)
355#else
356 if (info.m_uncomp_size > MAX_PATH ||
357 !mz_zip_reader_extract_to_mem_no_alloc(zip_archive, i, symlink_to,
358 MAX_PATH, 0, NULL, 0)) {
359 err = ZIP_EMEMNOALLOC;
360 goto out;
361 }
362 symlink_to[info.m_uncomp_size] = '\0';
363 if (symlink(symlink_to, path) != 0) {
364 err = ZIP_ESYMLINK;
365 goto out;
366 }
367#endif
368 } else {
369 if (!mz_zip_reader_is_file_a_directory(zip_archive, i)) {
370 if (!mz_zip_reader_extract_to_file(zip_archive, i, path, 0)) {
371 // Cannot extract zip archive to file
372 err = ZIP_ENOFILE;
373 goto out;
374 }
375 }
376
377#if defined(_MSC_VER)
378 (void)xattr; // unused
379#else
380 xattr = (info.m_external_attr >> 16) & 0xFFFF;
381 if (xattr > 0) {
382 if (chmod(path, (mode_t)xattr) < 0) {
383 err = ZIP_ENOPERM;
384 goto out;
385 }
386 }
387#endif
388 }
389
390 if (on_extract) {
391 if (on_extract(path, arg) < 0) {
392 goto out;
393 }
394 }
395 }
396
397out:
398 // Close the archive, freeing any resources it was using
399 if (!mz_zip_reader_end(zip_archive)) {
400 // Cannot end zip reader
401 err = ZIP_ECLSZIP;
402 }
403 return err;
404}
405
406static inline void zip_archive_finalize(mz_zip_archive *pzip) {
407 mz_zip_writer_finalize_archive(pzip);
408 zip_archive_truncate(pzip);
409}
410
411static int zip_entry_mark(struct zip_t *zip,
412 struct zip_entry_mark_t *entry_mark, int n,
413 char *const entries[], const size_t len) {
414 int err = 0;
415 if (!zip || !entry_mark || !entries) {
416 return ZIP_ENOINIT;
417 }
418
419 mz_zip_archive_file_stat file_stat;
420 mz_uint64 d_pos = ~0;
421 for (int i = 0; i < n; ++i) {
422
423 if ((err = zip_entry_openbyindex(zip, i))) {
424 return err;
425 }
426
427 mz_bool name_matches = MZ_FALSE;
428 for (int j = 0; j < (const int)len; ++j) {
429 if (zip_name_match(zip->entry.name, entries[j])) {
430 name_matches = MZ_TRUE;
431 break;
432 }
433 }
434 if (name_matches) {
435 entry_mark[i].type = MZ_DELETE;
436 } else {
437 entry_mark[i].type = MZ_KEEP;
438 }
439
440 if (!mz_zip_reader_file_stat(&zip->archive, i, &file_stat)) {
441 return ZIP_ENOENT;
442 }
443
444 zip_entry_close(zip);
445
446 entry_mark[i].m_local_header_ofs = file_stat.m_local_header_ofs;
447 entry_mark[i].file_index = -1;
448 entry_mark[i].lf_length = 0;
449 if ((entry_mark[i].type) == MZ_DELETE &&
450 (d_pos > entry_mark[i].m_local_header_ofs)) {
451 d_pos = entry_mark[i].m_local_header_ofs;
452 }
453 }
454 for (int i = 0; i < n; ++i) {
455 if ((entry_mark[i].m_local_header_ofs > d_pos) &&
456 (entry_mark[i].type != MZ_DELETE)) {
457 entry_mark[i].type = MZ_MOVE;
458 }
459 }
460 return err;
461}
462
463static int zip_index_next(mz_uint64 *local_header_ofs_array, int cur_index) {
464 int new_index = 0;
465 for (int i = cur_index - 1; i >= 0; --i) {
466 if (local_header_ofs_array[cur_index] > local_header_ofs_array[i]) {
467 new_index = i + 1;
468 return new_index;
469 }
470 }
471 return new_index;
472}
473
474static int zip_sort(mz_uint64 *local_header_ofs_array, int cur_index) {
475 int nxt_index = zip_index_next(local_header_ofs_array, cur_index);
476
477 if (nxt_index != cur_index) {
478 mz_uint64 temp = local_header_ofs_array[cur_index];
479 for (int i = cur_index; i > nxt_index; i--) {
480 local_header_ofs_array[i] = local_header_ofs_array[i - 1];
481 }
482 local_header_ofs_array[nxt_index] = temp;
483 }
484 return nxt_index;
485}
486
487static int zip_index_update(struct zip_entry_mark_t *entry_mark, int last_index,
488 int nxt_index) {
489 for (int j = 0; j < last_index; j++) {
490 if (entry_mark[j].file_index >= nxt_index) {
491 entry_mark[j].file_index += 1;
492 }
493 }
494 entry_mark[nxt_index].file_index = last_index;
495 return 0;
496}
497
498static int zip_entry_finalize(struct zip_t *zip,
499 struct zip_entry_mark_t *entry_mark,
500 const int n) {
501
502 mz_uint64 *local_header_ofs_array = (mz_uint64 *)calloc(n, sizeof(mz_uint64));
503 if (!local_header_ofs_array) {
504 return ZIP_EOOMEM;
505 }
506
507 for (int i = 0; i < n; ++i) {
508 local_header_ofs_array[i] = entry_mark[i].m_local_header_ofs;
509 int index = zip_sort(local_header_ofs_array, i);
510
511 if (index != i) {
512 zip_index_update(entry_mark, i, index);
513 }
514 entry_mark[i].file_index = index;
515 }
516
517 mz_uint64 *length = (mz_uint64 *)calloc(n, sizeof(mz_uint64));
518 if (!length) {
519 CLEANUP(local_header_ofs_array);
520 return ZIP_EOOMEM;
521 }
522 for (int i = 0; i < n - 1; i++) {
523 length[i] = local_header_ofs_array[i + 1] - local_header_ofs_array[i];
524 }
525 length[n - 1] = zip->archive.m_archive_size - local_header_ofs_array[n - 1];
526
527 for (int i = 0; i < n; i++) {
528 entry_mark[i].lf_length = length[entry_mark[i].file_index];
529 }
530
531 CLEANUP(length);
532 CLEANUP(local_header_ofs_array);
533 return 0;
534}
535
536static int zip_entry_set(struct zip_t *zip, struct zip_entry_mark_t *entry_mark,
537 int n, char *const entries[], const size_t len) {
538 int err = 0;
539
540 if ((err = zip_entry_mark(zip, entry_mark, n, entries, len)) < 0) {
541 return err;
542 }
543 if ((err = zip_entry_finalize(zip, entry_mark, n)) < 0) {
544 return err;
545 }
546 return 0;
547}
548
549static mz_int64 zip_file_move(MZ_FILE *m_pFile, const mz_uint64 to,
550 const mz_uint64 from, const mz_uint64 length,
551 mz_uint8 *move_buf,
552 const mz_int64 capacity_size) {
553 if ((mz_int64)length > capacity_size) {
554 return ZIP_ECAPSIZE;
555 }
556 if (MZ_FSEEK64(m_pFile, from, SEEK_SET)) {
557 MZ_FCLOSE(m_pFile);
558 return ZIP_EFSEEK;
559 }
560
561 if (fread(move_buf, 1, length, m_pFile) != length) {
562 MZ_FCLOSE(m_pFile);
563 return ZIP_EFREAD;
564 }
565 if (MZ_FSEEK64(m_pFile, to, SEEK_SET)) {
566 MZ_FCLOSE(m_pFile);
567 return ZIP_EFSEEK;
568 }
569 if (fwrite(move_buf, 1, length, m_pFile) != length) {
570 MZ_FCLOSE(m_pFile);
571 return ZIP_EFWRITE;
572 }
573 return (mz_int64)length;
574}
575
576static mz_int64 zip_files_move(MZ_FILE *m_pFile, mz_uint64 writen_num,
577 mz_uint64 read_num, mz_uint64 length) {
578 int n = 0;
579 const mz_int64 page_size = 1 << 12; // 4K
580 mz_uint8 *move_buf = (mz_uint8 *)calloc(1, page_size);
581 if (move_buf == NULL) {
582 return ZIP_EOOMEM;
583 }
584
585 mz_int64 moved_length = 0;
586 mz_int64 move_count = 0;
587 while ((mz_int64)length > 0) {
588 move_count = ((mz_int64)length >= page_size) ? page_size : (mz_int64)length;
589 n = zip_file_move(m_pFile, writen_num, read_num, move_count, move_buf,
590 page_size);
591 if (n < 0) {
592 moved_length = n;
593 goto cleanup;
594 }
595
596 if (n != move_count) {
597 goto cleanup;
598 }
599
600 writen_num += move_count;
601 read_num += move_count;
602 length -= move_count;
603 moved_length += move_count;
604 }
605
606cleanup:
607 CLEANUP(move_buf);
608 return moved_length;
609}
610
611static int zip_central_dir_move(mz_zip_internal_state *pState, int begin,
612 int end, int entry_num) {
613 if (begin == entry_num) {
614 return 0;
615 }
616
617 mz_uint64 l_size = 0;
618 mz_uint64 r_size = 0;
619 mz_uint64 d_size = 0;
620 mz_uint8 *next = NULL;
621 mz_uint8 *deleted = &MZ_ZIP_ARRAY_ELEMENT(
622 &pState->m_central_dir, mz_uint8,
623 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, begin));
624 l_size = (mz_uint32)(deleted - (mz_uint8 *)(pState->m_central_dir.m_p));
625 if (end == entry_num) {
626 r_size = 0;
627 } else {
628 next = &MZ_ZIP_ARRAY_ELEMENT(
629 &pState->m_central_dir, mz_uint8,
630 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, end));
631 r_size = pState->m_central_dir.m_size -
632 (mz_uint32)(next - (mz_uint8 *)(pState->m_central_dir.m_p));
633 d_size = next - deleted;
634 }
635
636 if (l_size == 0) {
637 memmove(pState->m_central_dir.m_p, next, r_size);
638 pState->m_central_dir.m_p = MZ_REALLOC(pState->m_central_dir.m_p, r_size);
639 for (int i = end; i < entry_num; i++) {
640 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i) -=
641 d_size;
642 }
643 }
644
645 if (l_size * r_size != 0) {
646 memmove(deleted, next, r_size);
647 for (int i = end; i < entry_num; i++) {
648 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i) -=
649 d_size;
650 }
651 }
652
653 pState->m_central_dir.m_size = l_size + r_size;
654 return 0;
655}
656
657static int zip_central_dir_delete(mz_zip_internal_state *pState,
658 int *deleted_entry_index_array,
659 int entry_num) {
660 int i = 0;
661 int begin = 0;
662 int end = 0;
663 int d_num = 0;
664 while (i < entry_num) {
665 while ((!deleted_entry_index_array[i]) && (i < entry_num)) {
666 i++;
667 }
668 begin = i;
669
670 while ((deleted_entry_index_array[i]) && (i < entry_num)) {
671 i++;
672 }
673 end = i;
674 zip_central_dir_move(pState, begin, end, entry_num);
675 }
676
677 i = 0;
678 while (i < entry_num) {
679 while ((!deleted_entry_index_array[i]) && (i < entry_num)) {
680 i++;
681 }
682 begin = i;
683 if (begin == entry_num) {
684 break;
685 }
686 while ((deleted_entry_index_array[i]) && (i < entry_num)) {
687 i++;
688 }
689 end = i;
690 int k = 0;
691 for (int j = end; j < entry_num; j++) {
692 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32,
693 begin + k) =
694 (mz_uint32)MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets,
695 mz_uint32, j);
696 k++;
697 }
698 d_num += end - begin;
699 }
700
701 pState->m_central_dir_offsets.m_size =
702 sizeof(mz_uint32) * (entry_num - d_num);
703 return 0;
704}
705
706static int zip_entries_delete_mark(struct zip_t *zip,
707 struct zip_entry_mark_t *entry_mark,
708 int entry_num) {
709 mz_uint64 writen_num = 0;
710 mz_uint64 read_num = 0;
711 mz_uint64 deleted_length = 0;
712 mz_uint64 move_length = 0;
713 int i = 0;
714 int deleted_entry_num = 0;
715 int n = 0;
716
717 mz_bool *deleted_entry_flag_array =
718 (mz_bool *)calloc(entry_num, sizeof(mz_bool));
719 if (deleted_entry_flag_array == NULL) {
720 return ZIP_EOOMEM;
721 }
722
723 mz_zip_internal_state *pState = zip->archive.m_pState;
724 zip->archive.m_zip_mode = MZ_ZIP_MODE_WRITING;
725
726 if (MZ_FSEEK64(pState->m_pFile, 0, SEEK_SET)) {
727 CLEANUP(deleted_entry_flag_array);
728 return ZIP_ENOENT;
729 }
730
731 while (i < entry_num) {
732 while ((entry_mark[i].type == MZ_KEEP) && (i < entry_num)) {
733 writen_num += entry_mark[i].lf_length;
734 read_num = writen_num;
735 i++;
736 }
737
738 while ((entry_mark[i].type == MZ_DELETE) && (i < entry_num)) {
739 deleted_entry_flag_array[i] = MZ_TRUE;
740 read_num += entry_mark[i].lf_length;
741 deleted_length += entry_mark[i].lf_length;
742 i++;
743 deleted_entry_num++;
744 }
745
746 while ((entry_mark[i].type == MZ_MOVE) && (i < entry_num)) {
747 move_length += entry_mark[i].lf_length;
748 mz_uint8 *p = &MZ_ZIP_ARRAY_ELEMENT(
749 &pState->m_central_dir, mz_uint8,
750 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i));
751 if (!p) {
752 CLEANUP(deleted_entry_flag_array);
753 return ZIP_ENOENT;
754 }
755 mz_uint32 offset = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
756 offset -= (mz_uint32)deleted_length;
757 MZ_WRITE_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS, offset);
758 i++;
759 }
760
761 n = zip_files_move(pState->m_pFile, writen_num, read_num, move_length);
762 if (n != (mz_int64)move_length) {
763 CLEANUP(deleted_entry_flag_array);
764 return n;
765 }
766 writen_num += move_length;
767 read_num += move_length;
768 }
769
770 zip->archive.m_archive_size -= deleted_length;
771 zip->archive.m_total_files = entry_num - deleted_entry_num;
772
773 zip_central_dir_delete(pState, deleted_entry_flag_array, entry_num);
774 CLEANUP(deleted_entry_flag_array);
775
776 return deleted_entry_num;
777}
778
779struct zip_t *zip_open(const char *zipname, int level, char mode) {
780 struct zip_t *zip = NULL;
781
782 if (!zipname || strlen(zipname) < 1) {
783 // zip_t archive name is empty or NULL
784 goto cleanup;
785 }
786
787 if (level < 0)
788 level = MZ_DEFAULT_LEVEL;
789 if ((level & 0xF) > MZ_UBER_COMPRESSION) {
790 // Wrong compression level
791 goto cleanup;
792 }
793
794 zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
795 if (!zip)
796 goto cleanup;
797
798 zip->level = (mz_uint)level;
799 switch (mode) {
800 case 'w':
801 // Create a new archive.
802 if (!mz_zip_writer_init_file(&(zip->archive), zipname, 0)) {
803 // Cannot initialize zip_archive writer
804 goto cleanup;
805 }
806 break;
807
808 case 'r':
809 case 'a':
810 case 'd':
811 if (!mz_zip_reader_init_file(
812 &(zip->archive), zipname,
813 zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) {
814 // An archive file does not exist or cannot initialize
815 // zip_archive reader
816 goto cleanup;
817 }
818 if ((mode == 'a' || mode == 'd') &&
819 !mz_zip_writer_init_from_reader(&(zip->archive), zipname)) {
820 mz_zip_reader_end(&(zip->archive));
821 goto cleanup;
822 }
823 break;
824
825 default:
826 goto cleanup;
827 }
828
829 return zip;
830
831cleanup:
832 CLEANUP(zip);
833 return NULL;
834}
835
836void zip_close(struct zip_t *zip) {
837 if (zip) {
838 // Always finalize, even if adding failed for some reason, so we have a
839 // valid central directory.
840 mz_zip_writer_finalize_archive(&(zip->archive));
841 zip_archive_truncate(&(zip->archive));
842 mz_zip_writer_end(&(zip->archive));
843 mz_zip_reader_end(&(zip->archive));
844
845 CLEANUP(zip);
846 }
847}
848
849int zip_is64(struct zip_t *zip) {
850 if (!zip || !zip->archive.m_pState) {
851 // zip_t handler or zip state is not initialized
852 return ZIP_ENOINIT;
853 }
854
855 return (int)zip->archive.m_pState->m_zip64;
856}
857
858int zip_entry_open(struct zip_t *zip, const char *entryname) {
859 size_t entrylen = 0;
860 mz_zip_archive *pzip = NULL;
861 mz_uint num_alignment_padding_bytes, level;
863 int err = 0;
864
865 if (!zip) {
866 return ZIP_ENOINIT;
867 }
868
869 if (!entryname) {
870 return ZIP_EINVENTNAME;
871 }
872
873 entrylen = strlen(entryname);
874 if (entrylen == 0) {
875 return ZIP_EINVENTNAME;
876 }
877
878 /*
879 .ZIP File Format Specification Version: 6.3.3
880
881 4.4.17.1 The name of the file, with optional relative path.
882 The path stored MUST not contain a drive or
883 device letter, or a leading slash. All slashes
884 MUST be forward slashes '/' as opposed to
885 backwards slashes '\' for compatibility with Amiga
886 and UNIX file systems etc. If input came from standard
887 input, there is no file name field.
888 */
889 if (zip->entry.name) {
890 CLEANUP(zip->entry.name);
891 }
892 zip->entry.name = zip_strrpl(entryname, entrylen, '\\', '/');
893 if (!zip->entry.name) {
894 // Cannot parse zip entry name
895 return ZIP_EINVENTNAME;
896 }
897
898 pzip = &(zip->archive);
899 if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) {
900 zip->entry.index =
901 mz_zip_reader_locate_file(pzip, zip->entry.name, NULL, 0);
902 if (zip->entry.index < 0) {
903 err = ZIP_ENOENT;
904 goto cleanup;
905 }
906
907 if (!mz_zip_reader_file_stat(pzip, (mz_uint)zip->entry.index, &stats)) {
908 err = ZIP_ENOENT;
909 goto cleanup;
910 }
911
912 zip->entry.comp_size = stats.m_comp_size;
913 zip->entry.uncomp_size = stats.m_uncomp_size;
914 zip->entry.uncomp_crc32 = stats.m_crc32;
915 zip->entry.offset = stats.m_central_dir_ofs;
916 zip->entry.header_offset = stats.m_local_header_ofs;
917 zip->entry.method = stats.m_method;
918 zip->entry.external_attr = stats.m_external_attr;
919#ifndef MINIZ_NO_TIME
920 zip->entry.m_time = stats.m_time;
921#endif
922
923 return 0;
924 }
925
926 zip->entry.index = (int)zip->archive.m_total_files;
927 zip->entry.comp_size = 0;
928 zip->entry.uncomp_size = 0;
929 zip->entry.uncomp_crc32 = MZ_CRC32_INIT;
930 zip->entry.offset = zip->archive.m_archive_size;
931 zip->entry.header_offset = zip->archive.m_archive_size;
932 memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
933 zip->entry.method = 0;
934
935 // UNIX or APPLE
936#if MZ_PLATFORM == 3 || MZ_PLATFORM == 19
937 // regular file with rw-r--r-- persmissions
938 zip->entry.external_attr = (mz_uint32)(0100644) << 16;
939#else
940 zip->entry.external_attr = 0;
941#endif
942
943 num_alignment_padding_bytes =
944 mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
945
946 if (!pzip->m_pState || (pzip->m_zip_mode != MZ_ZIP_MODE_WRITING)) {
947 // Invalid zip mode
948 err = ZIP_EINVMODE;
949 goto cleanup;
950 }
951 if (zip->level & MZ_ZIP_FLAG_COMPRESSED_DATA) {
952 // Invalid zip compression level
953 err = ZIP_EINVLVL;
954 goto cleanup;
955 }
956 // no zip64 support yet
957 if ((pzip->m_total_files == 0xFFFF) ||
958 ((pzip->m_archive_size + num_alignment_padding_bytes +
959 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
960 entrylen) > 0xFFFFFFFF)) {
961 // No zip64 support yet
962 err = ZIP_ENOSUP64;
963 goto cleanup;
964 }
965 if (!mz_zip_writer_write_zeros(pzip, zip->entry.offset,
966 num_alignment_padding_bytes +
967 sizeof(zip->entry.header))) {
968 // Cannot memset zip entry header
969 err = ZIP_EMEMSET;
970 goto cleanup;
971 }
972
973 zip->entry.header_offset += num_alignment_padding_bytes;
974 if (pzip->m_file_offset_alignment) {
975 MZ_ASSERT(
976 (zip->entry.header_offset & (pzip->m_file_offset_alignment - 1)) == 0);
977 }
978 zip->entry.offset += num_alignment_padding_bytes + sizeof(zip->entry.header);
979
980 if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, zip->entry.name,
981 entrylen) != entrylen) {
982 // Cannot write data to zip entry
983 err = ZIP_EWRTENT;
984 goto cleanup;
985 }
986
987 zip->entry.offset += entrylen;
988 level = zip->level & 0xF;
989 if (level) {
990 zip->entry.state.m_pZip = pzip;
991 zip->entry.state.m_cur_archive_file_ofs = zip->entry.offset;
992 zip->entry.state.m_comp_size = 0;
993
994 if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback,
995 &(zip->entry.state),
996 (int)tdefl_create_comp_flags_from_zip_params(
997 (int)level, -15, MZ_DEFAULT_STRATEGY)) !=
998 TDEFL_STATUS_OKAY) {
999 // Cannot initialize the zip compressor
1000 err = ZIP_ETDEFLINIT;
1001 goto cleanup;
1002 }
1003 }
1004
1005 zip->entry.m_time = time(NULL);
1006
1007 return 0;
1008
1009cleanup:
1010 CLEANUP(zip->entry.name);
1011 return err;
1012}
1013
1014int zip_entry_openbyindex(struct zip_t *zip, int index) {
1015 mz_zip_archive *pZip = NULL;
1017 mz_uint namelen;
1018 const mz_uint8 *pHeader;
1019 const char *pFilename;
1020
1021 if (!zip) {
1022 // zip_t handler is not initialized
1023 return ZIP_ENOINIT;
1024 }
1025
1026 pZip = &(zip->archive);
1027 if (pZip->m_zip_mode != MZ_ZIP_MODE_READING) {
1028 // open by index requires readonly mode
1029 return ZIP_EINVMODE;
1030 }
1031
1032 if (index < 0 || (mz_uint)index >= pZip->m_total_files) {
1033 // index out of range
1034 return ZIP_EINVIDX;
1035 }
1036
1037 if (!(pHeader = &MZ_ZIP_ARRAY_ELEMENT(
1038 &pZip->m_pState->m_central_dir, mz_uint8,
1039 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets,
1040 mz_uint32, index)))) {
1041 // cannot find header in central directory
1042 return ZIP_ENOHDR;
1043 }
1044
1045 namelen = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
1046 pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
1047
1048 /*
1049 .ZIP File Format Specification Version: 6.3.3
1050
1051 4.4.17.1 The name of the file, with optional relative path.
1052 The path stored MUST not contain a drive or
1053 device letter, or a leading slash. All slashes
1054 MUST be forward slashes '/' as opposed to
1055 backwards slashes '\' for compatibility with Amiga
1056 and UNIX file systems etc. If input came from standard
1057 input, there is no file name field.
1058 */
1059 if (zip->entry.name) {
1060 CLEANUP(zip->entry.name);
1061 }
1062 zip->entry.name = zip_strrpl(pFilename, namelen, '\\', '/');
1063 if (!zip->entry.name) {
1064 // local entry name is NULL
1065 return ZIP_EINVENTNAME;
1066 }
1067
1068 if (!mz_zip_reader_file_stat(pZip, (mz_uint)index, &stats)) {
1069 return ZIP_ENOENT;
1070 }
1071
1072 zip->entry.index = index;
1073 zip->entry.comp_size = stats.m_comp_size;
1074 zip->entry.uncomp_size = stats.m_uncomp_size;
1075 zip->entry.uncomp_crc32 = stats.m_crc32;
1076 zip->entry.offset = stats.m_central_dir_ofs;
1077 zip->entry.header_offset = stats.m_local_header_ofs;
1078 zip->entry.method = stats.m_method;
1079 zip->entry.external_attr = stats.m_external_attr;
1080#ifndef MINIZ_NO_TIME
1081 zip->entry.m_time = stats.m_time;
1082#endif
1083
1084 return 0;
1085}
1086
1087int zip_entry_close(struct zip_t *zip) {
1088 mz_zip_archive *pzip = NULL;
1089 mz_uint level;
1090 tdefl_status done;
1091 mz_uint16 entrylen;
1092 mz_uint16 dos_time = 0, dos_date = 0;
1093 int err = 0;
1094
1095 if (!zip) {
1096 // zip_t handler is not initialized
1097 err = ZIP_ENOINIT;
1098 goto cleanup;
1099 }
1100
1101 pzip = &(zip->archive);
1102 if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) {
1103 goto cleanup;
1104 }
1105
1106 level = zip->level & 0xF;
1107 if (level) {
1108 done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH);
1109 if (done != TDEFL_STATUS_DONE && done != TDEFL_STATUS_OKAY) {
1110 // Cannot flush compressed buffer
1111 err = ZIP_ETDEFLBUF;
1112 goto cleanup;
1113 }
1114 zip->entry.comp_size = zip->entry.state.m_comp_size;
1115 zip->entry.offset = zip->entry.state.m_cur_archive_file_ofs;
1116 zip->entry.method = MZ_DEFLATED;
1117 }
1118
1119 entrylen = (mz_uint16)strlen(zip->entry.name);
1120 if ((zip->entry.comp_size > 0xFFFFFFFF) || (zip->entry.offset > 0xFFFFFFFF)) {
1121 // No zip64 support, yet
1122 err = ZIP_ENOSUP64;
1123 goto cleanup;
1124 }
1125
1126#ifndef MINIZ_NO_TIME
1127 mz_zip_time_t_to_dos_time(zip->entry.m_time, &dos_time, &dos_date);
1128#endif
1129
1130 if (!mz_zip_writer_create_local_dir_header(
1131 pzip, zip->entry.header, entrylen, 0, zip->entry.uncomp_size,
1132 zip->entry.comp_size, zip->entry.uncomp_crc32, zip->entry.method, 0,
1133 dos_time, dos_date)) {
1134 // Cannot create zip entry header
1135 err = ZIP_ECRTHDR;
1136 goto cleanup;
1137 }
1138
1139 if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset,
1140 zip->entry.header,
1141 sizeof(zip->entry.header)) != sizeof(zip->entry.header)) {
1142 // Cannot write zip entry header
1143 err = ZIP_EWRTHDR;
1144 goto cleanup;
1145 }
1146
1147 if (!mz_zip_writer_add_to_central_dir(
1148 pzip, zip->entry.name, entrylen, NULL, 0, "", 0,
1149 zip->entry.uncomp_size, zip->entry.comp_size, zip->entry.uncomp_crc32,
1150 zip->entry.method, 0, dos_time, dos_date, zip->entry.header_offset,
1151 zip->entry.external_attr)) {
1152 // Cannot write to zip central dir
1153 err = ZIP_EWRTDIR;
1154 goto cleanup;
1155 }
1156
1157 pzip->m_total_files++;
1158 pzip->m_archive_size = zip->entry.offset;
1159
1160cleanup:
1161 if (zip) {
1162 zip->entry.m_time = 0;
1163 CLEANUP(zip->entry.name);
1164 }
1165 return err;
1166}
1167
1168const char *zip_entry_name(struct zip_t *zip) {
1169 if (!zip) {
1170 // zip_t handler is not initialized
1171 return NULL;
1172 }
1173
1174 return zip->entry.name;
1175}
1176
1177int zip_entry_index(struct zip_t *zip) {
1178 if (!zip) {
1179 // zip_t handler is not initialized
1180 return ZIP_ENOINIT;
1181 }
1182
1183 return zip->entry.index;
1184}
1185
1186int zip_entry_isdir(struct zip_t *zip) {
1187 if (!zip) {
1188 // zip_t handler is not initialized
1189 return ZIP_ENOINIT;
1190 }
1191
1192 if (zip->entry.index < 0) {
1193 // zip entry is not opened
1194 return ZIP_EINVIDX;
1195 }
1196
1197 return (int)mz_zip_reader_is_file_a_directory(&zip->archive,
1198 (mz_uint)zip->entry.index);
1199}
1200
1201unsigned long long zip_entry_size(struct zip_t *zip) {
1202 return zip ? zip->entry.uncomp_size : 0;
1203}
1204
1205unsigned int zip_entry_crc32(struct zip_t *zip) {
1206 return zip ? zip->entry.uncomp_crc32 : 0;
1207}
1208
1209int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) {
1210 mz_uint level;
1211 mz_zip_archive *pzip = NULL;
1212 tdefl_status status;
1213
1214 if (!zip) {
1215 // zip_t handler is not initialized
1216 return ZIP_ENOINIT;
1217 }
1218
1219 pzip = &(zip->archive);
1220 if (buf && bufsize > 0) {
1221 zip->entry.uncomp_size += bufsize;
1222 zip->entry.uncomp_crc32 = (mz_uint32)mz_crc32(
1223 zip->entry.uncomp_crc32, (const mz_uint8 *)buf, bufsize);
1224
1225 level = zip->level & 0xF;
1226 if (!level) {
1227 if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, buf,
1228 bufsize) != bufsize)) {
1229 // Cannot write buffer
1230 return ZIP_EWRTENT;
1231 }
1232 zip->entry.offset += bufsize;
1233 zip->entry.comp_size += bufsize;
1234 } else {
1235 status = tdefl_compress_buffer(&(zip->entry.comp), buf, bufsize,
1236 TDEFL_NO_FLUSH);
1237 if (status != TDEFL_STATUS_DONE && status != TDEFL_STATUS_OKAY) {
1238 // Cannot compress buffer
1239 return ZIP_ETDEFLBUF;
1240 }
1241 }
1242 }
1243
1244 return 0;
1245}
1246
1247int zip_entry_fwrite(struct zip_t *zip, const char *filename) {
1248 int err = 0;
1249 size_t n = 0;
1250 FILE *stream = NULL;
1251 mz_uint8 buf[MZ_ZIP_MAX_IO_BUF_SIZE];
1252 struct MZ_FILE_STAT_STRUCT file_stat;
1253
1254 if (!zip) {
1255 // zip_t handler is not initialized
1256 return ZIP_ENOINIT;
1257 }
1258
1259 memset(buf, 0, MZ_ZIP_MAX_IO_BUF_SIZE);
1260 memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT));
1261 if (MZ_FILE_STAT(filename, &file_stat) != 0) {
1262 // problem getting information - check errno
1263 return ZIP_ENOENT;
1264 }
1265
1266 if ((file_stat.st_mode & 0200) == 0) {
1267 // MS-DOS read-only attribute
1268 zip->entry.external_attr |= 0x01;
1269 }
1270 zip->entry.external_attr |= (mz_uint32)((file_stat.st_mode & 0xFFFF) << 16);
1271 zip->entry.m_time = file_stat.st_mtime;
1272
1273#if defined(_MSC_VER)
1274 if (fopen_s(&stream, filename, "rb"))
1275#else
1276 if (!(stream = fopen(filename, "rb")))
1277#endif
1278 {
1279 // Cannot open filename
1280 return ZIP_EOPNFILE;
1281 }
1282
1283 while ((n = fread(buf, sizeof(mz_uint8), MZ_ZIP_MAX_IO_BUF_SIZE, stream)) >
1284 0) {
1285 if (zip_entry_write(zip, buf, n) < 0) {
1286 err = ZIP_EWRTENT;
1287 break;
1288 }
1289 }
1290 fclose(stream);
1291
1292 return err;
1293}
1294
1295ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) {
1296 mz_zip_archive *pzip = NULL;
1297 mz_uint idx;
1298 size_t size = 0;
1299
1300 if (!zip) {
1301 // zip_t handler is not initialized
1302 return ZIP_ENOINIT;
1303 }
1304
1305 pzip = &(zip->archive);
1306 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) {
1307 // the entry is not found or we do not have read access
1308 return ZIP_ENOENT;
1309 }
1310
1311 idx = (mz_uint)zip->entry.index;
1312 if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
1313 // the entry is a directory
1314 return ZIP_EINVENTTYPE;
1315 }
1316
1317 *buf = mz_zip_reader_extract_to_heap(pzip, idx, &size, 0);
1318 if (*buf && bufsize) {
1319 *bufsize = size;
1320 }
1321 return size;
1322}
1323
1324ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
1325 mz_zip_archive *pzip = NULL;
1326
1327 if (!zip) {
1328 // zip_t handler is not initialized
1329 return ZIP_ENOINIT;
1330 }
1331
1332 pzip = &(zip->archive);
1333 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) {
1334 // the entry is not found or we do not have read access
1335 return ZIP_ENOENT;
1336 }
1337
1338 if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index,
1339 buf, bufsize, 0, NULL, 0)) {
1340 return ZIP_EMEMNOALLOC;
1341 }
1342
1343 return (ssize_t)zip->entry.uncomp_size;
1344}
1345
1346int zip_entry_fread(struct zip_t *zip, const char *filename) {
1347 mz_zip_archive *pzip = NULL;
1348 mz_uint idx;
1349 mz_uint32 xattr = 0;
1351
1352 if (!zip) {
1353 // zip_t handler is not initialized
1354 return ZIP_ENOINIT;
1355 }
1356
1357 memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat));
1358 pzip = &(zip->archive);
1359 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) {
1360 // the entry is not found or we do not have read access
1361 return ZIP_ENOENT;
1362 }
1363
1364 idx = (mz_uint)zip->entry.index;
1365 if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
1366 // the entry is a directory
1367 return ZIP_EINVENTTYPE;
1368 }
1369
1370 if (!mz_zip_reader_extract_to_file(pzip, idx, filename, 0)) {
1371 return ZIP_ENOFILE;
1372 }
1373
1374#if defined(_MSC_VER)
1375 (void)xattr; // unused
1376#else
1377 if (!mz_zip_reader_file_stat(pzip, idx, &info)) {
1378 // Cannot get information about zip archive;
1379 return ZIP_ENOFILE;
1380 }
1381
1382 xattr = (info.m_external_attr >> 16) & 0xFFFF;
1383 if (xattr > 0) {
1384 if (chmod(filename, (mode_t)xattr) < 0) {
1385 return ZIP_ENOPERM;
1386 }
1387 }
1388#endif
1389
1390 return 0;
1391}
1392
1393int zip_entry_extract(struct zip_t *zip,
1394 size_t (*on_extract)(void *arg, unsigned long long offset,
1395 const void *buf, size_t bufsize),
1396 void *arg) {
1397 mz_zip_archive *pzip = NULL;
1398 mz_uint idx;
1399
1400 if (!zip) {
1401 // zip_t handler is not initialized
1402 return ZIP_ENOINIT;
1403 }
1404
1405 pzip = &(zip->archive);
1406 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) {
1407 // the entry is not found or we do not have read access
1408 return ZIP_ENOENT;
1409 }
1410
1411 idx = (mz_uint)zip->entry.index;
1412 return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0))
1413 ? 0
1414 : ZIP_EINVIDX;
1415}
1416
1417int zip_entries_total(struct zip_t *zip) {
1418 if (!zip) {
1419 // zip_t handler is not initialized
1420 return ZIP_ENOINIT;
1421 }
1422
1423 return (int)zip->archive.m_total_files;
1424}
1425
1426int zip_entries_delete(struct zip_t *zip, char *const entries[],
1427 const size_t len) {
1428 int n = 0;
1429 int err = 0;
1430 struct zip_entry_mark_t *entry_mark = NULL;
1431
1432 if (zip == NULL || (entries == NULL && len != 0)) {
1433 return ZIP_ENOINIT;
1434 }
1435
1436 if (entries == NULL && len == 0) {
1437 return 0;
1438 }
1439
1440 n = zip_entries_total(zip);
1441
1442 entry_mark =
1443 (struct zip_entry_mark_t *)calloc(n, sizeof(struct zip_entry_mark_t));
1444 if (!entry_mark) {
1445 return ZIP_EOOMEM;
1446 }
1447
1448 zip->archive.m_zip_mode = MZ_ZIP_MODE_READING;
1449
1450 err = zip_entry_set(zip, entry_mark, n, entries, len);
1451 if (err < 0) {
1452 CLEANUP(entry_mark);
1453 return err;
1454 }
1455
1456 err = zip_entries_delete_mark(zip, entry_mark, n);
1457 CLEANUP(entry_mark);
1458 return err;
1459}
1460
1461int zip_stream_extract(const char *stream, size_t size, const char *dir,
1462 int (*on_extract)(const char *filename, void *arg),
1463 void *arg) {
1464 mz_zip_archive zip_archive;
1465 if (!stream || !dir) {
1466 // Cannot parse zip archive stream
1467 return ZIP_ENOINIT;
1468 }
1469 if (!memset(&zip_archive, 0, sizeof(mz_zip_archive))) {
1470 // Cannot memset zip archive
1471 return ZIP_EMEMSET;
1472 }
1473 if (!mz_zip_reader_init_mem(&zip_archive, stream, size, 0)) {
1474 // Cannot initialize zip_archive reader
1475 return ZIP_ENOINIT;
1476 }
1477
1478 return zip_archive_extract(&zip_archive, dir, on_extract, arg);
1479}
1480
1481struct zip_t *zip_stream_open(const char *stream, size_t size, int level,
1482 char mode) {
1483 struct zip_t *zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
1484 if (!zip) {
1485 return NULL;
1486 }
1487
1488 if (level < 0) {
1489 level = MZ_DEFAULT_LEVEL;
1490 }
1491 if ((level & 0xF) > MZ_UBER_COMPRESSION) {
1492 // Wrong compression level
1493 goto cleanup;
1494 }
1495 zip->level = (mz_uint)level;
1496
1497 if ((stream != NULL) && (size > 0) && (mode == 'r')) {
1498 if (!mz_zip_reader_init_mem(&(zip->archive), stream, size, 0)) {
1499 goto cleanup;
1500 }
1501 } else if ((stream == NULL) && (size == 0) && (mode == 'w')) {
1502 // Create a new archive.
1503 if (!mz_zip_writer_init_heap(&(zip->archive), 0, 1024)) {
1504 // Cannot initialize zip_archive writer
1505 goto cleanup;
1506 }
1507 } else {
1508 goto cleanup;
1509 }
1510 return zip;
1511
1512cleanup:
1513 CLEANUP(zip);
1514 return NULL;
1515}
1516
1517ssize_t zip_stream_copy(struct zip_t *zip, void **buf, ssize_t *bufsize) {
1518 if (!zip) {
1519 return ZIP_ENOINIT;
1520 }
1521
1522 zip_archive_finalize(&(zip->archive));
1523
1524 if (bufsize != NULL) {
1525 *bufsize = zip->archive.m_archive_size;
1526 }
1527 *buf = calloc(sizeof(unsigned char), zip->archive.m_archive_size);
1528 memcpy(*buf, zip->archive.m_pState->m_pMem, zip->archive.m_archive_size);
1529
1530 return zip->archive.m_archive_size;
1531}
1532
1533void zip_stream_close(struct zip_t *zip) {
1534 if (zip) {
1535 mz_zip_writer_end(&(zip->archive));
1536 mz_zip_reader_end(&(zip->archive));
1537 CLEANUP(zip);
1538 }
1539}
1540
1541int zip_create(const char *zipname, const char *filenames[], size_t len) {
1542 int err = 0;
1543 size_t i;
1544 mz_zip_archive zip_archive;
1545 struct MZ_FILE_STAT_STRUCT file_stat;
1546 mz_uint32 ext_attributes = 0;
1547
1548 if (!zipname || strlen(zipname) < 1) {
1549 // zip_t archive name is empty or NULL
1550 return ZIP_EINVZIPNAME;
1551 }
1552
1553 // Create a new archive.
1554 if (!memset(&(zip_archive), 0, sizeof(zip_archive))) {
1555 // Cannot memset zip archive
1556 return ZIP_EMEMSET;
1557 }
1558
1559 if (!mz_zip_writer_init_file(&zip_archive, zipname, 0)) {
1560 // Cannot initialize zip_archive writer
1561 return ZIP_ENOINIT;
1562 }
1563
1564 if (!memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT))) {
1565 return ZIP_EMEMSET;
1566 }
1567
1568 for (i = 0; i < len; ++i) {
1569 const char *name = filenames[i];
1570 if (!name) {
1571 err = ZIP_EINVENTNAME;
1572 break;
1573 }
1574
1575 if (MZ_FILE_STAT(name, &file_stat) != 0) {
1576 // problem getting information - check errno
1577 err = ZIP_ENOFILE;
1578 break;
1579 }
1580
1581 if ((file_stat.st_mode & 0200) == 0) {
1582 // MS-DOS read-only attribute
1583 ext_attributes |= 0x01;
1584 }
1585 ext_attributes |= (mz_uint32)((file_stat.st_mode & 0xFFFF) << 16);
1586
1587 if (!mz_zip_writer_add_file(&zip_archive, zip_basename(name), name, "", 0,
1589 ext_attributes)) {
1590 // Cannot add file to zip_archive
1591 err = ZIP_ENOFILE;
1592 break;
1593 }
1594 }
1595
1596 mz_zip_writer_finalize_archive(&zip_archive);
1597 mz_zip_writer_end(&zip_archive);
1598 return err;
1599}
1600
1601int zip_extract(const char *zipname, const char *dir,
1602 int (*on_extract)(const char *filename, void *arg), void *arg) {
1603 mz_zip_archive zip_archive;
1604
1605 if (!zipname || !dir) {
1606 // Cannot parse zip archive name
1607 return ZIP_EINVZIPNAME;
1608 }
1609
1610 if (!memset(&zip_archive, 0, sizeof(mz_zip_archive))) {
1611 // Cannot memset zip archive
1612 return ZIP_EMEMSET;
1613 }
1614
1615 // Now try to open the archive.
1616 if (!mz_zip_reader_init_file(&zip_archive, zipname, 0)) {
1617 // Cannot initialize zip_archive reader
1618 return ZIP_ENOINIT;
1619 }
1620
1621 return zip_archive_extract(&zip_archive, dir, on_extract, arg);
1622}
int zip_is64(struct zip_t *zip)
Definition zip.cpp:849
unsigned long long zip_entry_size(struct zip_t *zip)
Definition zip.cpp:1201
ssize_t zip_stream_copy(struct zip_t *zip, void **buf, ssize_t *bufsize)
Definition zip.cpp:1517
int zip_entry_isdir(struct zip_t *zip)
Definition zip.cpp:1186
const char * zip_entry_name(struct zip_t *zip)
Definition zip.cpp:1168
struct zip_t * zip_open(const char *zipname, int level, char mode)
Definition zip.cpp:779
void zip_stream_close(struct zip_t *zip)
Definition zip.cpp:1533
int zip_entry_fread(struct zip_t *zip, const char *filename)
Definition zip.cpp:1346
int zip_entry_index(struct zip_t *zip)
Definition zip.cpp:1177
struct zip_t * zip_stream_open(const char *stream, size_t size, int level, char mode)
Definition zip.cpp:1481
const char * zip_strerror(int errnum)
Definition zip.cpp:140
int zip_entry_fwrite(struct zip_t *zip, const char *filename)
Definition zip.cpp:1247
ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize)
Definition zip.cpp:1324
unsigned int zip_entry_crc32(struct zip_t *zip)
Definition zip.cpp:1205
#define ZIP_DEFAULT_COMPRESSION_LEVEL
Definition zip.h:50
int zip_create(const char *zipname, const char *filenames[], size_t len)
Definition zip.cpp:1541
void zip_close(struct zip_t *zip)
Definition zip.cpp:836
int zip_entry_open(struct zip_t *zip, const char *entryname)
Definition zip.cpp:858
int zip_entry_openbyindex(struct zip_t *zip, int index)
Definition zip.cpp:1014
int zip_extract(const char *zipname, const char *dir, int(*on_extract)(const char *filename, void *arg), void *arg)
Definition zip.cpp:1601
int zip_entries_total(struct zip_t *zip)
Definition zip.cpp:1417
#define ZIP_ENOINIT
Definition zip.h:55
int zip_entry_close(struct zip_t *zip)
Definition zip.cpp:1087
int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize)
Definition zip.cpp:1209
ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize)
Definition zip.cpp:1295
int zip_entries_delete(struct zip_t *zip, char *const entries[], const size_t len)
Definition zip.cpp:1426
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.cpp:1461
Definition zip.cpp:100
Definition zip.cpp:72
Definition zip.cpp:88