[libgsf] zip: by default, use zip64 when needed
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgsf] zip: by default, use zip64 when needed
- Date: Fri, 28 Nov 2014 00:35:02 +0000 (UTC)
commit c35ad400b5a5dc665404b2acd9c6aac3beaf4796
Author: Morten Welinder <terra gnome org>
Date: Thu Nov 27 19:33:50 2014 -0500
zip: by default, use zip64 when needed
We invent an "ingore" field for purposes on having a predictable header
size before we know the member size.
gsf/gsf-outfile-zip.c | 75 +++++++++++++++++++++++++++++++++++-------------
gsf/gsf-zip-impl.h | 3 +-
2 files changed, 56 insertions(+), 22 deletions(-)
---
diff --git a/gsf/gsf-outfile-zip.c b/gsf/gsf-outfile-zip.c
index 29dd63f..345fecd 100644
--- a/gsf/gsf-outfile-zip.c
+++ b/gsf/gsf-outfile-zip.c
@@ -38,7 +38,8 @@ enum {
PROP_SINK,
PROP_ENTRY_NAME,
PROP_COMPRESSION_METHOD,
- PROP_DEFLATE_LEVEL
+ PROP_DEFLATE_LEVEL,
+ PROP_ZIP64
};
static GObjectClass *parent_class;
@@ -163,6 +164,7 @@ zip_dirent_write (GsfOutput *sink, GsfZipDirent *dirent)
GString *extras = g_string_sized_new (ZIP_DIRENT_SIZE + nlen + 100);
if (dirent->zip64) {
+ gboolean do_offset = dirent->offset >= G_MAXUINT32;
char tmp[8];
/*
@@ -172,7 +174,6 @@ zip_dirent_write (GsfOutput *sink, GsfZipDirent *dirent)
* and the local headers. So we try to make them the
* same.
*/
- gboolean do_offset = dirent->offset >= 0xffffffffu;
GSF_LE_SET_GUINT16 (tmp, ZIP_DIRENT_EXTRA_FIELD_ZIP64);
GSF_LE_SET_GUINT16 (tmp + 2, (2 + do_offset) * 8);
g_string_append_len (extras, tmp, 4);
@@ -198,9 +199,9 @@ zip_dirent_write (GsfOutput *sink, GsfZipDirent *dirent)
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_DOSTIME, dirent->dostime);
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_CRC32, dirent->crc32);
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_CSIZE,
- dirent->zip64 ? 0xffffffffu : dirent->csize);
+ dirent->zip64 ? G_MAXUINT32 : dirent->csize);
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_USIZE,
- dirent->zip64 ? 0xffffffffu : dirent->usize);
+ dirent->zip64 ? G_MAXUINT32 : dirent->usize);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_NAME_SIZE, nlen);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_EXTRAS_SIZE, extras->len);
GSF_LE_SET_GUINT16 (buf + ZIP_DIRENT_COMMENT_SIZE, 0);
@@ -209,7 +210,7 @@ zip_dirent_write (GsfOutput *sink, GsfZipDirent *dirent)
/* Hardcode file mode 644 */
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_FILE_MODE, 0100644 << 16);
GSF_LE_SET_GUINT32 (buf + ZIP_DIRENT_OFFSET,
- MIN (dirent->offset, 0xffffffffu));
+ MIN (dirent->offset, G_MAXUINT32));
/* Stuff everything into extras so we can do just one write. */
g_string_insert_len (extras, 0, buf, sizeof buf);
@@ -231,13 +232,13 @@ zip_trailer_write (GsfOutfileZip *zip, unsigned entries,
memset (buf, 0, sizeof buf);
GSF_LE_SET_GUINT32 (buf, ZIP_TRAILER_SIGNATURE);
GSF_LE_SET_GUINT16 (buf + ZIP_TRAILER_ENTRIES,
- MIN (entries, 0xffffu));
+ MIN (entries, G_MAXUINT16));
GSF_LE_SET_GUINT16 (buf + ZIP_TRAILER_TOTAL_ENTRIES,
- MIN (entries, 0xffffu));
+ MIN (entries, G_MAXUINT16));
GSF_LE_SET_GUINT32 (buf + ZIP_TRAILER_DIR_SIZE,
- MIN (dirsize, 0xffffffffu));
+ MIN (dirsize, G_MAXUINT32));
GSF_LE_SET_GUINT32 (buf + ZIP_TRAILER_DIR_POS,
- MIN (dirpos, 0xffffffffu));
+ MIN (dirpos, G_MAXUINT32));
return gsf_output_write (zip->sink, sizeof buf, buf);
}
@@ -288,14 +289,15 @@ zip_close_root (GsfOutput *output)
GPtrArray *elem = zip->root_order;
unsigned entries = elem->len;
unsigned i;
+ guint8 zip64 = zip->zip64;
/* Check that children are closed */
for (i = 0 ; i < elem->len ; i++) {
GsfOutfileZip *child = g_ptr_array_index (elem, i);
GsfZipDirent *dirent = child->vdir->dirent;
- if (dirent->csize >= 0xffffffffu ||
- dirent->usize >= 0xffffffffu)
- zip->zip64 = TRUE; /* No choice. */
+ if (dirent->csize >= G_MAXUINT32 ||
+ dirent->usize >= G_MAXUINT32)
+ zip64 = TRUE; /* No choice. */
if (!gsf_output_is_closed (GSF_OUTPUT (child))) {
g_warning ("Child still open");
return FALSE;
@@ -312,14 +314,18 @@ zip_close_root (GsfOutput *output)
}
dirend = gsf_output_tell (zip->sink);
- if (entries >= 0xffffu || dirend >= 0xfffff000u) {
+ if (entries >= G_MAXUINT16 ||
+ dirend >= G_MAXUINT32 - ZIP_TRAILER_SIZE) {
/* We don't have a choice; force zip64. */
- zip->zip64 = TRUE;
+ zip64 = TRUE;
}
disconnect_children (zip);
- if (zip->zip64) {
+ if (zip64 == -1)
+ zip64 = FALSE;
+
+ if (zip64) {
if (!zip_trailer64_write (zip, entries, dirpos, dirend - dirpos))
return FALSE;
if (!zip_zip64_locator_write (zip, dirend))
@@ -406,7 +412,7 @@ zip_dirent_new_out (GsfOutfileZip *zip)
* The spec is a bit vague about the length limit for file names, but
* clearly we should not go beyond 0xffff.
*/
- if (strlen (name) < 0xffffu) {
+ if (strlen (name) < G_MAXUINT16) {
GsfZipDirent *dirent = gsf_zip_dirent_new ();
dirent->name = name;
dirent->compr_method = zip->compression_method;
@@ -431,7 +437,13 @@ zip_header_write (GsfOutfileZip *zip)
gsf_off_t csize = has_ddesc ? 0 : dirent->csize;
gsf_off_t usize = has_ddesc ? 0 : dirent->usize;
GString *extras = g_string_sized_new (ZIP_HEADER_SIZE + nlen + 100);
- const guint8 extract = dirent->zip64 ? 45 : 23;
+ gboolean real_extra_field =
+ (dirent->zip64 == TRUE ||
+ (dirent->zip64 == -1 &&
+ (dirent->usize >= G_MAXUINT32 ||
+ dirent->csize >= G_MAXUINT32 ||
+ dirent->offset >= G_MAXUINT32)));
+ const guint8 extract = real_extra_field ? 45 : 23;
/*
* In the has_ddesc case, we write crc32/size/usize as zero and store
@@ -445,7 +457,11 @@ zip_header_write (GsfOutfileZip *zip)
if (dirent->zip64) {
char tmp[8];
- GSF_LE_SET_GUINT16 (tmp, ZIP_DIRENT_EXTRA_FIELD_ZIP64);
+ guint16 typ = real_extra_field
+ ? ZIP_DIRENT_EXTRA_FIELD_ZIP64
+ : ZIP_DIRENT_EXTRA_FIELD_IGNORE;
+
+ GSF_LE_SET_GUINT16 (tmp, typ);
GSF_LE_SET_GUINT16 (tmp + 2, 2 * 8);
g_string_append_len (extras, tmp, 4);
GSF_LE_SET_GUINT64 (tmp, usize);
@@ -464,9 +480,9 @@ zip_header_write (GsfOutfileZip *zip)
GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_DOSTIME, dirent->dostime);
GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_CRC32, crc32);
GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_CSIZE,
- dirent->zip64 ? 0xffffffffu : csize);
+ dirent->zip64 ? G_MAXUINT32 : csize);
GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_USIZE,
- dirent->zip64 ? 0xffffffffu : usize);
+ dirent->zip64 ? G_MAXUINT32 : usize);
GSF_LE_SET_GUINT16 (hbuf + ZIP_HEADER_NAME_SIZE, nlen);
GSF_LE_SET_GUINT16 (hbuf + ZIP_HEADER_EXTRAS_SIZE, extras->len);
@@ -786,7 +802,7 @@ gsf_outfile_zip_init (GObject *obj)
zip->sink = NULL;
zip->root = NULL;
zip->entry_name = NULL;
- zip->zip64 = FALSE;
+ zip->zip64 = -1;
zip->vdir = NULL;
zip->root_order = NULL;
zip->stream = NULL;
@@ -821,6 +837,9 @@ gsf_outfile_zip_get_property (GObject *object,
case PROP_DEFLATE_LEVEL:
g_value_set_int (value, zip->deflate_level);
break;
+ case PROP_ZIP64:
+ g_value_set_int (value, zip->zip64);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -862,6 +881,9 @@ gsf_outfile_zip_set_property (GObject *object,
g_warning ("Unsupported deflate level %d", level);
}
break;
+ case PROP_ZIP64:
+ zip->zip64 = g_value_get_int (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -929,6 +951,17 @@ gsf_outfile_zip_class_init (GObjectClass *gobject_class)
GSF_PARAM_STATIC |
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_DEFLATE_LEVEL,
+ g_param_spec_int ("zip64",
+ _("Zip64"),
+ _("Whether to use zip64 format, -1 meaning automatic"),
+ -1, 1,
+ -1,
+ GSF_PARAM_STATIC |
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
}
GSF_CLASS (GsfOutfileZip, gsf_outfile_zip,
diff --git a/gsf/gsf-zip-impl.h b/gsf/gsf-zip-impl.h
index e4afaed..8202086 100644
--- a/gsf/gsf-zip-impl.h
+++ b/gsf/gsf-zip-impl.h
@@ -111,6 +111,7 @@ G_BEGIN_DECLS
/* A few well-defined extra-field tags. */
enum {
ZIP_DIRENT_EXTRA_FIELD_ZIP64 = 0x0001,
+ ZIP_DIRENT_EXTRA_FIELD_IGNORE = 0x4949, /* "II" -- gsf defined */
ZIP_DIRENT_EXTRA_FIELD_UNIXTIME = 0x5455, /* "UT" */
ZIP_DIRENT_EXTRA_FIELD_UIDGID = 0x7875 /* "ux" */
};
@@ -143,7 +144,7 @@ typedef struct {
gsf_off_t offset;
gsf_off_t data_offset;
guint32 dostime;
- gboolean zip64;
+ guint8 zip64; /* -1 = auto, FALSE, TRUE. */
} GsfZipDirent;
typedef struct {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]