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/gzlibdecompressor.c | |
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/gzlibdecompressor.c')
-rw-r--r-- | gio/gzlibdecompressor.c | 134 |
1 files changed, 126 insertions, 8 deletions
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 |