A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 by James Buren
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "zip.h"
23#include "string-extra.h"
24#include "file.h"
25#include "dir.h"
26#include "system.h"
27#include "errno.h"
28#include "core_alloc.h"
29#include "timefuncs.h"
30#include "pathfuncs.h"
31#include "crc32.h"
32#include "rbendian.h"
33
34#define zip_core_alloc(N) core_alloc_ex((N),&buflib_ops_locked)
35
36enum {
37 ZIP_SIG_ED = 0x06054b50,
38 ZIP_SIG_CD = 0x02014b50,
39 ZIP_SIG_LF = 0x04034b50,
40 ZIP_BIT_DD = 0x0008,
41 ZIP_METHOD_STORE = 0x0000,
42 ZIP_MAX_LENGTH = 0xffff,
43 ZIP_BUFFER_SIZE = 4096,
44};
45
46enum {
47 ZIP_STATE_INITIAL,
48 ZIP_STATE_ED_ENTER,
49 ZIP_STATE_ED_EXIT,
50 ZIP_STATE_CD_ENTER,
51 ZIP_STATE_CD_EXIT,
52 ZIP_STATE_LF_ENTER,
53 ZIP_STATE_LF_EXIT,
54};
55
56struct zip_ed_disk {
57 uint32_t signature;
58 uint16_t disk_number;
59 uint16_t disk_number_cd;
60 uint16_t disk_entries_cd;
61 uint16_t cd_entries;
62 uint32_t cd_size;
63 uint32_t cd_offset;
64 uint16_t comment_length;
65 // comment block (variable length)
66} __attribute__((packed));
67
68struct zip_ed {
69 uint32_t cd_size;
70 uint32_t cd_offset;
71 uint16_t cd_entries;
72};
73
74struct zip_cd_disk {
75 uint32_t signature;
76 uint16_t version_madeby;
77 uint16_t version_needed;
78 uint16_t flags;
79 uint16_t method;
80 uint16_t time;
81 uint16_t date;
82 uint32_t crc;
83 uint32_t compressed_size;
84 uint32_t uncompressed_size;
85 uint16_t name_length;
86 uint16_t extra_length;
87 uint16_t comment_length;
88 uint16_t disk_number;
89 uint16_t internal_attributes;
90 uint32_t external_attributes;
91 uint32_t lf_offset;
92 // name block (variable length)
93 // extra block (variable length)
94 // comment block (variable length)
95} __attribute__((packed));
96
97struct zip_cd {
98 uint32_t crc;
99 uint32_t compressed_size;
100 uint32_t uncompressed_size;
101 uint32_t lf_offset;
102};
103
104struct zip_lf_disk {
105 uint32_t signature;
106 uint16_t version_needed;
107 uint16_t flags;
108 uint16_t method;
109 uint16_t time;
110 uint16_t date;
111 uint32_t crc;
112 uint32_t compressed_size;
113 uint32_t uncompressed_size;
114 uint16_t name_length;
115 uint16_t extra_length;
116 // name block (variable length)
117 // extra block (variable length)
118} __attribute__((packed));
119
120struct zip_lf {
121 uint16_t flags;
122 uint16_t method;
123 uint16_t time;
124 uint16_t date;
125 uint32_t crc;
126 uint32_t compressed_size;
127 uint32_t uncompressed_size;
128 uint16_t name_length;
129 char name[MAX_PATH];
130};
131
132struct zip {
133 ssize_t (*read) (struct zip*, void*, size_t);
134 off_t (*seek) (struct zip*, off_t, int);
135 off_t (*size) (struct zip*);
136 void (*close) (struct zip*);
137 int zip_handle;
138 int state;
139 zip_callback cb;
140 struct zip_args args;
141 void* ctx;
142 struct zip_ed ed;
143 int cds_handle;
144 struct zip_cd* cds;
145 struct zip_lf lf;
146};
147
148struct zip_file {
149 struct zip base;
150 int file;
151};
152
153struct zip_mem {
154 struct zip base;
155 int mem_handle;
156 const uint8_t* mem;
157 off_t mem_offset;
158 off_t mem_size;
159};
160
161struct zip_extract {
162 zip_callback cb;
163 void* ctx;
164 size_t name_offset;
165 size_t name_size;
166 char* name;
167 int file;
168 char path[MAX_PATH];
169};
170
171static int zip_read_ed(struct zip* z) {
172 const off_t file_size = z->size(z);
173 const off_t max_size = sizeof(struct zip_ed_disk) + ZIP_MAX_LENGTH;
174 const off_t read_size = MIN(file_size, max_size);
175 const uint32_t sig = htole32(ZIP_SIG_ED);
176 int mem_handle = -1;
177 uint8_t* mem;
178 off_t i = read_size - sizeof(struct zip_ed_disk);
179 const struct zip_ed_disk* edd;
180 uint16_t disk_number;
181 uint16_t disk_number_cd;
182 uint16_t disk_entries_cd;
183 uint16_t cd_entries;
184 struct zip_ed* ed = &z->ed;
185 int rv;
186
187 z->state = ZIP_STATE_ED_ENTER;
188
189 if (file_size < (off_t) sizeof(struct zip_ed_disk)) {
190 rv = -2;
191 goto bail;
192 }
193
194 if ((mem_handle = zip_core_alloc(read_size)) < 0) {
195 rv = -3;
196 goto bail;
197 }
198
199 mem = core_get_data(mem_handle);
200
201 if (z->seek(z, -read_size, SEEK_END) < 0) {
202 rv = -4;
203 goto bail;
204 }
205
206 if (z->read(z, mem, read_size) != read_size) {
207 rv = -5;
208 goto bail;
209 }
210
211 for (; i >= 0; i--)
212 if (memcmp(mem + i, &sig, sizeof(uint32_t)) == 0)
213 break;
214
215 if (i < 0) {
216 rv = -6;
217 goto bail;
218 }
219
220 edd = (struct zip_ed_disk*) (mem + i);
221 disk_number = letoh16(edd->disk_number);
222 disk_number_cd = letoh16(edd->disk_number_cd);
223 disk_entries_cd = letoh16(edd->disk_entries_cd);
224 cd_entries = letoh16(edd->cd_entries);
225
226 if (disk_number != 0 || disk_number_cd != 0 || disk_entries_cd != cd_entries) {
227 rv = -7;
228 goto bail;
229 }
230
231 ed->cd_size = letoh32(edd->cd_size);
232 ed->cd_offset = letoh32(edd->cd_offset);
233 ed->cd_entries = cd_entries;
234
235 z->state = ZIP_STATE_ED_EXIT;
236 rv = 0;
237
238bail:
239 core_free(mem_handle);
240 return rv;
241}
242
243static int zip_read_cd(struct zip* z, bool use_cb) {
244 const struct zip_ed* ed = &z->ed;
245 const uint32_t cd_size = ed->cd_size;
246 const uint32_t cd_offset = ed->cd_offset;
247 const uint16_t cd_entries = ed->cd_entries;
248 const uint32_t sig = htole32(ZIP_SIG_CD);
249 int cds_handle = -1;
250 int mem_handle = -1;
251 struct zip_cd* cds;
252 uint8_t* mem;
253 struct zip_lf* lf = &z->lf;
254 struct zip_args* args = &z->args;
255 struct zip_cd_disk* cdd;
256 struct zip_cd* cd;
257 uint16_t name_length;
258 int rv;
259
260 z->state = ZIP_STATE_CD_ENTER;
261
262 if ((cds_handle = zip_core_alloc(sizeof(struct zip_cd) * cd_entries)) < 0) {
263 rv = -7;
264 goto bail;
265 }
266
267 if ((mem_handle = zip_core_alloc(cd_size)) < 0) {
268 rv = -8;
269 goto bail;
270 }
271
272 cds = core_get_data(cds_handle);
273 mem = core_get_data(mem_handle);
274
275 if (z->seek(z, cd_offset, SEEK_SET) < 0) {
276 rv = -9;
277 goto bail;
278 }
279
280 if (z->read(z, mem, cd_size) != (ssize_t) cd_size) {
281 rv = -10;
282 goto bail;
283 }
284
285 if (use_cb) {
286 args->entries = cd_entries;
287 args->name = lf->name;
288 args->block = NULL;
289 args->block_size = 0;
290 args->read_size = 0;
291 }
292
293 cdd = (struct zip_cd_disk*) mem;
294
295 for (uint16_t i = 0; i < cd_entries; i++) {
296 if (cdd->signature != sig) {
297 rv = -11;
298 goto bail;
299 }
300
301 cd = &cds[i];
302
303 cd->crc = letoh32(cdd->crc);
304 cd->compressed_size = letoh32(cdd->compressed_size);
305 cd->uncompressed_size = letoh32(cdd->uncompressed_size);
306 cd->lf_offset = letoh32(cdd->lf_offset);
307
308 mem += sizeof(struct zip_cd_disk);
309 name_length = letoh16(cdd->name_length);
310 if (use_cb) {
311 if (name_length >= sizeof(lf->name)) {
312 rv = -12;
313 goto bail;
314 }
315
316 args->entry = i + 1;
317 args->file_size = cd->uncompressed_size;
318 args->mtime = dostime_mktime(letoh16(cdd->date), letoh16(cdd->time));
319
320 memcpy(lf->name, mem, name_length);
321 lf->name[name_length] = '\0';
322
323 if ((rv = z->cb(args, ZIP_PASS_SHALLOW, z->ctx)) > 0)
324 goto bail;
325 }
326 mem += name_length;
327 mem += letoh16(cdd->extra_length);
328 mem += letoh16(cdd->comment_length);
329 cdd = (struct zip_cd_disk*) mem;
330 }
331
332 z->cds_handle = cds_handle;
333 z->cds = cds;
334 z->state = ZIP_STATE_CD_EXIT;
335 rv = 0;
336
337bail:
338 if (rv != 0)
339 core_free(cds_handle);
340 core_free(mem_handle);
341 return rv;
342}
343
344static int zip_read_lf(struct zip* z, uint16_t i) {
345 const uint32_t sig = htole32(ZIP_SIG_LF);
346 const struct zip_cd* cd = &z->cds[i];
347 struct zip_lf* lf = &z->lf;
348 struct zip_lf_disk lfd;
349 uint16_t name_length;
350
351 if (z->seek(z, cd->lf_offset, SEEK_SET) < 0)
352 return -14;
353
354 if (z->read(z, &lfd, sizeof(struct zip_lf_disk)) != sizeof(struct zip_lf_disk))
355 return -15;
356
357 if (lfd.signature != sig)
358 return -16;
359
360 name_length = letoh16(lfd.name_length);
361
362 if (name_length >= sizeof(lf->name))
363 return -17;
364
365 if (z->read(z, lf->name, name_length) != name_length)
366 return -18;
367
368 if (z->seek(z, letoh16(lfd.extra_length), SEEK_CUR) < 0)
369 return -19;
370
371 lf->flags = letoh16(lfd.flags);
372 lf->method = letoh16(lfd.method);
373 lf->time = letoh16(lfd.time);
374 lf->date = letoh16(lfd.date);
375 lf->crc = letoh32(lfd.crc);
376 lf->compressed_size = letoh32(lfd.compressed_size);
377 lf->uncompressed_size = letoh32(lfd.uncompressed_size);
378 lf->name_length = name_length;
379 lf->name[name_length] = '\0';
380
381 if ((lf->flags & ZIP_BIT_DD) == ZIP_BIT_DD) {
382 lf->crc = cd->crc;
383 lf->compressed_size = cd->compressed_size;
384 lf->uncompressed_size = cd->uncompressed_size;
385 }
386
387 return 0;
388}
389
390static int zip_read_store(struct zip* z, void* mem, uint32_t mem_size) {
391 const struct zip_lf* lf = &z->lf;
392 struct zip_args* args = &z->args;
393 uint32_t file_size = lf->uncompressed_size;
394 uint32_t block_size = mem_size;
395 uint32_t crc = 0xffffffff;
396 int rv;
397
398 if (lf->compressed_size != lf->uncompressed_size)
399 return -21;
400
401 args->block = mem;
402 args->block_size = block_size;
403 args->read_size = 0;
404
405 do {
406 if (block_size > file_size) {
407 args->block_size = block_size = file_size;
408 }
409
410 if (z->read(z, mem, block_size) != (off_t) block_size)
411 return -22;
412
413 args->read_size += block_size;
414 crc = crc_32r(mem, block_size, crc);
415
416 if ((rv = z->cb(args, ZIP_PASS_DATA, z->ctx)) != 0)
417 return (rv < 0) ? 0 : rv;
418
419 file_size -= block_size;
420 } while (file_size > 0);
421
422 if (~crc != lf->crc)
423 return -24;
424
425 return 0;
426}
427
428static int zip_read_entry(struct zip* z, uint16_t i, void* mem, uint32_t mem_size) {
429 const struct zip_lf* lf = &z->lf;
430 struct zip_args* args = &z->args;
431 int rv;
432
433 if ((rv = zip_read_lf(z, i)) != 0)
434 return rv;
435
436 args->entry = i + 1;
437 args->file_size = lf->uncompressed_size;
438 args->mtime = dostime_mktime(lf->date, lf->time);
439 args->block = NULL;
440 args->block_size = 0;
441 args->read_size = 0;
442
443 if ((rv = z->cb(&z->args, ZIP_PASS_START, z->ctx)) != 0)
444 return (rv < 0) ? 0 : rv;
445
446 if (lf->uncompressed_size == 0)
447 goto skip_data;
448
449 if (lf->method == ZIP_METHOD_STORE) {
450 if ((rv = zip_read_store(z, mem, mem_size)) != 0)
451 return rv;
452 } else {
453 return -20;
454 }
455
456skip_data:
457 args->block = NULL;
458 args->block_size = 0;
459 args->read_size = 0;
460
461 if ((rv = z->cb(args, ZIP_PASS_END, z->ctx)) != 0)
462 return (rv < 0) ? 0 : rv;
463
464 return 0;
465}
466
467static int zip_read_entries(struct zip* z) {
468 const struct zip_ed* ed = &z->ed;
469 const uint16_t cd_entries = ed->cd_entries;
470 struct zip_lf* lf = &z->lf;
471 struct zip_args* args = &z->args;
472 uint32_t mem_size = ZIP_BUFFER_SIZE;
473 int mem_handle;
474 void* mem;
475 int rv;
476
477 z->state = ZIP_STATE_LF_ENTER;
478
479 if ((mem_handle = zip_core_alloc(mem_size)) < 0) {
480 rv = -13;
481 goto bail;
482 }
483
484 mem = core_get_data(mem_handle);
485
486 args->entries = cd_entries;
487 args->name = lf->name;
488
489 for (uint16_t i = 0; i < cd_entries; i++)
490 if ((rv = zip_read_entry(z, i, mem, mem_size)) > 0)
491 goto bail;
492
493 z->state = ZIP_STATE_LF_EXIT;
494 rv = 0;
495
496bail:
497 core_free(mem_handle);
498 return rv;
499}
500
501static void zip_init(struct zip* z, int zip_handle) {
502 z->zip_handle = zip_handle;
503 z->state = ZIP_STATE_INITIAL;
504 z->cb = NULL;
505 memset(&z->args, 0, sizeof(struct zip_args));
506 z->ctx = NULL;
507 memset(&z->ed, 0, sizeof(struct zip_ed));
508 z->cds_handle = -1;
509 z->cds = NULL;
510 memset(&z->lf, 0, sizeof(struct zip_lf));
511}
512
513static ssize_t zip_file_read(struct zip* zh, void* mem, size_t mem_size) {
514 struct zip_file* z = (struct zip_file*) zh;
515
516 return read(z->file, mem, mem_size);
517}
518
519static off_t zip_file_seek(struct zip* zh, off_t offset, int whence) {
520 struct zip_file* z = (struct zip_file*) zh;
521
522 return lseek(z->file, offset, whence);
523}
524
525static off_t zip_file_size(struct zip* zh) {
526 struct zip_file* z = (struct zip_file*) zh;
527
528 return filesize(z->file);
529}
530
531static void zip_file_close(struct zip* zh) {
532 struct zip_file* z = (struct zip_file*) zh;
533
534 close(z->file);
535}
536
537static void zip_file_init(struct zip_file* z, int zip_handle, int file) {
538 struct zip* zh = &z->base;
539
540 zh->read = zip_file_read;
541 zh->seek = zip_file_seek;
542 zh->size = zip_file_size;
543 zh->close = zip_file_close;
544 zip_init(zh, zip_handle);
545
546 z->file = file;
547}
548
549static ssize_t zip_mem_read(struct zip* zh, void* mem, size_t mem_size) {
550 struct zip_mem* z = (struct zip_mem*) zh;
551 off_t bytes = z->mem_size - z->mem_offset;
552 off_t read_size = MIN(bytes, (off_t) mem_size);
553
554 memcpy(mem, z->mem + z->mem_offset, read_size);
555 z->mem_offset += read_size;
556
557 return read_size;
558}
559
560static off_t zip_mem_seek(struct zip* zh, off_t offset, int whence) {
561 struct zip_mem* z = (struct zip_mem*) zh;
562 off_t new_offset;
563
564 switch (whence) {
565 case SEEK_SET:
566 new_offset = offset;
567 break;
568
569 case SEEK_CUR:
570 new_offset = z->mem_offset + offset;
571 break;
572
573 case SEEK_END:
574 new_offset = z->mem_size + offset;
575 break;
576
577 default:
578 new_offset = -1;
579 break;
580 }
581
582 if (new_offset < 0 || new_offset > z->mem_size)
583 return -1;
584
585 z->mem_offset = new_offset;
586
587 return new_offset;
588}
589
590static off_t zip_mem_size(struct zip* zh) {
591 struct zip_mem* z = (struct zip_mem*) zh;
592
593 return z->mem_size;
594}
595
596static void zip_mem_close(struct zip* zh) {
597 struct zip_mem* z = (struct zip_mem*) zh;
598
599 core_free(z->mem_handle);
600}
601
602static void zip_mem_init(struct zip_mem* z, int zip_handle, int mem_handle, const void* mem, off_t mem_size) {
603 struct zip* zh = &z->base;
604
605 zh->read = zip_mem_read;
606 zh->seek = zip_mem_seek;
607 zh->size = zip_mem_size;
608 zh->close = zip_mem_close;
609 zip_init(zh, zip_handle);
610
611 z->mem_handle = mem_handle;
612 z->mem = mem;
613 z->mem_offset = 0;
614 z->mem_size = mem_size;
615}
616
617static int zip_extract_start(const struct zip_args* args, struct zip_extract* ze) {
618 size_t name_length;
619 const char* dir;
620 size_t dir_length;
621
622 if ((name_length = strlcpy(ze->name, args->name, ze->name_size)) >= ze->name_size)
623 return 5;
624
625 if ((dir_length = path_dirname(ze->name, &dir)) > 0) {
626 char c = ze->name[dir_length];
627
628 ze->name[dir_length] = '\0';
629
630 if (!dir_exists(ze->path)) {
631 const char* path = ze->name;
632 const char* name;
633
634 while (parse_path_component(&path, &name) > 0) {
635 size_t offset = path - ze->name;
636 char c = ze->name[offset];
637
638 ze->name[offset] = '\0';
639
640 if (mkdir(ze->path) < 0 && errno != EEXIST)
641 return 6;
642
643 ze->name[offset] = c;
644 }
645 }
646
647 ze->name[dir_length] = c;
648 }
649
650 if (ze->name[name_length - 1] == PATH_SEPCH) {
651 if (mkdir(ze->path) < 0 && errno != EEXIST)
652 return 7;
653
654 return 0;
655 }
656
657 if ((ze->file = creat(ze->path, 0666)) < 0)
658 return 8;
659
660 return 0;
661}
662
663static int zip_extract_data(const struct zip_args* args, struct zip_extract* ze) {
664 if (write(ze->file, args->block, args->block_size) != (ssize_t) args->block_size) {
665 return 9;
666 }
667
668 return 0;
669}
670
671static int zip_extract_end(const struct zip_args* args, struct zip_extract* ze) {
672 int rv;
673
674 if (ze->file >= 0) {
675 rv = close(ze->file);
676
677 ze->file = -1;
678
679 if (rv < 0)
680 return 10;
681 }
682
683 if (modtime(ze->path, args->mtime) < 0)
684 return 11;
685
686 return 0;
687}
688
689static int zip_extract_callback(const struct zip_args* args, int pass, void* ctx) {
690 struct zip_extract* ze = ctx;
691 int rv;
692
693 if (ze->cb != NULL && (rv = ze->cb(args, pass, ze->ctx)) != 0)
694 return rv;
695
696 switch (pass) {
697 case ZIP_PASS_START:
698 return zip_extract_start(args, ze);
699
700 case ZIP_PASS_DATA:
701 return zip_extract_data(args, ze);
702
703 case ZIP_PASS_END:
704 return zip_extract_end(args, ze);
705
706 default:
707 return 1;
708 }
709}
710
711struct zip* zip_open(const char* name, bool try_mem) {
712 int file = -1;
713 int mem_handle = -1;
714 int zip_handle = -1;
715 off_t mem_size;
716 void* mem;
717 void* zip;
718
719 if (name == NULL || name[0] == '\0')
720 goto bail;
721
722 if ((file = open(name, O_RDONLY)) < 0)
723 goto bail;
724
725 if (try_mem && (mem_handle = zip_core_alloc(mem_size = filesize(file))) >= 0) {
726 if ((zip_handle = zip_core_alloc(sizeof(struct zip_mem))) < 0)
727 goto bail;
728
729 mem = core_get_data(mem_handle);
730
731 if (read(file, mem, mem_size) != mem_size)
732 goto bail;
733
734 close(file);
735
736 zip = core_get_data(zip_handle);
737
738 zip_mem_init(zip, zip_handle, mem_handle, mem, mem_size);
739 } else {
740 if ((zip_handle = zip_core_alloc(sizeof(struct zip_file))) < 0)
741 goto bail;
742
743 zip = core_get_data(zip_handle);
744
745 zip_file_init(zip, zip_handle, file);
746 }
747
748 return zip;
749
750bail:
751 if (file >= 0)
752 close(file);
753 core_free(mem_handle);
754 core_free(zip_handle);
755 return NULL;
756}
757
758int zip_read_shallow(struct zip* z, zip_callback cb, void* ctx) {
759 int rv;
760
761 if (z == NULL || z->state != ZIP_STATE_INITIAL || cb == NULL)
762 return -1;
763
764 z->cb = cb;
765 z->ctx = ctx;
766
767 if ((rv = zip_read_ed(z)) != 0)
768 return rv;
769
770 return zip_read_cd(z, true);
771}
772
773int zip_read_deep(struct zip* z, zip_callback cb, void* ctx) {
774 int rv;
775
776 if (z == NULL || (z->state != ZIP_STATE_INITIAL && z->state != ZIP_STATE_CD_EXIT) || cb == NULL)
777 return -1;
778
779 z->cb = cb;
780 z->ctx = ctx;
781
782 if (z->state == ZIP_STATE_CD_EXIT)
783 goto read_entries;
784
785 if ((rv = zip_read_ed(z)) != 0)
786 return rv;
787
788 if ((rv = zip_read_cd(z, false)) != 0)
789 return rv;
790
791read_entries:
792 return zip_read_entries(z);
793}
794
795int zip_extract(struct zip* z, const char* root, zip_callback cb, void* ctx) {
796 int rv;
797 int ze_handle = -1;
798 struct zip_extract* ze;
799 char* path;
800 size_t size;
801 size_t length;
802
803 if (root == NULL || root[0] == '\0')
804 root = PATH_ROOTSTR;
805
806 if (root[0] != PATH_SEPCH) {
807 rv = -1;
808 goto bail;
809 }
810
811 if (!dir_exists(root)) {
812 rv = 1;
813 goto bail;
814 }
815
816 if ((ze_handle = zip_core_alloc(sizeof(struct zip_extract))) < 0) {
817 rv = 2;
818 goto bail;
819 }
820
821 ze = core_get_data(ze_handle);
822 ze->cb = cb;
823 ze->ctx = ctx;
824 ze->file = -1;
825
826 path = ze->path;
827 size = sizeof(ze->path);
828 length = strlcpy(path, root, size);
829
830 if (length >= size) {
831 rv = 3;
832 goto bail;
833 }
834
835 path += length;
836 size -= length;
837
838 if (path[-1] != PATH_SEPCH) {
839 length = strlcpy(path, PATH_SEPSTR, size);
840
841 if (length >= size) {
842 rv = 4;
843 goto bail;
844 }
845
846 path += length;
847 size -= length;
848 }
849
850 ze->name_offset = path - ze->path;
851 ze->name_size = size;
852 ze->name = path;
853
854 rv = zip_read_deep(z, zip_extract_callback, ze);
855
856bail:
857 if (ze_handle >= 0) {
858 if (ze->file >= 0)
859 close(ze->file);
860
861 core_free(ze_handle);
862 }
863 return rv;
864}
865
866void zip_close(struct zip* z) {
867 if (z == NULL)
868 return;
869
870 z->close(z);
871
872 core_free(z->cds_handle);
873
874 core_free(z->zip_handle);
875}