[gimp] file-compressor: Add support for xz compressed files (bug #683159)



commit fc4a192f23bb44a59e199118c8c8a7d3027d6fd1
Author: Mukund Sivaraman <muks banu com>
Date:   Sun Sep 2 04:32:04 2012 +0530

    file-compressor: Add support for xz compressed files (bug #683159)
    
    This commit causes a compiler warning because string literals are of
    type signed char, and we use a character out of the signed range in the
    mimetype for xz.  It can be fixed by changing the data type of the mime
    string to (unsigned char *), and not using string literals, but that's
    a bit too much for this commit.

 configure.ac                               |   29 ++++-
 plug-ins/file-compressor/Makefile.am       |    4 +-
 plug-ins/file-compressor/file-compressor.c |  207 ++++++++++++++++++++++++++++
 3 files changed, 238 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 6ae2ad6..d1e076f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -63,6 +63,7 @@ m4_define([libgudev_required_version], [167])
 m4_define([exif_required_version], [0.6.15])
 m4_define([lcms_required_version], [1.16])
 m4_define([libpng_required_version], [1.2.37])
+m4_define([liblzma_required_version], [5.0.0])
 
 
 AC_INIT([GIMP], [gimp_version],
@@ -1176,8 +1177,34 @@ fi
 AM_CONDITIONAL(HAVE_BZIP2, test "x$have_libbzip2" = xyes)
 AC_SUBST(BZIP2_LIBS)
 
+
+###################
+# Check for liblzma
+###################
+
+AC_ARG_WITH(liblzma,  [  --without-liblzma       build without LZMA support])
+
+have_liblzma=no
+if test "x$with_liblzma" != xno; then
+  have_liblzma=yes
+  PKG_CHECK_MODULES(LZMA, liblzma >= liblzma_required_version,
+    AC_DEFINE(HAVE_LIBLZMA, 1, [Define to 1 if liblzma is available]),
+    have_liblzma="no (liblzma not found or too old)")
+fi
+
+AC_SUBST(LZMA_CFLAGS)
+AC_SUBST(LZMA_LIBS)
+
+AM_CONDITIONAL(HAVE_LIBLZMA, test "x$have_liblzma" = xyes)
+
+
+#######################################################################
+# file-compressor is only built when all the compressor libraries are
+# available. We should revisit this at some point to make it build even
+# with fewer libraries.
+#######################################################################
 have_compressor=no
-if test "x$have_zlib" = xyes && test "x$have_libbzip2" = xyes; then
+if test "x$have_zlib" = xyes && test "x$have_libbzip2" = xyes && test "x$have_liblzma" = xyes; then
    have_compressor=yes
 fi
 
diff --git a/plug-ins/file-compressor/Makefile.am b/plug-ins/file-compressor/Makefile.am
index e8263a4..710117b 100644
--- a/plug-ins/file-compressor/Makefile.am
+++ b/plug-ins/file-compressor/Makefile.am
@@ -23,6 +23,7 @@ INCLUDES = \
 	-I$(top_srcdir)	\
 	$(GTK_CFLAGS)	\
 	$(GEGL_CFLAGS) \
+	$(LZMA_CFLAGS) \
 	-I$(includedir)
 
 LDADD = \
@@ -35,4 +36,5 @@ LDADD = \
 	$(RT_LIBS)		\
 	$(INTLLIBS)		\
 	$(Z_LIBS)		\
-	$(BZIP2_LIBS)
+	$(BZIP2_LIBS)		\
+	$(LZMA_LIBS)
diff --git a/plug-ins/file-compressor/file-compressor.c b/plug-ins/file-compressor/file-compressor.c
index 8bfcc38..d5843c5 100644
--- a/plug-ins/file-compressor/file-compressor.c
+++ b/plug-ins/file-compressor/file-compressor.c
@@ -27,6 +27,9 @@
 /* and, very loosely on hrz.c by */
 /* Albert Cahalan <acahalan at cs.uml.edu> */
 
+/* LZMA compression code is based on code by Lasse Collin which was
+ * placed in the public-domain. */
+
 /* This is reads and writes compressed image files for GIMP
  *
  * It should work with file names of the form
@@ -87,6 +90,7 @@
 
 #include <zlib.h>
 #include <bzlib.h>
+#include <lzma.h>
 
 /* Author 1: Josh MacDonald (url.c)          */
 /* Author 2: Daniel Risacher (gz.c)          */
@@ -159,6 +163,12 @@ bzip2_load                                (const char         *infile,
 static gboolean
 bzip2_save                                (const char         *infile,
                                            const char         *outfile);
+static gboolean
+xz_load                                   (const char         *infile,
+                                           const char         *outfile);
+static gboolean
+xz_save                                   (const char         *infile,
+                                           const char         *outfile);
 
 static const Compressor compressors[] =
 {
@@ -198,6 +208,25 @@ static const Compressor compressors[] =
     "saves files compressed with bzip2",
     "This procedure saves files in the bzip2 compressed format.",
     bzip2_save
+  },
+
+  {
+    N_("xz archive"),
+    "application/x-xz",
+    "xcf.xz,xz,xcfxz",
+    "0,ustring,\xFD7zXZ\x00",
+    ".xcfxz",
+    ".xz",
+
+    "file-xz-load",
+    "loads files compressed with xz",
+    "This procedure loads files in the xz compressed format.",
+    xz_load,
+
+    "file-xz-save",
+    "saves files compressed with xz",
+    "This procedure saves files in the xz compressed format.",
+    xz_save
   }
 };
 
@@ -764,3 +793,181 @@ bzip2_save (const char *infile,
 
   return ret;
 }
+
+static gboolean
+xz_load (const char *infile,
+         const char *outfile)
+{
+  gboolean ret;
+  FILE *in;
+  FILE *out;
+  lzma_stream strm = LZMA_STREAM_INIT;
+  lzma_action action;
+  guint8 inbuf[BUFSIZ];
+  guint8 outbuf[BUFSIZ];
+  lzma_ret status;
+
+  ret = FALSE;
+  in = NULL;
+  out = NULL;
+
+  in = g_fopen (infile, "rb");
+  if (!in)
+    goto out;
+
+  out = g_fopen (outfile, "wb");
+  if (!out)
+    goto out;
+
+  if (lzma_stream_decoder (&strm, UINT64_MAX, 0) != LZMA_OK)
+    goto out;
+
+  strm.next_in = NULL;
+  strm.avail_in = 0;
+  strm.next_out = outbuf;
+  strm.avail_out = sizeof outbuf;
+
+  action = LZMA_RUN;
+  status = LZMA_OK;
+
+  while (status == LZMA_OK)
+    {
+      /* Fill the input buffer if it is empty. */
+      if ((strm.avail_in == 0) && (!feof(in)))
+        {
+          strm.next_in = inbuf;
+          strm.avail_in = fread (inbuf, 1, sizeof inbuf, in);
+
+          if (ferror (in))
+            goto out;
+
+          /* Once the end of the input file has been reached, we need to
+             tell lzma_code() that no more input will be coming and that
+             it should finish the encoding. */
+          if (feof (in))
+            action = LZMA_FINISH;
+        }
+
+      status = lzma_code (&strm, action);
+
+      if ((strm.avail_out == 0) || (status == LZMA_STREAM_END))
+        {
+          /* When lzma_code() has returned LZMA_STREAM_END, the output
+             buffer is likely to be only partially full. Calculate how
+             much new data there is to be written to the output file. */
+          size_t write_size = sizeof outbuf - strm.avail_out;
+
+          if (fwrite (outbuf, 1, write_size, out) != write_size)
+            goto out;
+
+          /* Reset next_out and avail_out. */
+          strm.next_out = outbuf;
+          strm.avail_out = sizeof outbuf;
+        }
+    }
+
+  if (status != LZMA_STREAM_END)
+    goto out;
+
+  lzma_end (&strm);
+  ret = TRUE;
+
+ out:
+  if (in)
+    fclose (in);
+
+  if (out)
+    fclose (out);
+
+  return ret;
+}
+
+static gboolean
+xz_save (const char *infile,
+         const char *outfile)
+{
+  gboolean ret;
+  FILE *in;
+  FILE *out;
+  lzma_stream strm = LZMA_STREAM_INIT;
+  lzma_action action;
+  guint8 inbuf[BUFSIZ];
+  guint8 outbuf[BUFSIZ];
+  lzma_ret status;
+
+  ret = FALSE;
+  in = NULL;
+  out = NULL;
+
+  in = g_fopen (infile, "rb");
+  if (!in)
+    goto out;
+
+  out = g_fopen (outfile, "wb");
+  if (!out)
+    goto out;
+
+  if (lzma_easy_encoder (&strm,
+                         LZMA_PRESET_DEFAULT,
+                         LZMA_CHECK_CRC64) != LZMA_OK)
+    goto out;
+
+  strm.next_in = NULL;
+  strm.avail_in = 0;
+  strm.next_out = outbuf;
+  strm.avail_out = sizeof outbuf;
+
+  action = LZMA_RUN;
+  status = LZMA_OK;
+
+  while (status == LZMA_OK)
+    {
+      /* Fill the input buffer if it is empty. */
+      if ((strm.avail_in == 0) && (!feof(in)))
+        {
+          strm.next_in = inbuf;
+          strm.avail_in = fread (inbuf, 1, sizeof inbuf, in);
+
+          if (ferror (in))
+            goto out;
+
+          /* Once the end of the input file has been reached, we need to
+             tell lzma_code() that no more input will be coming and that
+             it should finish the encoding. */
+          if (feof (in))
+            action = LZMA_FINISH;
+        }
+
+      status = lzma_code (&strm, action);
+
+      if ((strm.avail_out == 0) || (status == LZMA_STREAM_END))
+        {
+          /* When lzma_code() has returned LZMA_STREAM_END, the output
+             buffer is likely to be only partially full. Calculate how
+             much new data there is to be written to the output file. */
+          size_t write_size = sizeof outbuf - strm.avail_out;
+
+          if (fwrite (outbuf, 1, write_size, out) != write_size)
+            goto out;
+
+          /* Reset next_out and avail_out. */
+          strm.next_out = outbuf;
+          strm.avail_out = sizeof outbuf;
+        }
+    }
+
+  if (status != LZMA_STREAM_END)
+    goto out;
+
+  lzma_end (&strm);
+  ret = TRUE;
+
+ out:
+  if (in)
+    fclose (in);
+
+  if (out)
+    fclose (out);
+
+  return ret;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]