2 zip_dirent.c -- read directory entry (local or central), clean dirent
3 Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner
5 This file is part of libzip, a library to manipulate ZIP archives.
6 The authors can be contacted at <libzip@nih.at>
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in
15 the documentation and/or other materials provided with the
17 3. The names of the authors may not be used to endorse or promote
18 products derived from this software without specific prior
21 THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include <sys/types.h>
44 static time_t _zip_d2u_time(zip_uint16_t, zip_uint16_t);
45 static zip_string_t *_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str);
46 static zip_extra_field_t *_zip_ef_utf8(zip_uint16_t, zip_string_t *, zip_error_t *);
50 _zip_cdir_free(zip_cdir_t *cd)
57 for (i=0; i<cd->nentry; i++)
58 _zip_entry_finalize(cd->entry+i);
60 _zip_string_free(cd->comment);
66 _zip_cdir_new(zip_uint64_t nentry, zip_error_t *error)
71 if ((cd=(zip_cdir_t *)malloc(sizeof(*cd))) == NULL) {
72 zip_error_set(error, ZIP_ER_MEMORY, 0);
78 else if ((nentry > SIZE_MAX/sizeof(*(cd->entry))) || (cd->entry=(zip_entry_t *)malloc(sizeof(*(cd->entry))*(size_t)nentry)) == NULL) {
79 zip_error_set(error, ZIP_ER_MEMORY, 0);
84 for (i=0; i<nentry; i++)
85 _zip_entry_init(cd->entry+i);
87 cd->nentry = cd->nentry_alloc = nentry;
88 cd->size = cd->offset = 0;
96 _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors)
98 zip_uint64_t offset, size;
99 zip_string_t *comment;
100 zip_uint8_t buf[EOCDLEN + EOCD64LEN + EOCD64LOCLEN];
101 zip_buffer_t *buffer;
107 if ((off = zip_source_tell_write(za->src)) < 0) {
108 _zip_error_set_from_source(&za->error, za->src);
111 offset = (zip_uint64_t)off;
115 for (i=0; i<survivors; i++) {
116 zip_entry_t *entry = za->entry+filelist[i].idx;
118 if ((ret=_zip_dirent_write(za, entry->changes ? entry->changes : entry->orig, ZIP_FL_CENTRAL)) < 0)
124 if ((off = zip_source_tell_write(za->src)) < 0) {
125 _zip_error_set_from_source(&za->error, za->src);
128 size = (zip_uint64_t)off - offset;
130 if (offset > ZIP_UINT32_MAX || survivors > ZIP_UINT16_MAX)
134 if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) {
135 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
140 _zip_buffer_put(buffer, EOCD64_MAGIC, 4);
141 _zip_buffer_put_64(buffer, EOCD64LEN-12);
142 _zip_buffer_put_16(buffer, 45);
143 _zip_buffer_put_16(buffer, 45);
144 _zip_buffer_put_32(buffer, 0);
145 _zip_buffer_put_32(buffer, 0);
146 _zip_buffer_put_64(buffer, survivors);
147 _zip_buffer_put_64(buffer, survivors);
148 _zip_buffer_put_64(buffer, size);
149 _zip_buffer_put_64(buffer, offset);
150 _zip_buffer_put(buffer, EOCD64LOC_MAGIC, 4);
151 _zip_buffer_put_32(buffer, 0);
152 _zip_buffer_put_64(buffer, offset+size);
153 _zip_buffer_put_32(buffer, 1);
156 _zip_buffer_put(buffer, EOCD_MAGIC, 4);
157 _zip_buffer_put_32(buffer, 0);
158 _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors));
159 _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors));
160 _zip_buffer_put_32(buffer, size >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)size);
161 _zip_buffer_put_32(buffer, offset >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)offset);
163 comment = za->comment_changed ? za->comment_changes : za->comment_orig;
165 _zip_buffer_put_16(buffer, (zip_uint16_t)(comment ? comment->length : 0));
167 if (!_zip_buffer_ok(buffer)) {
168 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
169 _zip_buffer_free(buffer);
173 if (_zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer)) < 0) {
174 _zip_buffer_free(buffer);
178 _zip_buffer_free(buffer);
181 if (_zip_write(za, comment->raw, comment->length) < 0) {
186 return (zip_int64_t)size;
191 _zip_dirent_clone(const zip_dirent_t *sde)
195 if ((tde=(zip_dirent_t *)malloc(sizeof(*tde))) == NULL)
199 memcpy(tde, sde, sizeof(*sde));
201 _zip_dirent_init(tde);
211 _zip_dirent_finalize(zip_dirent_t *zde)
213 if (!zde->cloned || zde->changed & ZIP_DIRENT_FILENAME) {
214 _zip_string_free(zde->filename);
215 zde->filename = NULL;
217 if (!zde->cloned || zde->changed & ZIP_DIRENT_EXTRA_FIELD) {
218 _zip_ef_free(zde->extra_fields);
219 zde->extra_fields = NULL;
221 if (!zde->cloned || zde->changed & ZIP_DIRENT_COMMENT) {
222 _zip_string_free(zde->comment);
229 _zip_dirent_free(zip_dirent_t *zde)
234 _zip_dirent_finalize(zde);
240 _zip_dirent_init(zip_dirent_t *de)
243 de->local_extra_fields_read = 0;
246 de->version_madeby = 20 | (ZIP_OPSYS_DEFAULT << 8);
247 de->version_needed = 20; /* 2.0 */
249 de->comp_method = ZIP_CM_DEFAULT;
255 de->extra_fields = NULL;
259 de->ext_attrib = ZIP_EXT_ATTRIB_DEFAULT;
265 _zip_dirent_needs_zip64(const zip_dirent_t *de, zip_flags_t flags)
267 if (de->uncomp_size >= ZIP_UINT32_MAX || de->comp_size >= ZIP_UINT32_MAX
268 || ((flags & ZIP_FL_CENTRAL) && de->offset >= ZIP_UINT32_MAX))
276 _zip_dirent_new(void)
280 if ((de=(zip_dirent_t *)malloc(sizeof(*de))) == NULL)
283 _zip_dirent_init(de);
288 /* _zip_dirent_read(zde, fp, bufp, left, localp, error):
289 Fills the zip directory entry zde.
291 If buffer is non-NULL, data is taken from there; otherwise data is read from fp as needed.
293 If local is true, it reads a local header instead of a central directory entry.
295 Returns size of dirent read if successful. On error, error is filled in and -1 is returned.
299 _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_error_t *error)
301 zip_uint8_t buf[CDENTRYSIZE];
302 zip_uint16_t dostime, dosdate;
303 zip_uint32_t size, variable_size;
304 zip_uint16_t filename_len, comment_len, ef_len;
306 bool from_buffer = (buffer != NULL);
308 size = local ? LENTRYSIZE : CDENTRYSIZE;
311 if (_zip_buffer_left(buffer) < size) {
312 zip_error_set(error, ZIP_ER_NOZIP, 0);
317 if ((buffer = _zip_buffer_new_from_source(src, size, buf, error)) == NULL) {
322 if (memcmp(_zip_buffer_get(buffer, 4), (local ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) {
323 zip_error_set(error, ZIP_ER_NOZIP, 0);
325 _zip_buffer_free(buffer);
330 /* convert buffercontents to zip_dirent */
332 _zip_dirent_init(zde);
334 zde->version_madeby = _zip_buffer_get_16(buffer);
336 zde->version_madeby = 0;
337 zde->version_needed = _zip_buffer_get_16(buffer);
338 zde->bitflags = _zip_buffer_get_16(buffer);
339 zde->comp_method = _zip_buffer_get_16(buffer);
341 /* convert to time_t */
342 dostime = _zip_buffer_get_16(buffer);
343 dosdate = _zip_buffer_get_16(buffer);
344 zde->last_mod = _zip_d2u_time(dostime, dosdate);
346 zde->crc = _zip_buffer_get_32(buffer);
347 zde->comp_size = _zip_buffer_get_32(buffer);
348 zde->uncomp_size = _zip_buffer_get_32(buffer);
350 filename_len = _zip_buffer_get_16(buffer);
351 ef_len = _zip_buffer_get_16(buffer);
355 zde->disk_number = 0;
360 comment_len = _zip_buffer_get_16(buffer);
361 zde->disk_number = _zip_buffer_get_16(buffer);
362 zde->int_attrib = _zip_buffer_get_16(buffer);
363 zde->ext_attrib = _zip_buffer_get_32(buffer);
364 zde->offset = _zip_buffer_get_32(buffer);
367 if (!_zip_buffer_ok(buffer)) {
368 zip_error_set(error, ZIP_ER_INTERNAL, 0);
370 _zip_buffer_free(buffer);
375 zde->filename = NULL;
376 zde->extra_fields = NULL;
379 variable_size = (zip_uint32_t)filename_len+(zip_uint32_t)ef_len+(zip_uint32_t)comment_len;
382 if (_zip_buffer_left(buffer) < variable_size) {
383 zip_error_set(error, ZIP_ER_INCONS, 0);
388 _zip_buffer_free(buffer);
390 if ((buffer = _zip_buffer_new_from_source(src, variable_size, NULL, error)) == NULL) {
396 zde->filename = _zip_read_string(buffer, src, filename_len, 1, error);
397 if (!zde->filename) {
398 if (zip_error_code_zip(error) == ZIP_ER_EOF) {
399 zip_error_set(error, ZIP_ER_INCONS, 0);
402 _zip_buffer_free(buffer);
407 if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) {
408 if (_zip_guess_encoding(zde->filename, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) {
409 zip_error_set(error, ZIP_ER_INCONS, 0);
411 _zip_buffer_free(buffer);
419 zip_uint8_t *ef = _zip_read_data(buffer, src, ef_len, 0, error);
423 _zip_buffer_free(buffer);
427 if (!_zip_ef_parse(ef, ef_len, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, &zde->extra_fields, error)) {
430 _zip_buffer_free(buffer);
436 zde->local_extra_fields_read = 1;
440 zde->comment = _zip_read_string(buffer, src, comment_len, 0, error);
443 _zip_buffer_free(buffer);
447 if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) {
448 if (_zip_guess_encoding(zde->comment, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) {
449 zip_error_set(error, ZIP_ER_INCONS, 0);
451 _zip_buffer_free(buffer);
458 zde->filename = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_NAME, zde->filename);
459 zde->comment = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_COMMENT, zde->comment);
463 if (zde->uncomp_size == ZIP_UINT32_MAX || zde->comp_size == ZIP_UINT32_MAX || zde->offset == ZIP_UINT32_MAX) {
464 zip_uint16_t got_len;
465 zip_buffer_t *ef_buffer;
466 const zip_uint8_t *ef = _zip_ef_get_by_id(zde->extra_fields, &got_len, ZIP_EF_ZIP64, 0, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, error);
467 /* TODO: if got_len == 0 && !ZIP64_EOCD: no error, 0xffffffff is valid value */
470 _zip_buffer_free(buffer);
475 if ((ef_buffer = _zip_buffer_new((zip_uint8_t *)ef, got_len)) == NULL) {
476 zip_error_set(error, ZIP_ER_MEMORY, 0);
478 _zip_buffer_free(buffer);
483 if (zde->uncomp_size == ZIP_UINT32_MAX)
484 zde->uncomp_size = _zip_buffer_get_64(ef_buffer);
486 /* From appnote.txt: This entry in the Local header MUST
487 include BOTH original and compressed file size fields. */
488 (void)_zip_buffer_skip(ef_buffer, 8); /* error is caught by _zip_buffer_eof() call */
490 if (zde->comp_size == ZIP_UINT32_MAX)
491 zde->comp_size = _zip_buffer_get_64(ef_buffer);
493 if (zde->offset == ZIP_UINT32_MAX)
494 zde->offset = _zip_buffer_get_64(ef_buffer);
495 if (zde->disk_number == ZIP_UINT16_MAX)
496 zde->disk_number = _zip_buffer_get_32(buffer);
499 if (!_zip_buffer_eof(ef_buffer)) {
500 zip_error_set(error, ZIP_ER_INCONS, 0);
501 _zip_buffer_free(ef_buffer);
503 _zip_buffer_free(buffer);
507 _zip_buffer_free(ef_buffer);
510 if (!_zip_buffer_ok(buffer)) {
511 zip_error_set(error, ZIP_ER_INTERNAL, 0);
513 _zip_buffer_free(buffer);
518 _zip_buffer_free(buffer);
521 /* zip_source_seek / zip_source_tell don't support values > ZIP_INT64_MAX */
522 if (zde->offset > ZIP_INT64_MAX) {
523 zip_error_set(error, ZIP_ER_SEEK, EFBIG);
527 zde->extra_fields = _zip_ef_remove_internal(zde->extra_fields);
529 return (zip_int64_t)(size + variable_size);
533 static zip_string_t *
534 _zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str)
538 zip_buffer_t *buffer;
540 const zip_uint8_t *ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, id, 0, ZIP_EF_BOTH, NULL);
542 if (ef == NULL || ef_len < 5 || ef[0] != 1) {
546 if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) {
550 _zip_buffer_get_8(buffer);
551 ef_crc = _zip_buffer_get_32(buffer);
553 if (_zip_string_crc32(str) == ef_crc) {
554 zip_uint16_t len = (zip_uint16_t)_zip_buffer_left(buffer);
555 zip_string_t *ef_str = _zip_string_new(_zip_buffer_get(buffer, len), len, ZIP_FL_ENC_UTF_8, NULL);
557 if (ef_str != NULL) {
558 _zip_string_free(str);
563 _zip_buffer_free(buffer);
570 _zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error)
573 bool local = (flags & ZIP_EF_LOCAL) != 0;
576 zip_buffer_t *buffer;
578 size = local ? LENTRYSIZE : CDENTRYSIZE;
580 if (zip_source_seek(src, local ? 26 : 28, SEEK_CUR) < 0) {
581 _zip_error_set_from_source(error, src);
585 if ((buffer = _zip_buffer_new_from_source(src, local ? 4 : 6, b, error)) == NULL) {
589 for (i=0; i<(local ? 2 : 3); i++) {
590 size += _zip_buffer_get_16(buffer);
593 if (!_zip_buffer_eof(buffer)) {
594 zip_error_set(error, ZIP_ER_INTERNAL, 0);
595 _zip_buffer_free(buffer);
599 _zip_buffer_free(buffer);
605 Writes zip directory entry.
607 If flags & ZIP_EF_LOCAL, it writes a local header instead of a central
608 directory entry. If flags & ZIP_EF_FORCE_ZIP64, a ZIP64 extra field is written, even if not needed.
610 Returns 0 if successful, 1 if successful and wrote ZIP64 extra field. On error, error is filled in and -1 is
615 _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags)
617 zip_uint16_t dostime, dosdate;
618 zip_encoding_type_t com_enc, name_enc;
619 zip_extra_field_t *ef;
620 zip_extra_field_t *ef64;
621 zip_uint32_t ef_total_size;
623 bool is_really_zip64;
624 zip_uint8_t buf[CDENTRYSIZE];
625 zip_buffer_t *buffer;
629 name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN);
630 com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN);
632 if ((name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_ASCII) ||
633 (name_enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8_KNOWN) ||
634 (name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_UTF8_KNOWN))
635 de->bitflags |= ZIP_GPBF_ENCODING_UTF_8;
637 de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCODING_UTF_8;
638 if (name_enc == ZIP_ENCODING_UTF8_KNOWN) {
639 ef = _zip_ef_utf8(ZIP_EF_UTF_8_NAME, de->filename, &za->error);
643 if ((flags & ZIP_FL_LOCAL) == 0 && com_enc == ZIP_ENCODING_UTF8_KNOWN){
644 zip_extra_field_t *ef2 = _zip_ef_utf8(ZIP_EF_UTF_8_COMMENT, de->comment, &za->error);
654 is_really_zip64 = _zip_dirent_needs_zip64(de, flags);
655 is_zip64 = (flags & (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64) || is_really_zip64;
658 zip_uint8_t ef_zip64[EFZIP64SIZE];
659 zip_buffer_t *ef_buffer = _zip_buffer_new(ef_zip64, sizeof(ef_zip64));
660 if (ef_buffer == NULL) {
661 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
666 if (flags & ZIP_FL_LOCAL) {
667 if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX) {
668 _zip_buffer_put_64(ef_buffer, de->uncomp_size);
669 _zip_buffer_put_64(ef_buffer, de->comp_size);
673 if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX || de->offset > ZIP_UINT32_MAX) {
674 if (de->uncomp_size >= ZIP_UINT32_MAX) {
675 _zip_buffer_put_64(ef_buffer, de->uncomp_size);
677 if (de->comp_size >= ZIP_UINT32_MAX) {
678 _zip_buffer_put_64(ef_buffer, de->comp_size);
680 if (de->offset >= ZIP_UINT32_MAX) {
681 _zip_buffer_put_64(ef_buffer, de->offset);
686 if (!_zip_buffer_ok(ef_buffer)) {
687 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
688 _zip_buffer_free(ef_buffer);
693 ef64 = _zip_ef_new(ZIP_EF_ZIP64, (zip_uint16_t)(_zip_buffer_offset(ef_buffer)), ef_zip64, ZIP_EF_BOTH);
694 _zip_buffer_free(ef_buffer);
699 if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) {
700 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
705 _zip_buffer_put(buffer, (flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 4);
707 if ((flags & ZIP_FL_LOCAL) == 0) {
708 _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_madeby));
710 _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_needed));
711 _zip_buffer_put_16(buffer, de->bitflags&0xfff9); /* clear compression method specific flags */
712 _zip_buffer_put_16(buffer, (zip_uint16_t)de->comp_method);
714 _zip_u2d_time(de->last_mod, &dostime, &dosdate);
715 _zip_buffer_put_16(buffer, dostime);
716 _zip_buffer_put_16(buffer, dosdate);
718 _zip_buffer_put_32(buffer, de->crc);
720 if (((flags & ZIP_FL_LOCAL) == ZIP_FL_LOCAL) && ((de->comp_size >= ZIP_UINT32_MAX) || (de->uncomp_size >= ZIP_UINT32_MAX))) {
721 /* In local headers, if a ZIP64 EF is written, it MUST contain
722 * both compressed and uncompressed sizes (even if one of the
723 * two is smaller than 0xFFFFFFFF); on the other hand, those
724 * may only appear when the corresponding standard entry is
725 * 0xFFFFFFFF. (appnote.txt 4.5.3) */
726 _zip_buffer_put_32(buffer, ZIP_UINT32_MAX);
727 _zip_buffer_put_32(buffer, ZIP_UINT32_MAX);
730 if (de->comp_size < ZIP_UINT32_MAX) {
731 _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);
734 _zip_buffer_put_32(buffer, ZIP_UINT32_MAX);
736 if (de->uncomp_size < ZIP_UINT32_MAX) {
737 _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);
740 _zip_buffer_put_32(buffer, ZIP_UINT32_MAX);
744 _zip_buffer_put_16(buffer, _zip_string_length(de->filename));
745 /* TODO: check for overflow */
746 ef_total_size = (zip_uint32_t)_zip_ef_size(de->extra_fields, flags) + (zip_uint32_t)_zip_ef_size(ef, ZIP_EF_BOTH);
747 _zip_buffer_put_16(buffer, (zip_uint16_t)ef_total_size);
749 if ((flags & ZIP_FL_LOCAL) == 0) {
750 _zip_buffer_put_16(buffer, _zip_string_length(de->comment));
751 _zip_buffer_put_16(buffer, (zip_uint16_t)de->disk_number);
752 _zip_buffer_put_16(buffer, de->int_attrib);
753 _zip_buffer_put_32(buffer, de->ext_attrib);
754 if (de->offset < ZIP_UINT32_MAX)
755 _zip_buffer_put_32(buffer, (zip_uint32_t)de->offset);
757 _zip_buffer_put_32(buffer, ZIP_UINT32_MAX);
760 if (!_zip_buffer_ok(buffer)) {
761 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
762 _zip_buffer_free(buffer);
767 if (_zip_write(za, buf, _zip_buffer_offset(buffer)) < 0) {
768 _zip_buffer_free(buffer);
773 _zip_buffer_free(buffer);
776 if (_zip_string_write(za, de->filename) < 0) {
783 if (_zip_ef_write(za, ef, ZIP_EF_BOTH) < 0) {
789 if (de->extra_fields) {
790 if (_zip_ef_write(za, de->extra_fields, flags) < 0) {
795 if ((flags & ZIP_FL_LOCAL) == 0) {
797 if (_zip_string_write(za, de->comment) < 0) {
809 _zip_d2u_time(zip_uint16_t dtime, zip_uint16_t ddate)
813 memset(&tm, 0, sizeof(tm));
815 /* let mktime decide if DST is in effect */
818 tm.tm_year = ((ddate>>9)&127) + 1980 - 1900;
819 tm.tm_mon = ((ddate>>5)&15) - 1;
820 tm.tm_mday = ddate&31;
822 tm.tm_hour = (dtime>>11)&31;
823 tm.tm_min = (dtime>>5)&63;
824 tm.tm_sec = (dtime<<1)&62;
830 static zip_extra_field_t *
831 _zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error)
833 const zip_uint8_t *raw;
835 zip_buffer_t *buffer;
836 zip_extra_field_t *ef;
838 if ((raw=_zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL)) == NULL) {
839 /* error already set */
843 if (len+5 > ZIP_UINT16_MAX) {
844 zip_error_set(error, ZIP_ER_INVAL, 0); /* TODO: better error code? */
848 if ((buffer = _zip_buffer_new(NULL, len+5)) == NULL) {
849 zip_error_set(error, ZIP_ER_MEMORY, 0);
853 _zip_buffer_put_8(buffer, 1);
854 _zip_buffer_put_32(buffer, _zip_string_crc32(str));
855 _zip_buffer_put(buffer, raw, len);
857 if (!_zip_buffer_ok(buffer)) {
858 zip_error_set(error, ZIP_ER_INTERNAL, 0);
859 _zip_buffer_free(buffer);
863 ef = _zip_ef_new(id, (zip_uint16_t)(_zip_buffer_offset(buffer)), _zip_buffer_data(buffer), ZIP_EF_BOTH);
864 _zip_buffer_free(buffer);
871 _zip_get_dirent(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error)
876 if (idx >= za->nentry) {
877 zip_error_set(error, ZIP_ER_INVAL, 0);
881 if ((flags & ZIP_FL_UNCHANGED) || za->entry[idx].changes == NULL) {
882 if (za->entry[idx].orig == NULL) {
883 zip_error_set(error, ZIP_ER_INVAL, 0);
886 if (za->entry[idx].deleted && (flags & ZIP_FL_UNCHANGED) == 0) {
887 zip_error_set(error, ZIP_ER_DELETED, 0);
890 return za->entry[idx].orig;
893 return za->entry[idx].changes;
900 _zip_u2d_time(time_t intime, zip_uint16_t *dtime, zip_uint16_t *ddate)
904 tm = localtime(&intime);
905 if (tm->tm_year < 80) {
909 *ddate = (zip_uint16_t)(((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday);
910 *dtime = (zip_uint16_t)(((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1));