Coverage Report

Created: 2026-01-25 07:15

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