[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / gio / gzlibcompressor.c
index fa657fa..68445d0 100644 (file)
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Alexander Larsson <alexl@redhat.com>
  */
 
 #include "config.h"
 
+#include "gzlibcompressor.h"
+
 #include <errno.h>
 #include <zlib.h>
 #include <string.h>
 
-#include "gzlibcompressor.h"
-#include "glib.h"
+#include "gfileinfo.h"
 #include "gioerror.h"
-#include "glibintl.h"
 #include "gioenums.h"
 #include "gioenumtypes.h"
+#include "glibintl.h"
 
-#include "gioalias.h"
 
 enum {
   PROP_0,
   PROP_FORMAT,
-  PROP_LEVEL
+  PROP_LEVEL,
+  PROP_FILE_INFO
 };
 
 /**
@@ -64,8 +63,37 @@ struct _GZlibCompressor
   GZlibCompressorFormat format;
   int level;
   z_stream zstream;
+  gz_header gzheader;
+  GFileInfo *file_info;
 };
 
+static void
+g_zlib_compressor_set_gzheader (GZlibCompressor *compressor)
+{
+  /* On win32, these functions were not exported before 1.2.4 */
+#if !defined (G_OS_WIN32) || ZLIB_VERNUM >= 0x1240
+  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);
+#endif /* !G_OS_WIN32 || ZLIB >= 1.2.4 */
+}
+
 G_DEFINE_TYPE_WITH_CODE (GZlibCompressor, g_zlib_compressor, G_TYPE_OBJECT,
                         G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
                                                g_zlib_compressor_iface_init))
@@ -79,6 +107,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);
 }
 
@@ -103,6 +134,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;
@@ -130,6 +165,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;
@@ -173,6 +212,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
@@ -204,6 +245,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 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));
 }
 
 /**
@@ -231,6 +290,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)
 {
@@ -240,6 +352,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
@@ -319,6 +434,3 @@ g_zlib_compressor_iface_init (GConverterIface *iface)
   iface->convert = g_zlib_compressor_convert;
   iface->reset = g_zlib_compressor_reset;
 }
-
-#define __G_ZLIB_COMPRESSOR_C__
-#include "gioaliasdef.c"