Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gimp/plug-ins/common/   (Gimp Bildeditor Version 3.2.0©)  Datei vom 14.2.2026 mit Größe 30 kB image not shown  

Quelle  file-compressor.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 * Copyright (C) 1997 Daniel Risacher, magnus@alum.mit.edu
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */


/* Minor changes to support file magic */
/* 4 Oct 1997 -- Risacher */

/* compressor plug-in for GIMP           */
/* based on gz.c which in turn is        */
/* loosely based on url.c by             */
/* Josh MacDonald, jmacd@cs.berkeley.edu */

/* 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
 * filename.foo.[gz|bz2] where foo is some already-recognized extension
 *
 * and it also works for names of the form
 * filename.xcf[gz|bz2] - which is equivalent to
 * filename.xcf.[gz|bz2]
 *
 * I added the xcfgz bit because having a default extension of xcf.gz
 * can confuse the file selection dialog box somewhat, forcing the
 * user to type sometimes when they otherwise wouldn't need to.
 *
 * I later decided I didn't like it because I don't like to bloat
 * the file-extension namespace.  But I left in the recognition
 * feature/bug so if people want to use files named foo.xcfgz by
 * default, they can just hack their pluginrc file.
 *
 * to do this hack, change :
 *                      "xcf.gz,gz,xcfgz"
 * to
 *                      "xcfgz,gz,xcf.gz"
 *
 *
 * -Dan Risacher, 0430 CDT, 26 May 1997
 */


#include "config.h"

#include <string.h>
#include <errno.h>

#include <sys/types.h>

#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif

#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif

#include <sys/stat.h>
#include <fcntl.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef _WIN32
#include <io.h>
#define close _close
#define fileno _fileno
#endif

#include <glib/gstdio.h>
#ifndef _O_BINARY
#define _O_BINARY 0
#endif

#include <libgimp/gimp.h>

#include "libgimp/stdplugins-intl.h"

#include <archive.h>
#include <archive_entry.h>
#include <zlib.h>
#include <bzlib.h>
#include <lzma.h>


/* Author 1: Josh MacDonald (url.c)          */
/* Author 2: Daniel Risacher (gz.c)          */
/* Author 3: Michael Natterer (compressor.c) */

/* According to USAF Lt Steve Werhle, US DoD software development
 * contracts average about $25 USD per source line of code (SLOC).  By
 * that metric, I figure this plug-in is worth about $10,000 USD */

/* But you got it free.   Magic of Gnu. */

typedef gboolean (* LoadFn) (GFile *infile,
                             GFile *outfile);
typedef gboolean (* SaveFn) (GFile *infile,
                             GFile *outfile);

typedef struct _CompressorEntry CompressorEntry;

struct _CompressorEntry
{
  const gchar *file_type;
  const gchar *mime_type;
  const gchar *extensions;
  const gchar *magic;
  const gchar *xcf_extension;
  const gchar *generic_extension;

  const gchar *load_proc;
  const gchar *load_blurb;
  const gchar *load_help;
  LoadFn       load_fn;

  const gchar *save_proc;
  const gchar *save_blurb;
  const gchar *save_help;
  SaveFn       save_fn;
};


typedef struct _Compressor      Compressor;
typedef struct _CompressorClass CompressorClass;

struct _Compressor
{
  GimpPlugIn      parent_instance;
};

struct _CompressorClass
{
  GimpPlugInClass parent_class;
};


#define COMPRESSOR_TYPE  (compressor_get_type ())
#define COMPRESSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COMPRESSOR_TYPE, Compressor))

GType                   compressor_get_type         (void) G_GNUC_CONST;

static GList          * compressor_query_procedures (GimpPlugIn            *plug_in);
static GimpProcedure  * compressor_create_procedure (GimpPlugIn            *plug_in,
                                                     const gchar           *name);

static GimpValueArray * compressor_export           (GimpProcedure         *procedure,
                                                     GimpRunMode            run_mode,
                                                     GimpImage             *image,
                                                     GFile                 *file,
                                                     GimpExportOptions     *options,
                                                     GimpMetadata          *metadata,
                                                     GimpProcedureConfig   *config,
                                                     gpointer               run_data);
static GimpValueArray * compressor_load             (GimpProcedure         *procedure,
                                                     GimpRunMode            run_mode,
                                                     GFile                 *file,
                                                     GimpMetadata          *metadata,
                                                     GimpMetadataLoadFlags *flags,
                                                     GimpProcedureConfig   *config,
                                                     gpointer              run_data);

static GimpImage         * load_image               (const CompressorEntry *compressor,
                                                     GFile                 *file,
                                                     gint32                 run_mode,
                                                     GimpPDBStatusType     *status,
                                                     GError               **error);
static GimpPDBStatusType   export_image             (const CompressorEntry *compressor,
                                                     GFile                 *file,
                                                     GimpImage             *image,
                                                     GimpExportOptions     *options,
                                                     gint                   n_drawables,
                                                     GList                 *drawables,
                                                     gint32                 run_mode,
                                                     GError               **error);

static gboolean            valid_file               (GFile                 *file);
static const gchar       * find_extension           (const CompressorEntry *compressor,
                                                     const gchar           *filename);

static gboolean            gzip_load                (GFile                 *infile,
                                                     GFile                 *outfile);
static gboolean            gzip_export              (GFile                 *infile,
                                                     GFile                 *outfile);

static gboolean            bzip2_load               (GFile                 *infile,
                                                     GFile                 *outfile);
static gboolean            bzip2_export             (GFile                 *infile,
                                                     GFile                 *outfile);

static gboolean            xz_load                  (GFile                 *infile,
                                                     GFile                 *outfile);
static gboolean            xz_export                (GFile                 *infile,
                                                     GFile                 *outfile);

static gboolean            zip_load                 (GFile                 *infile,
                                                     GFile                 *outfile);
static goffset             get_file_info            (GFile                 *file);


G_DEFINE_TYPE (Compressor, compressor, GIMP_TYPE_PLUG_IN)

GIMP_MAIN (COMPRESSOR_TYPE)
DEFINE_STD_SET_I18N


static const CompressorEntry compressors[] =
{
  {
    N_("gzip archive"),
    "application/x-gzip",
    "xcf.gz,xcfgz",
    "0,string,\037\213",
    ".xcfgz",
    ".gz",

    "file-gz-load",
    N_("Loads files compressed with gzip"),
    N_("This procedure loads files in the gzip compressed format."),
    gzip_load,

    "file-gz-export",
    N_("Exports files compressed with gzip"),
    N_("This procedure exports files in the gzip compressed format."),
    gzip_export
  },

  {
    N_("bzip archive"),
    "application/x-bzip",
    "xcf.bz2,xcfbz2",
    "0,string,BZh",
    ".xcfbz2",
    ".bz2",

    "file-bz2-load",
    N_("Loads files compressed with bzip2"),
    N_("This procedure loads files in the bzip2 compressed format."),
    bzip2_load,

    "file-bz2-export",
    N_("Exports files compressed with bzip2"),
    N_("This procedure exports files in the bzip2 compressed format."),
    bzip2_export
  },

  {
    N_("xz archive"),
    "application/x-xz",
    "xcf.xz,xcfxz",
    "0,string,\3757zXZ\x00",
    ".xcfxz",
    ".xz",

    "file-xz-load",
    N_("Loads files compressed with xz"),
    N_("This procedure loads files in the xz compressed format."),
    xz_load,

    "file-xz-export",
    N_("Exports files compressed with xz"),
    N_("This procedure exports files in the xz compressed format."),
    xz_export
  },

  {
    N_("zip archive"),
    "application/zip",
    "hgt.zip",
    "0,string,PK\x03\x04",
    ".xcfzip",
    ".zip",

    "file-zip-load",
    N_("Loads files compressed with zip"),
    N_("This procedure loads files in the zip compressed format."),
    zip_load,

    NULL,
    NULL,
    NULL,
    NULL
  }
};


static void
compressor_class_init (CompressorClass *klass)
{
  GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);

  plug_in_class->query_procedures = compressor_query_procedures;
  plug_in_class->create_procedure = compressor_create_procedure;
  plug_in_class->set_i18n         = STD_SET_I18N;
}

static void
compressor_init (Compressor *compressor)
{
}

static GList *
compressor_query_procedures (GimpPlugIn *plug_in)
{
  GList *list = NULL;
  gint   i;

  for (i = 0; i < G_N_ELEMENTS (compressors); i++)
    {
      const CompressorEntry *compressor = &compressors[i];

      list = g_list_append (list, g_strdup (compressor->load_proc));
      if (compressor->save_proc)
        list = g_list_append (list, g_strdup (compressor->save_proc));
    }

  return list;
}

static GimpProcedure *
compressor_create_procedure (GimpPlugIn  *plug_in,
                             const gchar *name)
{
  GimpProcedure *procedure = NULL;
  gint           i;

  for (i = 0; i < G_N_ELEMENTS (compressors); i++)
    {
      const CompressorEntry *compressor = &compressors[i];

      if (! strcmp (name, compressor->load_proc))
        {
          procedure = gimp_load_procedure_new (plug_in, name,
                                               GIMP_PDB_PROC_TYPE_PLUGIN,
                                               compressor_load,
                                               (gpointer) compressor, NULL);

          gimp_procedure_set_documentation (procedure,
                                            _(compressor->load_blurb),
                                            _(compressor->load_help),
                                            name);

          gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure),
                                          compressor->magic);
        }
      else if (compressor->save_proc && ! strcmp (name, compressor->save_proc))
        {
          procedure = gimp_export_procedure_new (plug_in, name,
                                                 GIMP_PDB_PROC_TYPE_PLUGIN,
                                                 FALSE, compressor_export,
                                                 (gpointer) compressor, NULL);

          gimp_procedure_set_image_types (procedure, "RGB*, GRAY*, INDEXED*");

          gimp_procedure_set_documentation (procedure,
                                            _(compressor->save_blurb),
                                            _(compressor->save_help),
                                            name);
        }

      if (procedure)
        {
          gimp_procedure_set_menu_label (procedure, _(compressor->file_type));

          gimp_procedure_set_attribution (procedure,
                                          "Daniel Risacher",
                                          "Daniel Risacher, Spencer Kimball "
                                          "and Peter Mattis",
                                          "1995-1997");

          gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
                                              compressor->mime_type);
          gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
                                              compressor->extensions);
          gimp_file_procedure_set_meta (GIMP_FILE_PROCEDURE (procedure),
                                        TRUE, compressor->generic_extension + 1);

          return procedure;
        }
    }

  return NULL;
}

static GimpValueArray *
compressor_load (GimpProcedure         *procedure,
                 GimpRunMode            run_mode,
                 GFile                 *file,
                 GimpMetadata          *metadata,
                 GimpMetadataLoadFlags *flags,
                 GimpProcedureConfig   *config,
                 gpointer               run_data)
{
  const CompressorEntry *compressor = run_data;
  GimpValueArray        *return_vals;
  GimpPDBStatusType      status;
  GimpImage             *image;
  GError                *error = NULL;

  /*  We handle PDB errors by forwarding them to the caller in
   *  our return values.
   */

  gimp_plug_in_set_pdb_error_handler (gimp_procedure_get_plug_in (procedure),
                                      GIMP_PDB_ERROR_HANDLER_PLUGIN);

  image = load_image (compressor, file, run_mode, &status, &error);

  return_vals = gimp_procedure_new_return_values (procedure, status, error);

  if (image && status == GIMP_PDB_SUCCESS)
    GIMP_VALUES_SET_IMAGE (return_vals, 1, image);

  return return_vals;
}

static GimpValueArray *
compressor_export (GimpProcedure        *procedure,
                   GimpRunMode           run_mode,
                   GimpImage            *image,
                   GFile                *file,
                   GimpExportOptions    *options,
                   GimpMetadata         *metadata,
                   GimpProcedureConfig  *config,
                   gpointer              run_data)
{
  const CompressorEntry *compressor  = run_data;
  GimpPDBStatusType      status;
  GList                 *drawables   = gimp_image_list_layers (image);
  gint                   n_drawables = g_list_length (drawables);
  GError                *error       = NULL;

  /*  We handle PDB errors by forwarding them to the caller in
   *  our return values.
   */

  gimp_plug_in_set_pdb_error_handler (gimp_procedure_get_plug_in (procedure),
                                      GIMP_PDB_ERROR_HANDLER_PLUGIN);

  status = export_image (compressor, file, image, options, n_drawables,
                         drawables, run_mode, &error);

  g_list_free (drawables);
  return gimp_procedure_new_return_values (procedure, status, error);
}

static GimpPDBStatusType
export_image (const CompressorEntry  *compressor,
              GFile                  *file,
              GimpImage              *image,
              GimpExportOptions      *options,
              gint                    n_drawables,
              GList                  *drawables,
              gint32                  run_mode,
              GError                **error)
{
  const gchar *ext;
  GFile       *tmp_file;

  ext = find_extension (compressor, g_file_peek_path (file));

  if (! ext)
    {
      g_message (_("No sensible file extension, saving as compressed XCF."));
      ext = ".xcf";
    }

  /* get a temp name with the right extension and save into it. */

  tmp_file = gimp_temp_file (ext + 1);

  if (! (gimp_file_save (run_mode, image, tmp_file, options) &&
         valid_file (tmp_file)))
    {
      g_file_delete (tmp_file, NULL, NULL);
      g_object_unref (tmp_file);

      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   "%s", gimp_pdb_get_last_error (gimp_get_pdb ()));

      return gimp_pdb_get_last_status (gimp_get_pdb ());
    }

  gimp_progress_init_printf (_("Compressing '%s'"),
                             gimp_file_get_utf8_name  (file));

  if (! compressor->save_fn (tmp_file, file))
    {
      g_file_delete (tmp_file, NULL, NULL);
      g_object_unref (tmp_file);

      return GIMP_PDB_EXECUTION_ERROR;
    }

  g_file_delete (tmp_file, NULL, NULL);
  g_object_unref (tmp_file);

  gimp_progress_update (1.0);

  /* ask the core to save a thumbnail for compressed XCF files */
  if (strcmp (ext, ".xcf") == 0)
    gimp_file_create_thumbnail (image, file);

  return GIMP_PDB_SUCCESS;
}

static GimpImage *
load_image (const CompressorEntry  *compressor,
            GFile                  *file,
            gint32                  run_mode,
            GimpPDBStatusType      *status,
            GError                **error)
{
  GimpImage   *image;
  const gchar *ext;
  GFile       *tmp_file;

  ext = find_extension (compressor, g_file_peek_path (file));

  if (! ext)
    {
      g_message (_("No sensible file extension, "
                   "attempting to load with file magic."));
      ext = ".foo";
    }

  /* find a temp name */
  tmp_file = gimp_temp_file (ext + 1);

  if (! compressor->load_fn (file, tmp_file))
    {
      g_object_unref (tmp_file);
      *status = GIMP_PDB_EXECUTION_ERROR;
      return NULL;
    }

  /* now that we uncompressed it, load the temp file */

  image = gimp_file_load (run_mode, tmp_file);

  g_file_delete (tmp_file, NULL, NULL);
  g_object_unref (tmp_file);

  if (image)
    {
      GFile *xcf_file;

      *status = GIMP_PDB_SUCCESS;

      if ((xcf_file = gimp_image_get_xcf_file (image)))
        /* Replace the temporary file with the actual source file, but
         * only if the inner format was actually XCF.
         */

        gimp_image_set_file (image, file);

      g_clear_object (&xcf_file);
    }
  else
    {
      /* Forward the return status of the underlining plug-in for the
       * given format.
       */

      *status = gimp_pdb_get_last_status (gimp_get_pdb ());

      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   "%s", gimp_pdb_get_last_error (gimp_get_pdb ()));
    }

  return image;
}

static gboolean
valid_file (GFile *file)
{
  GStatBuf  buf;
  gboolean  valid;

  valid = g_stat (g_file_peek_path (file), &buf) == 0 && buf.st_size > 0;

  return valid;
}

static const gchar *
find_extension (const CompressorEntry *compressor,
                const gchar           *filename)
{
  gchar *filename_copy;
  gchar *ext;

  /* we never free this copy - aren't we evil! */
  filename_copy = g_strdup (filename);

  /* find the extension, boy! */
  ext = strrchr (filename_copy, '.');

  while (TRUE)
    {
      if (!ext || ext[1] == '\0' || strchr (ext, G_DIR_SEPARATOR))
        {
          return NULL;
        }

      if (0 == g_ascii_strcasecmp (ext, compressor->xcf_extension))
        {
          return ".xcf";  /* we've found it */
        }
      if (0 != g_ascii_strcasecmp (ext, compressor->generic_extension))
        {
          return ext;
        }
      else
        {
          /* we found ".gz" so strip it, loop back, and look again */
          *ext = '\0';
          ext = strrchr (filename_copy, '.');
        }
    }
}

static gboolean
gzip_load (GFile *infile,
           GFile *outfile)
{
  gboolean  ret;
  int       fd;
  gzFile    in;
  FILE     *out;
  char      buf[16384];
  int       len;

  ret = FALSE;
  in = NULL;
  out = NULL;

  fd = g_open (g_file_peek_path (infile), O_RDONLY | _O_BINARY, 0);
  if (fd == -1)
    goto out;

  in = gzdopen (fd, "rb");
  if (! in)
    {
      close (fd);
      goto out;
    }

  out = g_fopen (g_file_peek_path (outfile), "wb");
  if (! out)
    goto out;

  while (TRUE)
    {
      len = gzread (in, buf, sizeof buf);

      if (len < 0)
        break;
      else if (len == 0)
        {
          ret = TRUE;
          break;
        }

      if (fwrite(buf, 1, len, out) != len)
        break;
    }

 out:
  /* There is no need to close(fd) as it is closed by gzclose(). */
  if (in)
    if (gzclose (in) != Z_OK)
      ret = FALSE;

  if (out)
    fclose (out);

  return ret;
}

static gboolean
gzip_export (GFile *infile,
             GFile *outfile)
{
  gboolean  ret;
  FILE     *in;
  int       fd;
  gzFile    out;
  char      buf[16384];
  int       len;
  goffset   tot = 0, file_size;

  ret = FALSE;
  in = NULL;
  out = NULL;

  in = g_fopen (g_file_peek_path (infile), "rb");
  if (! in)
    goto out;

  fd = g_open (g_file_peek_path (outfile), O_CREAT | O_WRONLY | O_TRUNC | _O_BINARY, 0664);
  if (fd == -1)
    goto out;

  out = gzdopen (fd, "wb");
  if (! out)
    {
      close (fd);
      goto out;
    }

  file_size = get_file_info (infile);
  while (TRUE)
    {
      len = fread (buf, 1, sizeof buf, in);
      if (ferror (in))
        break;

      if (len < 0)
        break;
      else if (len == 0)
        {
          ret = TRUE;
          break;
        }

      if (gzwrite (out, buf, len) != len)
        break;

      gimp_progress_update ((tot += len) * 1.0 / file_size);
    }

 out:
  if (in)
    fclose (in);

  /* There is no need to close(fd) as it is closed by gzclose(). */
  if (out)
    if (gzclose (out) != Z_OK)
      ret = FALSE;

  return ret;
}

static gboolean
bzip2_load (GFile *infile,
            GFile *outfile)
{
  gboolean  ret;
  int       fd;
  BZFILE   *in;
  FILE     *out;
  char      buf[16384];
  int       len;

  ret = FALSE;
  in = NULL;
  out = NULL;

  fd = g_open (g_file_peek_path (infile), O_RDONLY | _O_BINARY, 0);
  if (fd == -1)
    goto out;

  in = BZ2_bzdopen (fd, "rb");
  if (!in)
    {
      close (fd);
      goto out;
    }

  out = g_fopen (g_file_peek_path (outfile), "wb");
  if (!out)
    goto out;

  while (TRUE)
    {
      len = BZ2_bzread (in, buf, sizeof buf);

      if (len < 0)
        break;
      else if (len == 0)
        {
          ret = TRUE;
          break;
        }

      if (fwrite(buf, 1, len, out) != len)
        break;
    }

 out:
  /* TODO: Check this in the case of BZ2_bzclose(): */
  /* There is no need to close(fd) as it is closed by BZ2_bzclose(). */
  if (in)
    BZ2_bzclose (in);

  if (out)
    fclose (out);

  return ret;
}

static gboolean
bzip2_export (GFile *infile,
              GFile *outfile)
{
  gboolean  ret;
  FILE     *in;
  int       fd;
  BZFILE   *out;
  char      buf[16384];
  int       len;
  goffset   tot = 0, file_size;

  ret = FALSE;
  in = NULL;
  out = NULL;

  in = g_fopen (g_file_peek_path (infile), "rb");
  if (!in)
    goto out;

  fd = g_open (g_file_peek_path (outfile), O_CREAT | O_WRONLY | O_TRUNC | _O_BINARY, 0664);
  if (fd == -1)
    goto out;

  out = BZ2_bzdopen (fd, "wb");
  if (!out)
    {
      close (fd);
      goto out;
    }

  file_size = get_file_info (infile);
  while (TRUE)
    {
      len = fread (buf, 1, sizeof buf, in);
      if (ferror (in))
        break;

      if (len < 0)
        break;
      else if (len == 0)
        {
          ret = TRUE;
          break;
        }

      if (BZ2_bzwrite (out, buf, len) != len)
        break;

      gimp_progress_update ((tot += len) * 1.0 / file_size);
    }

 out:
  if (in)
    fclose (in);

  /* TODO: Check this in the case of BZ2_bzclose(): */
  /* There is no need to close(fd) as it is closed by BZ2_bzclose(). */
  if (out)
    BZ2_bzclose (out);

  return ret;
}

static gboolean
xz_load (GFile *infile,
         GFile *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 (g_file_peek_path (infile), "rb");
  if (!in)
    goto out;

  out = g_fopen (g_file_peek_path (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_export (GFile *infile,
           GFile *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;
  goffset      tot = 0, file_size;

  ret = FALSE;
  in = NULL;
  out = NULL;

  in = g_fopen (g_file_peek_path (infile), "rb");
  if (!in)
    goto out;

  file_size = get_file_info (infile);
  out = g_fopen (g_file_peek_path (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;

          gimp_progress_update ((tot += strm.avail_in) * 1.0 / file_size);
        }

      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
zip_load (GFile *infile,
          GFile *outfile)
{
  gboolean              ret;
  FILE                 *in;
  FILE                 *out;
  struct archive       *a;
  struct archive_entry *entry;
  gint                  r;

  ret = FALSE;
  in  = NULL;
  out = NULL;

  in = g_fopen (g_file_peek_path (infile), "rb");
  if (!in)
    goto out;

  out = g_fopen (g_file_peek_path (outfile), "wb");
  if (! out)
    goto out;

  if ((a = archive_read_new ()))
    {
      const gchar *name = gimp_file_get_utf8_name (infile);

      archive_read_support_format_all (a);

      r = archive_read_open_filename (a, name, 10240);
      if (r != ARCHIVE_OK)
        {
          archive_read_close (a);
          archive_read_free (a);

          goto out;
        }

      if (archive_read_next_header (a, &entry) == ARCHIVE_OK)
        {
          r = archive_read_data_into_fd (a, fileno (out));

          if (r != ARCHIVE_OK)
            {
              archive_read_close (a);
              archive_read_free (a);

              goto out;
            }
          ret = TRUE;

          if (archive_read_next_header (a, &entry) != ARCHIVE_EOF)
            /* Leave a chance for the load to succeed (in case the first
             * file happens to be an image file), yet still warns. This
             * procedure expects that the archive contains a single
             * file.
             */

            g_message (_("This zip archive contains more than one file."));
        }
      archive_read_close (a);
      archive_read_free (a);
    }

 out:
  if (in)
    fclose (in);

  if (out)
    fclose (out);

  return ret;
}

/* get file size from a filename */
static goffset
get_file_info (GFile *file)
{
  GFileInfo *info;
  goffset    size = 1;

  info = g_file_query_info (file,
                            G_FILE_ATTRIBUTE_STANDARD_SIZE,
                            G_FILE_QUERY_INFO_NONE,
                            NULL, NULL);

  if (info)
    {
      size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE);

      g_object_unref (info);
    }

  return size;
}

Messung
CHZG
839610093

¤ Dauer der Verarbeitung: 0.12 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.