[libgsf] Zip: special-case a stored "mimetype" entry.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgsf] Zip: special-case a stored "mimetype" entry.
- Date: Mon, 15 Dec 2014 13:40:54 +0000 (UTC)
commit a92fd65fe806678284808ca14f0ebf48ed4a9adb
Author: Morten Welinder <terra gnome org>
Date: Mon Dec 15 08:40:23 2014 -0500
Zip: special-case a stored "mimetype" entry.
ChangeLog | 9 ++++++++
gsf/gsf-outfile-zip.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 61 insertions(+), 2 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 00349aa..858dd1d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2014-12-15 Morten Welinder <terra gnome org>
+
+ * gsf/gsf-outfile-zip.c (special_mimetype_dirent): New function.
+ (zip_dirent_write, zip_header_write): Don't write a special unix
+ mtime field for the special mimetype entry.
+ (zip_close_root): Sort by offset. Note: this may not be necessary
+ or even desired, but help with the zipdetails utility.
+ (zip_init_write): Make the special mimetype default to !zip64.
+
2014-12-14 Morten Welinder <terra gnome org>
* gsf/gsf-outfile-zip.c (zip_dirent_write): Fix test for writing
diff --git a/gsf/gsf-outfile-zip.c b/gsf/gsf-outfile-zip.c
index 9d07ad7..24b305a 100644
--- a/gsf/gsf-outfile-zip.c
+++ b/gsf/gsf-outfile-zip.c
@@ -155,6 +155,23 @@ gsf_outfile_zip_seek (G_GNUC_UNUSED GsfOutput *output,
return FALSE;
}
+/*
+ * The "mimetype" member is special for ODF. It cannot have any
+ * extra field (and thus cannot be a zip64 member). Hardcode
+ * this to help compatibility with libgsf users depending on
+ * past behaviour of zip creation.
+ *
+ * The flip side is that such a file cannot be 4G+.
+ */
+static gboolean
+special_mimetype_dirent (const GsfZipDirent *dirent)
+{
+ return (dirent->offset == 0 &&
+ dirent->zip64 != TRUE &&
+ dirent->compr_method == GSF_ZIP_STORED &&
+ strcmp (dirent->name, "mimetype") == 0);
+}
+
static gboolean
zip_dirent_write (GsfOutfileZip *zip, const GsfZipDirent *dirent)
{
@@ -200,7 +217,9 @@ zip_dirent_write (GsfOutfileZip *zip, const GsfZipDirent *dirent)
g_string_append_len (extras, tmp, 8);
}
- if (dirent->mtime && dirent->mtime <= G_MAXUINT32) {
+ if (dirent->mtime &&
+ dirent->mtime <= G_MAXUINT32 &&
+ !special_mimetype_dirent (dirent)) {
/* Clearly a year 2038 problem here. */
char tmp[4];
GSF_LE_SET_GUINT16 (tmp, ZIP_DIRENT_EXTRA_FIELD_UNIXTIME);
@@ -306,6 +325,17 @@ zip_zip64_locator_write (GsfOutfileZip *zip, gsf_off_t trailerpos)
return gsf_output_write (zip->sink, sizeof buf, buf);
}
+static gint
+offset_ordering (gconstpointer a_, gconstpointer b_)
+{
+ GsfOutfileZip *a = *(GsfOutfileZip **)a_;
+ GsfOutfileZip *b = *(GsfOutfileZip **)b_;
+ gsf_off_t diff = a->vdir->dirent->offset - b->vdir->dirent->offset;
+
+ return diff < 0 ? -1 : diff > 0 ? +1 : 0;
+}
+
+
static gboolean
zip_close_root (GsfOutput *output)
{
@@ -328,6 +358,21 @@ zip_close_root (GsfOutput *output)
}
}
+ if (1) {
+ /*
+ * It is unclear whether we need this. However, the
+ * zipdetails utility gets utterly confused if we do
+ * not.
+ *
+ * If we do not sort, we will use the ordering in which
+ * the members were actually being written. Note, that
+ * merely creating the member doesn't count -- it's the
+ * actual writing (or closing an empty member) that
+ * counts.
+ */
+ g_ptr_array_sort (elem, offset_ordering);
+ }
+
/* Write directory */
dirpos = gsf_output_tell (zip->sink);
for (i = 0 ; i < entries ; i++) {
@@ -536,7 +581,9 @@ zip_header_write (GsfOutfileZip *zip)
g_string_append_len (extras, tmp, 8);
}
- if (dirent->mtime && dirent->mtime <= G_MAXUINT32) {
+ if (dirent->mtime &&
+ dirent->mtime <= G_MAXUINT32 &&
+ !special_mimetype_dirent (dirent)) {
/* Clearly a year 2038 problem here. */
char tmp[4];
GSF_LE_SET_GUINT16 (tmp, ZIP_DIRENT_EXTRA_FIELD_UNIXTIME);
@@ -600,6 +647,9 @@ zip_init_write (GsfOutput *output)
}
dirent->offset = gsf_output_tell (zip->sink);
+ if (special_mimetype_dirent (dirent))
+ dirent->zip64 = FALSE;
+
zip->vdir->dirent = dirent;
zip_header_write (zip);
zip->writing = TRUE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]