diff options
author | Christian Persch <chpe@gnome.org> | 2010-05-13 19:57:41 +0200 |
---|---|---|
committer | Christian Persch <chpe@gnome.org> | 2010-08-17 17:37:32 +0200 |
commit | cae86073eaf932b85836e98df8d87c65d90f5842 (patch) | |
tree | 771fa6f4e1dcf3ff3556426818f886855a61b6e5 /gio | |
parent | b196cd74473cbc812359ee3b484a3986604e9aba (diff) | |
download | glib-cae86073eaf932b85836e98df8d87c65d90f5842.tar.gz |
Add GZIP header processing to GZlibCompressor/GZlibDecompressor
Add GZlibCompressor:file-info property. If it contains a non-NULL
GFileInfo, and the compressor is in GZIP mode, the filename and
modification time from the file info are written to the GZIP header
in the output data.
Add GZlibDeompressor:file-info property. If the decompressor is in GZIP
mode, and the GZIP data contains a GZIP header, the filename and
modification time are read from it, stored in a GFileInfo, and the
file-info property is notified.
Bug #617691.
Diffstat (limited to 'gio')
-rw-r--r-- | gio/gio.symbols | 3 | ||||
-rw-r--r-- | gio/gzlibcompressor.c | 117 | ||||
-rw-r--r-- | gio/gzlibcompressor.h | 5 | ||||
-rw-r--r-- | gio/gzlibdecompressor.c | 134 | ||||
-rw-r--r-- | gio/gzlibdecompressor.h | 3 | ||||
-rw-r--r-- | gio/tests/filter-cat.c | 38 |
6 files changed, 290 insertions, 10 deletions
diff --git a/gio/gio.symbols b/gio/gio.symbols index 5f439cf22..2a83b1035 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -1423,6 +1423,8 @@ g_unix_fd_list_steal_fds #if IN_FILE(__G_ZLIB_COMPRESSOR_C__) g_zlib_compressor_get_type G_GNUC_CONST g_zlib_compressor_new +g_zlib_compressor_get_file_info +g_zlib_compressor_set_file_info #endif #endif @@ -1430,6 +1432,7 @@ g_zlib_compressor_new #if IN_FILE(__G_ZLIB_DECOMPRESSOR_C__) g_zlib_decompressor_get_type G_GNUC_CONST g_zlib_decompressor_new +g_zlib_decompressor_get_file_info #endif #endif diff --git a/gio/gzlibcompressor.c b/gio/gzlibcompressor.c index fc6f33e2f..bfcbcff64 100644 --- a/gio/gzlibcompressor.c +++ b/gio/gzlibcompressor.c @@ -28,6 +28,7 @@ #include <zlib.h> #include <string.h> +#include "gfileinfo.h" #include "gioerror.h" #include "gioenums.h" #include "gioenumtypes.h" @@ -37,7 +38,8 @@ enum { PROP_0, PROP_FORMAT, - PROP_LEVEL + PROP_LEVEL, + PROP_FILE_INFO }; /** @@ -63,8 +65,34 @@ struct _GZlibCompressor GZlibCompressorFormat format; int level; z_stream zstream; + gz_header gzheader; + GFileInfo *file_info; }; +static void +g_zlib_compressor_set_gzheader (GZlibCompressor *compressor) +{ + const gchar *filename; + + if (compressor->format != G_ZLIB_COMPRESSOR_FORMAT_GZIP || + compressor->file_info == NULL) + return; + + memset (&compressor->gzheader, 0, sizeof (gz_header)); + compressor->gzheader.os = 0x03; /* Unix */ + + filename = g_file_info_get_name (compressor->file_info); + compressor->gzheader.name = (Bytef *) filename; + compressor->gzheader.name_max = filename ? strlen (filename) + 1 : 0; + + compressor->gzheader.time = + (uLong) g_file_info_get_attribute_uint64 (compressor->file_info, + G_FILE_ATTRIBUTE_TIME_MODIFIED); + + if (deflateSetHeader (&compressor->zstream, &compressor->gzheader) != Z_OK) + g_warning ("unexpected zlib error: %s\n", compressor->zstream.msg); +} + G_DEFINE_TYPE_WITH_CODE (GZlibCompressor, g_zlib_compressor, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, g_zlib_compressor_iface_init)) @@ -78,6 +106,9 @@ g_zlib_compressor_finalize (GObject *object) deflateEnd (&compressor->zstream); + if (compressor->file_info) + g_object_unref (compressor->file_info); + G_OBJECT_CLASS (g_zlib_compressor_parent_class)->finalize (object); } @@ -102,6 +133,10 @@ g_zlib_compressor_set_property (GObject *object, compressor->level = g_value_get_int (value); break; + case PROP_FILE_INFO: + g_zlib_compressor_set_file_info (compressor, g_value_get_object (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -129,6 +164,10 @@ g_zlib_compressor_get_property (GObject *object, g_value_set_int (value, compressor->level); break; + case PROP_FILE_INFO: + g_value_set_object (value, compressor->file_info); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -172,6 +211,8 @@ g_zlib_compressor_constructed (GObject *object) if (res != Z_OK) g_warning ("unexpected zlib error: %s\n", compressor->zstream.msg); + + g_zlib_compressor_set_gzheader (compressor); } static void @@ -203,6 +244,24 @@ g_zlib_compressor_class_init (GZlibCompressorClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GZlibCompressor:file-info: + * + * If set to a non-%NULL #GFileInfo object, and #GZlibCompressor:format is + * %G_ZLIB_COMPRESSOR_FORMAT_GZIP, the compressor will write the file name + * and modification time from the file info to the the GZIP header. + * + * Since: 2.26 + */ + g_object_class_install_property (gobject_class, + PROP_FILE_INFO, + g_param_spec_object ("file-info", + P_("file info"), + P_("File info"), + G_TYPE_FILE_INFO, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); } /** @@ -230,6 +289,59 @@ g_zlib_compressor_new (GZlibCompressorFormat format, return compressor; } +/** + * g_zlib_compressor_get_file_info: + * @compressor: a #GZlibCompressor + * + * Returns the #GZlibCompressor:file-info property. + * + * Returns: (transfer none): a #GFileInfo, or %NULL + * + * Since: 2.26 + */ +GFileInfo * +g_zlib_compressor_get_file_info (GZlibCompressor *compressor) +{ + g_return_val_if_fail (G_IS_ZLIB_COMPRESSOR (compressor), NULL); + + return compressor->file_info; +} + +/** + * g_zlib_compressor_set_file_info: + * @compressor: a #GZlibCompressor + * @file_info: (allow-none): a #GFileInfo + * + * Sets @file_info in @compressor. If non-%NULL, and @compressor's + * #GZlibCompressor:format property is %G_ZLIB_COMPRESSOR_FORMAT_GZIP, + * it will be used to set the file name and modification time in + * the GZIP header of the compressed data. + * + * Note: it is an error to call this function while a compression is in + * progress; it may only be called immediately after creation of @compressor, + * or after resetting it with g_converter_reset(). + * + * Since: 2.26 + */ +void +g_zlib_compressor_set_file_info (GZlibCompressor *compressor, + GFileInfo *file_info) +{ + g_return_if_fail (G_IS_ZLIB_COMPRESSOR (compressor)); + + if (file_info == compressor->file_info) + return; + + if (compressor->file_info) + g_object_unref (compressor->file_info); + if (file_info) + g_object_ref (file_info); + compressor->file_info = file_info; + g_object_notify (G_OBJECT (compressor), "file-info"); + + g_zlib_compressor_set_gzheader (compressor); +} + static void g_zlib_compressor_reset (GConverter *converter) { @@ -239,6 +351,9 @@ g_zlib_compressor_reset (GConverter *converter) res = deflateReset (&compressor->zstream); if (res != Z_OK) g_warning ("unexpected zlib error: %s\n", compressor->zstream.msg); + + /* deflateReset reset the header too, so re-set it */ + g_zlib_compressor_set_gzheader (compressor); } static GConverterResult diff --git a/gio/gzlibcompressor.h b/gio/gzlibcompressor.h index 0e14a80f3..582478159 100644 --- a/gio/gzlibcompressor.h +++ b/gio/gzlibcompressor.h @@ -28,6 +28,7 @@ #define __G_ZLIB_COMPRESSOR_H__ #include <gio/gconverter.h> +#include <gio/gfileinfo.h> G_BEGIN_DECLS @@ -50,6 +51,10 @@ GType g_zlib_compressor_get_type (void) G_GNUC_CONST; GZlibCompressor *g_zlib_compressor_new (GZlibCompressorFormat format, int level); +GFileInfo *g_zlib_compressor_get_file_info (GZlibCompressor *compressor); +void g_zlib_compressor_set_file_info (GZlibCompressor *compressor, + GFileInfo *file_info); + G_END_DECLS #endif /* __G_ZLIB_COMPRESSOR_H__ */ diff --git a/gio/gzlibdecompressor.c b/gio/gzlibdecompressor.c index 7eeee79ed..f07261394 100644 --- a/gio/gzlibdecompressor.c +++ b/gio/gzlibdecompressor.c @@ -28,6 +28,7 @@ #include <zlib.h> #include <string.h> +#include "gfileinfo.h" #include "gioerror.h" #include "gioenums.h" #include "gioenumtypes.h" @@ -36,7 +37,8 @@ enum { PROP_0, - PROP_FORMAT + PROP_FORMAT, + PROP_FILE_INFO }; /** @@ -50,6 +52,12 @@ enum { static void g_zlib_decompressor_iface_init (GConverterIface *iface); +typedef struct { + gz_header gzheader; + char filename[257]; + GFileInfo *file_info; +} HeaderData; + /** * GZlibDecompressor: * @@ -61,8 +69,35 @@ struct _GZlibDecompressor GZlibCompressorFormat format; z_stream zstream; + HeaderData *header_data; }; +static void +g_zlib_decompressor_set_gzheader (GZlibDecompressor *decompressor) +{ + if (decompressor->format != G_ZLIB_COMPRESSOR_FORMAT_GZIP) + return; + + if (decompressor->header_data != NULL) + { + if (decompressor->header_data->file_info) + g_object_unref (decompressor->header_data->file_info); + + memset (decompressor->header_data, 0, sizeof (HeaderData)); + } + else + { + decompressor->header_data = g_new0 (HeaderData, 1); + } + + decompressor->header_data->gzheader.name = (Bytef*) &decompressor->header_data->filename; + /* We keep one byte to guarantee the string is 0-terminated */ + decompressor->header_data->gzheader.name_max = 256; + + if (inflateGetHeader (&decompressor->zstream, &decompressor->header_data->gzheader) != Z_OK) + g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg); +} + G_DEFINE_TYPE_WITH_CODE (GZlibDecompressor, g_zlib_decompressor, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, g_zlib_decompressor_iface_init)) @@ -76,6 +111,13 @@ g_zlib_decompressor_finalize (GObject *object) inflateEnd (&decompressor->zstream); + if (decompressor->header_data != NULL) + { + if (decompressor->header_data->file_info) + g_object_unref (decompressor->header_data->file_info); + g_free (decompressor->header_data); + } + G_OBJECT_CLASS (g_zlib_decompressor_parent_class)->finalize (object); } @@ -119,6 +161,13 @@ g_zlib_decompressor_get_property (GObject *object, g_value_set_enum (value, decompressor->format); break; + case PROP_FILE_INFO: + if (decompressor->header_data) + g_value_set_object (value, decompressor->header_data->file_info); + else + g_value_set_object (value, NULL); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -156,6 +205,8 @@ g_zlib_decompressor_constructed (GObject *object) if (res != Z_OK) g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg); + + g_zlib_decompressor_set_gzheader (decompressor); } static void @@ -177,6 +228,25 @@ g_zlib_decompressor_class_init (GZlibDecompressorClass *klass) G_ZLIB_COMPRESSOR_FORMAT_ZLIB, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GZlibDecompressor:file-info: + * + * A #GFileInfo containing the information found in the GZIP header + * of the data stream processed, or %NULL if the header was not yet + * fully processed, is not present at all, or the compressor's + * #GZlibDecompressor:format property is not %G_ZLIB_COMPRESSOR_FORMAT_GZIP. + * + * Since: 2.26 + */ + g_object_class_install_property (gobject_class, + PROP_FILE_INFO, + g_param_spec_object ("file-info", + P_("file info"), + P_("File info"), + G_TYPE_FILE_INFO, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); } /** @@ -201,6 +271,31 @@ g_zlib_decompressor_new (GZlibCompressorFormat format) return decompressor; } +/** + * g_zlib_decompressor_get_file_info: + * @decompressor: a #GZlibDecompressor + * + * Retrieves the #GFileInfo constructed from the GZIP header data + * of compressed data processed by @compressor, or %NULL if @decompressor's + * #GZlibDecompressor:format property is not %G_ZLIB_COMPRESSOR_FORMAT_GZIP, + * or the header data was not fully processed yet, or it not present in the + * data stream at all. + * + * Returns: (transfer none): a #GFileInfo, or %NULL + * + * Since: 2.26 + */ +GFileInfo * +g_zlib_decompressor_get_file_info (GZlibDecompressor *decompressor) +{ + g_return_val_if_fail (G_IS_ZLIB_DECOMPRESSOR (decompressor), NULL); + + if (decompressor->header_data) + return decompressor->header_data->file_info; + + return NULL; +} + static void g_zlib_decompressor_reset (GConverter *converter) { @@ -210,6 +305,8 @@ g_zlib_decompressor_reset (GConverter *converter) res = inflateReset (&decompressor->zstream); if (res != Z_OK) g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg); + + g_zlib_decompressor_set_gzheader (decompressor); } static GConverterResult @@ -271,17 +368,38 @@ g_zlib_decompressor_convert (GConverter *converter, return G_CONVERTER_ERROR; } - if (res == Z_OK || res == Z_STREAM_END) + g_assert (res == Z_OK || res == Z_STREAM_END); + + *bytes_read = inbuf_size - decompressor->zstream.avail_in; + *bytes_written = outbuf_size - decompressor->zstream.avail_out; + + if (decompressor->header_data != NULL && + decompressor->header_data->gzheader.done == 1) { - *bytes_read = inbuf_size - decompressor->zstream.avail_in; - *bytes_written = outbuf_size - decompressor->zstream.avail_out; + HeaderData *data = decompressor->header_data; + + /* So we don't notify again */ + data->gzheader.done = 2; + + data->file_info = g_file_info_new (); + g_file_info_set_attribute_uint64 (data->file_info, + G_FILE_ATTRIBUTE_TIME_MODIFIED, + data->gzheader.time); + g_file_info_set_attribute_uint32 (data->file_info, + G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, + 0); + + if (data->filename[0] != '\0') + g_file_info_set_attribute_byte_string (data->file_info, + G_FILE_ATTRIBUTE_STANDARD_NAME, + data->filename); - if (res == Z_STREAM_END) - return G_CONVERTER_FINISHED; - return G_CONVERTER_CONVERTED; + g_object_notify (G_OBJECT (decompressor), "file-info"); } - g_assert_not_reached (); + if (res == Z_STREAM_END) + return G_CONVERTER_FINISHED; + return G_CONVERTER_CONVERTED; } static void diff --git a/gio/gzlibdecompressor.h b/gio/gzlibdecompressor.h index fa334c2b6..f7bb57dde 100644 --- a/gio/gzlibdecompressor.h +++ b/gio/gzlibdecompressor.h @@ -28,6 +28,7 @@ #define __G_ZLIB_DECOMPRESSOR_H__ #include <gio/gconverter.h> +#include <gio/gfileinfo.h> G_BEGIN_DECLS @@ -49,6 +50,8 @@ GType g_zlib_decompressor_get_type (void) G_GNUC_CONST; GZlibDecompressor *g_zlib_decompressor_new (GZlibCompressorFormat format); +GFileInfo *g_zlib_decompressor_get_file_info (GZlibDecompressor *decompressor); + G_END_DECLS #endif /* __G_ZLIB_DECOMPRESSOR_H__ */ diff --git a/gio/tests/filter-cat.c b/gio/tests/filter-cat.c index 770ab1a9d..ff7ddd3c7 100644 --- a/gio/tests/filter-cat.c +++ b/gio/tests/filter-cat.c @@ -50,6 +50,23 @@ static GOptionEntry entries[] = { }; static void +decompressor_file_info_notify_cb (GZlibDecompressor *decompressor, + GParamSpec *pspec, + gpointer data) +{ + GFileInfo *file_info; + const gchar *filename; + + file_info = g_zlib_decompressor_get_file_info (decompressor); + if (file_info == NULL) + return; + + filename = g_file_info_get_name (file_info); + if (filename) + g_printerr ("Decompressor filename: %s\n", filename); +} + +static void cat (GFile * file) { GInputStream *in; @@ -79,6 +96,7 @@ cat (GFile * file) conv = (GConverter *)g_zlib_decompressor_new (gzip?G_ZLIB_COMPRESSOR_FORMAT_GZIP:G_ZLIB_COMPRESSOR_FORMAT_ZLIB); old = in; in = (GInputStream *) g_converter_input_stream_new (in, conv); + g_signal_connect (conv, "notify::file-info", G_CALLBACK (decompressor_file_info_notify_cb), NULL); g_object_unref (conv); g_object_unref (old); } @@ -108,11 +126,29 @@ cat (GFile * file) if (compress) { GInputStream *old; - conv = (GConverter *)g_zlib_compressor_new (gzip?G_ZLIB_COMPRESSOR_FORMAT_GZIP:G_ZLIB_COMPRESSOR_FORMAT_ZLIB, -1); + GFileInfo *in_file_info; + + in_file_info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_TIME_MODIFIED, + G_FILE_QUERY_INFO_NONE, + NULL, + &error); + if (in_file_info == NULL) + { + g_printerr ("%s: %s: error reading file info: %s\n", + g_get_prgname (), g_file_get_uri (file), error->message); + g_error_free (error); + return; + } + + conv = (GConverter *)g_zlib_compressor_new(gzip?G_ZLIB_COMPRESSOR_FORMAT_GZIP:G_ZLIB_COMPRESSOR_FORMAT_ZLIB, -1); + g_zlib_compressor_set_file_info (G_ZLIB_COMPRESSOR (conv), in_file_info); old = in; in = (GInputStream *) g_converter_input_stream_new (in, conv); g_object_unref (conv); g_object_unref (old); + g_object_unref (in_file_info); } while (1) |