[gcab/wip/hughsie/future: 6/18] Use g_autoptr() to fix several memory leaks in the library



commit d02b7219132c83c7c9b3e1d4738def38b44689e9
Author: Richard Hughes <richard hughsie com>
Date:   Tue Dec 12 15:31:33 2017 +0000

    Use g_autoptr() to fix several memory leaks in the library
    
    The biggest change is to use the new-ish G_DECLARE_FINAL_TYPE to get rid of a
    lot of C boilerplate.
    
    This also gives us the new g_autoptr() cleanup functions for each object which
    we can use to clean up the memory management in the command line tool and
    removes a lot of memory leaks in the error paths.

 gcab.c                 |  203 +++++++++++++++++++++++-------------------------
 libgcab/gcab-cabinet.c |  116 +++++++++++----------------
 libgcab/gcab-cabinet.h |   24 ++----
 libgcab/gcab-file.c    |   45 ++++++++++-
 libgcab/gcab-file.h    |   24 ++----
 libgcab/gcab-folder.c  |   96 +++++++++++------------
 libgcab/gcab-folder.h  |   16 +----
 libgcab/gcab-priv.h    |   29 ++------
 8 files changed, 254 insertions(+), 299 deletions(-)
---
diff --git a/gcab.c b/gcab.c
index 18f5842..4d04ae3 100644
--- a/gcab.c
+++ b/gcab.c
@@ -1,6 +1,7 @@
 /*
  * LibGCab
  * Copyright (c) 2012, Marc-André Lureau <marcandre lureau gmail com>
+ * Copyright (c) 2017, Richard Hughes <richard hughsie com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,20 +27,6 @@
 #include <locale.h>
 #include <glib/gi18n.h>
 
-G_GNUC_PRINTF(1, 2) static void
-gcab_error (const gchar *format, ...)
-{
-    va_list args;
-
-    g_fprintf (stderr, PACKAGE_NAME ": ");
-    va_start(args, format);
-    g_vfprintf (stderr, format, args);
-    va_end(args);
-    g_fprintf (stderr, "\n");
-
-    exit (1);
-}
-
 int verbose = 0;
 
 static gboolean
@@ -52,11 +39,10 @@ file_callback (GCabFile *cabfile, gpointer data)
         return TRUE;
 
     if (file) {
-        gchar *path =  g_file_get_relative_path (cwd, file);
+        g_autofree gchar *path =  g_file_get_relative_path (cwd, file);
         if (!path)
             path = g_file_get_parse_name (file);
         g_print ("%s\n", path);
-        g_free (path);
     } else {
         g_print ("%s\n", gcab_file_get_name (cabfile));
     }
@@ -86,35 +72,35 @@ remove_leading_path (gchar *name)
     return name + i;
 }
 
-static
-void save_array_to_file (const GByteArray *array, const gchar *base, const gchar *suffix)
+static gboolean
+save_array_to_file (const GByteArray *array, const gchar *base, const gchar *suffix, GError **error)
 {
-    GError *error = NULL;
-    gchar *resname = g_strdup_printf ("%s.%s", base, suffix);
+    g_autofree gchar *resname = NULL;
+    g_autoptr(GFile) outputfile = NULL;
+    g_autoptr(GOutputStream) output = NULL;
+    resname = g_strdup_printf ("%s.%s", base, suffix);
     g_print (_("Dumping %s data to: %s ...\n"), suffix, resname);
-    GFile *outputfile = g_file_new_for_commandline_arg (resname);
-    GOutputStream *output = G_OUTPUT_STREAM (g_file_replace (outputfile, NULL, FALSE, 0, NULL, &error));
-
-    if (!error)
-        g_output_stream_write_all (output, array->data, array->len, NULL, NULL, &error);
-
-    if (error)
-        gcab_error (_("can't write file %s: %s"), resname, error->message);
-
-    g_object_unref (output);
-    g_object_unref (outputfile);
-    g_free (resname);
-    g_clear_error (&error);
+    outputfile = g_file_new_for_commandline_arg (resname);
+    output = G_OUTPUT_STREAM (g_file_replace (outputfile, NULL, FALSE, 0, NULL, error));
+    if (output == NULL) {
+        g_prefix_error (error, _("Cannot write file %s: "), resname);
+        return FALSE;
+    }
+    if (!g_output_stream_write_all (output, array->data, array->len, NULL, NULL, error)) {
+        g_prefix_error (error, _("Cannot write file %s: "), resname);
+        return FALSE;
+    }
+    return TRUE;
 }
 
 int
 main (int argc, char *argv[])
 {
-    GError *error = NULL;
-    GOptionContext *context;
+    g_autoptr(GError) error = NULL;
+    g_autoptr(GOptionContext) context = NULL;
 
-    gchar **args = NULL;
-    gchar *change = NULL;
+    g_auto(GStrv) args = NULL;
+    g_autofree gchar *change = NULL;
     gboolean version = FALSE;
     gboolean nopath = FALSE;
     gboolean space = FALSE;
@@ -151,50 +137,59 @@ main (int argc, char *argv[])
     g_set_prgname (PACKAGE_NAME);
 
     context = g_option_context_new (_("- create a Cabinet file"));
-    gchar *s = g_strdup_printf (_("Report bugs to <%s>"), PACKAGE_BUGREPORT);
+    g_autofree gchar *s = g_strdup_printf (_("Report bugs to <%s>"), PACKAGE_BUGREPORT);
     g_option_context_set_description (context, s);
-    g_free(s);
     g_option_context_set_summary (context, _("\
 gcab saves many files together into a cabinet archive, and can restore\n\
 individual files from the archive.\
 "));
     g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
     g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
-    if (!g_option_context_parse (context, &argc, &argv, &error))
-        gcab_error (_("option parsing failed: %s\n"), (error && error->message) ? error->message : "unknown 
error");
-    g_option_context_free(context);
+    if (!g_option_context_parse (context, &argc, &argv, &error)) {
+        g_printerr ("%s: %s\n", _("Option parsing failed"), error->message);
+        return EXIT_FAILURE;
+    }
 
     if (version) {
         g_printf (PACKAGE_STRING "\n");
         return 0;
     }
 
-    if ((list + extract + create + dump_reserved + list_details) != 1)
-        gcab_error (_("Please specify a single operation."));
+    if ((list + extract + create + dump_reserved + list_details) != 1) {
+        g_printerr ("%s\n", _("Please specify a single operation"));
+        return EXIT_FAILURE;
+    }
 
-    if (!args || args[0] == NULL)
-        gcab_error (_("cabinet file must be specified."));
+    if (!args || args[0] == NULL) {
+        g_printerr ("%s\n", _("Cabinet file must be specified"));
+        return EXIT_FAILURE;
+    }
 
-    GCancellable *cancellable = g_cancellable_new ();
-    GCabCabinet *cabinet = gcab_cabinet_new ();
-    GCabFolder *folder;
-    GFile *outputfile;
-    GOutputStream *output;
-    GFile *cwd;
+    g_autoptr(GCabCabinet) cabinet = gcab_cabinet_new ();
+    g_autoptr(GCabFolder) folder = NULL;
+    g_autoptr(GCancellable) cancellable = g_cancellable_new ();
+    g_autoptr(GFile) cwd = NULL;
+    g_autoptr(GFile) outputfile = NULL;
+    g_autoptr(GOutputStream) output = NULL;
 
     if (list || list_details || extract || dump_reserved) {
-        GFile *file = g_file_new_for_commandline_arg (args[0]);
-        GInputStream *in = G_INPUT_STREAM (g_file_read (file, cancellable, &error));
+        g_autoptr(GFile) file = g_file_new_for_commandline_arg (args[0]);
+        g_autoptr(GInputStream) in = G_INPUT_STREAM (g_file_read (file, cancellable, &error));
 
-        if (!in)
-            gcab_error (_("can't open %s for reading: %s\n"), args[0], (error && error->message) ? 
error->message : "unknown error");
-        if (!gcab_cabinet_load (cabinet, in, cancellable, &error))
-            gcab_error (_("error reading %s: %s\n"), args[0], (error && error->message) ? error->message : 
"unknown error");
+        if (in == NULL) {
+            g_printerr ("%s %s: %s\n", _("Cannot open file for reading"), args[0], error->message);
+            return EXIT_FAILURE;
+        }
+        if (!gcab_cabinet_load (cabinet, in, cancellable, &error)) {
+            g_printerr ("%s %s: %s\n", _("Error reading"), args[0], error->message);
+            return EXIT_FAILURE;
+        }
 
         if (list || list_details) {
             GPtrArray *folders = gcab_cabinet_get_folders (cabinet);
             for (guint i = 0; i < folders->len; i++) {
-                GSList *l, *files = gcab_folder_get_files (g_ptr_array_index (folders, i));
+                GSList *l;
+                g_autoptr(GSList) files = gcab_folder_get_files (g_ptr_array_index (folders, i));
 
                 for (l = files; l != NULL; l = l->next) {
                     if (list_details) {
@@ -215,93 +210,91 @@ individual files from the archive.\
                         g_print ("%s\n", gcab_file_get_name (GCAB_FILE (l->data)));
                     }
                 }
-                g_slist_free (files);
             }
         } else if (extract) {
-            g_object_unref (file);
+            g_autoptr(GFile) file2 = NULL;
             if (change == NULL)
                 change = g_get_current_dir ();
-            file = g_file_new_for_path (change);
-
-            if (!gcab_cabinet_extract (cabinet, file, file_callback, NULL, NULL, cancellable, &error))
-                gcab_error (_("error during extraction: %s"), (error && error->message) ? error->message : 
"unknown error");
+            file2 = g_file_new_for_path (change);
+            if (!gcab_cabinet_extract (cabinet, file2, file_callback, NULL, NULL, cancellable, &error)) {
+                g_printerr ("%s: %s\n", _("Error during extraction"), error->message);
+                return EXIT_FAILURE;
+            }
         } else if (dump_reserved) {
-            GByteArray *reserved;
-
+            g_autoptr(GByteArray) reserved = NULL;
             g_object_get (cabinet, "reserved", &reserved, NULL);
             if (reserved != NULL) {
-                save_array_to_file (reserved, args[0], "header");
-                g_byte_array_unref (reserved);
+                if (!save_array_to_file (reserved, args[0], "header", &error)) {
+                    g_printerr ("%s\n", error->message);
+                    return EXIT_FAILURE;
+                }
             }
 
             reserved = (GByteArray *)gcab_cabinet_get_signature (cabinet, cancellable, &error);
-            if (error)
-                gcab_error (_("error while reading signature: %s"), (error && error->message) ? 
error->message : "unknown error");
+            if (reserved == NULL)
+                g_printerr ("%s: %s\n", _("Error while reading signature"), error->message);
             if (reserved != NULL)
-                save_array_to_file (reserved, args[0], "signature");
+                if (!save_array_to_file (reserved, args[0], "signature", &error)) {
+                    g_printerr ("%s\n", error->message);
+                    return EXIT_FAILURE;
+                }
         }
-
-        g_object_unref (in);
-        g_object_unref (file);
-        goto end;
+        return EXIT_SUCCESS;
     }
 
-    if (args[1] == NULL)
-        gcab_error (_("please specify input files."));
+    if (args[1] == NULL) {
+        g_printerr ("%s\n", _("No input files specified"));
+        return EXIT_FAILURE;
+    }
 
     if (space) {
-        GByteArray *reserved = g_byte_array_sized_new (space);
+        g_autoptr(GByteArray) reserved = g_byte_array_sized_new (space);
         g_byte_array_set_size (reserved, space);
         g_object_set (cabinet, "reserved", reserved, NULL);
-        g_byte_array_unref (reserved);
     }
 
     folder = gcab_folder_new (compress ? GCAB_COMPRESSION_MSZIP : 0);
 
     for (gint i = 1; args[i]; i++) {
-        GFile *file = g_file_new_for_commandline_arg (args[i]);
-        gchar *name = nopath ? g_path_get_basename (args[i]) : g_strdup (args[i]);
-        GCabFile *cabfile = gcab_file_new_with_file (
+        g_autoptr(GFile) file = g_file_new_for_commandline_arg (args[i]);
+        g_autofree gchar *name = nopath ? g_path_get_basename (args[i]) : g_strdup (args[i]);
+        g_autoptr(GCabFile) cabfile = gcab_file_new_with_file (
                                  remove_leading_path (name), file);
 
         if (!gcab_folder_add_file (folder, cabfile, TRUE, NULL, &error)) {
-            g_warning (_("Can't add file %s: %s"), args[i], (error && error->message) ? error->message : 
"unknown error");
+            g_warning ("%s %s: %s", _("Cannot add file"), args[i], error->message);
             g_clear_error (&error);
         }
-
-        g_object_unref (cabfile);
-        g_free (name);
-        g_object_unref (file);
     }
 
-    if (gcab_folder_get_nfiles (folder) == 0)
-        gcab_error (_("no files to be archived."));
+    if (gcab_folder_get_nfiles (folder) == 0) {
+        g_printerr ("%s\n", _("No files to be archived"));
+        return EXIT_FAILURE;
+    }
 
     outputfile = g_file_new_for_commandline_arg (args[0]);
     output = G_OUTPUT_STREAM (g_file_replace (outputfile, NULL, FALSE,
                                               0, NULL, &error));
-    if (error)
-        gcab_error (_("can't create cab file %s: %s"), args[0], (error && error->message) ? error->message : 
"unknown error");
+    if (output == NULL) {
+        g_printerr ("%s %s: %s\n", _("Cannot create cab file"), args[0], error->message);
+        return EXIT_FAILURE;
+    }
 
     cwd = g_file_new_for_commandline_arg (".");
-    if (!gcab_cabinet_add_folder (cabinet, folder, &error))
-        gcab_error (_("can't add folder to cab file %s: %s"), args[0], (error && error->message) ? 
error->message : "unknown error");
+    if (!gcab_cabinet_add_folder (cabinet, folder, &error)) {
+        g_printerr ("%s %s: %s\n", _("Cannot add folder to cab file"), args[0], error->message);
+        return EXIT_FAILURE;
+    }
 
     if (!gcab_cabinet_write (cabinet, output,
                              file_callback,
                              NULL,
                              cwd,
                              NULL,
-                             &error))
-        gcab_error (_("can't write cab file %s: %s"), args[0], (error && error->message) ? error->message : 
"unknown error");
-
-    g_object_unref (cwd);
-    g_object_unref (output);
-    g_object_unref (outputfile);
-
-end:
-    g_object_unref (cabinet);
-    g_object_unref (cancellable);
+                             &error)) {
+        g_printerr ("%s %s: %s\n", _("Cannot write cab file"), args[0], error->message);
+        return EXIT_FAILURE;
+    }
 
-    return 0;
+    return EXIT_SUCCESS;
 }
diff --git a/libgcab/gcab-cabinet.c b/libgcab/gcab-cabinet.c
index 2c015e3..a1a64c4 100644
--- a/libgcab/gcab-cabinet.c
+++ b/libgcab/gcab-cabinet.c
@@ -1,6 +1,7 @@
 /*
  * LibGCab
  * Copyright (c) 2012, Marc-André Lureau <marcandre lureau gmail com>
+ * Copyright (c) 2017, Richard Hughes <richard hughsie com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -35,13 +36,7 @@
  * extracting and creation of archives.
  */
 
-struct _GCabCabinetClass
-{
-    GObjectClass parent_class;
-};
-
-struct _GCabCabinet
-{
+struct _GCabCabinet {
     GObject parent_instance;
 
     GPtrArray *folders;
@@ -82,7 +77,8 @@ gcab_cabinet_finalize (GObject *object)
         g_byte_array_unref (self->reserved);
     if (self->signature)
         g_byte_array_unref (self->signature);
-    g_clear_object (&self->stream);
+    if (self->stream)
+        g_object_unref (self->stream);
 
     G_OBJECT_CLASS (gcab_cabinet_parent_class)->finalize (object);
 }
@@ -242,18 +238,15 @@ gcab_cabinet_write (GCabCabinet *self,
     g_return_val_if_fail (self->folders->len == 1, FALSE);
 
     GCabFolder *cabfolder = g_ptr_array_index (self->folders, 0);
-    GCabFile *file;
     gsize nfiles = gcab_folder_get_nfiles (cabfolder);
-    GInputStream *in = NULL;
-    GDataOutputStream *dstream = NULL;
-    gboolean success = FALSE;
+    g_autoptr(GDataOutputStream) dstream = NULL;
     gssize len, offset = 0;
     cdata_t block = { 0, };
     guint8 data[DATABLOCKSIZE];
     gsize written;
     size_t sumstr = 0;
-    GSList *l, *files;
-    cfile_t *prevf = NULL;
+    g_autoptr(GSList) files = NULL;
+    GCabFile *prevf = NULL;
 
     dstream = g_data_output_stream_new (out);
     g_data_output_stream_set_byte_order (dstream, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN);
@@ -268,83 +261,79 @@ gcab_cabinet_write (GCabCabinet *self,
     }
 
     files = gcab_folder_get_files (cabfolder);
-    for (l = files; l != NULL; l = l->next)
-        sumstr += strlen (GCAB_FILE (l->data)->name) + 1;
+    for (GSList *l = files; l != NULL; l = l->next) {
+        GCabFile *cabfile = GCAB_FILE (l->data);
+        sumstr += strlen (gcab_file_get_name (cabfile)) + 1;
+    }
 
-    folder.typecomp = cabfolder->comptype;
+    folder.typecomp = gcab_folder_get_comptype (cabfolder);
     folder.offsetdata = header.offsetfiles + nfiles * 16 + sumstr;
     folder.ndatab = gcab_folder_get_ndatablocks (cabfolder);
 
     /* avoid seeking to allow growing output streams */
     for (guint i = 0; i < folder.offsetdata; i++)
         if (!g_data_output_stream_put_byte (dstream, 0, cancellable, error))
-            goto end;
+            return FALSE;
+
+    for (GSList *l = files; l != NULL; l = l->next) {
+        g_autoptr(GInputStream) in = NULL;
 
-    for (l = files; l != NULL; l = l->next) {
-        file = GCAB_FILE (l->data);
+        GCabFile *file = GCAB_FILE (l->data);
         if (file_callback)
             file_callback (file, user_data);
 
-        g_clear_object (&in);
-        in = G_INPUT_STREAM (g_file_read (file->file, cancellable, error));
+        in = G_INPUT_STREAM (g_file_read (gcab_file_get_gfile (file), cancellable, error));
         if (in == NULL)
-            goto end;
+            return FALSE;
 
         while ((len = g_input_stream_read (in,
                                            &data[offset], DATABLOCKSIZE - offset,
                                            cancellable, error)) == (DATABLOCKSIZE - offset)) {
             if (!cdata_write (&block, dstream, folder.typecomp, data, DATABLOCKSIZE, &written, cancellable, 
error))
-                goto end;
+                return FALSE;
             header.size += written;
             offset = 0;
         }
 
         if (len == -1)
-            goto end;
+            return FALSE;
 
         offset += len;
     }
     if (offset != 0) {
         if (!cdata_write (&block, dstream, folder.typecomp, data, offset, &written, cancellable, error))
-            goto end;
+            return FALSE;
         header.size += written;
     }
 
     if (!g_seekable_seek (G_SEEKABLE (out), 0,
                           G_SEEK_SET, cancellable, error))
-        goto end;
+        return FALSE;
 
     header.nfiles = nfiles;
     header.size += header.offsetfiles + nfiles * 16; /* 1st part cfile struct = 16 bytes */
     header.size += sumstr;
 
     if (!cheader_write (&header, dstream, cancellable, error))
-        goto end;
+        return FALSE;
 
     if (!cfolder_write (&folder, dstream, cancellable, error))
-        goto end;
+        return FALSE;
 
-    for (l = files; l != NULL; l = l->next) {
-        file = GCAB_FILE (l->data);
-        file->cfile.uoffset = prevf ? prevf->uoffset + prevf->usize : 0;
-        prevf = &file->cfile;
+    for (GSList *l = files; l != NULL; l = l->next) {
+        GCabFile *file = GCAB_FILE (l->data);
+        gcab_file_set_uoffset (file, prevf ? gcab_file_get_uoffset (prevf) + gcab_file_get_usize (prevf) : 
0);
+        prevf = file;
 
         /* automatically set flag if UTF-8 encoding */
-        if (!g_str_is_ascii (file->cfile.name))
-            file->cfile.fattr |= GCAB_FILE_ATTRIBUTE_NAME_IS_UTF;
+        if (!g_str_is_ascii (gcab_file_get_name (file)))
+            gcab_file_add_attribute (file, GCAB_FILE_ATTRIBUTE_NAME_IS_UTF);
 
-        if (!cfile_write (&file->cfile, dstream, cancellable, error))
-            goto end;
+        if (!cfile_write (gcab_file_get_cfile (file), dstream, cancellable, error))
+            return FALSE;
     }
 
-    success = TRUE;
-
-end:
-    g_clear_object (&dstream);
-    g_clear_object (&in);
-    g_slist_free (files);
-
-    return success;
+    return TRUE;
 }
 
 /**
@@ -413,16 +402,13 @@ gcab_cabinet_load (GCabCabinet *self,
 
     self->stream = g_object_ref (stream);
 
-    gboolean success = FALSE;
     cheader_t cheader;
-    GDataInputStream *in = g_data_input_stream_new (stream);
+    g_autoptr(GDataInputStream) in = g_data_input_stream_new (stream);
     g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (in), FALSE);
     g_data_input_stream_set_byte_order (in, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN);
 
-    GPtrArray *folders = self->folders;
-
     if (!cheader_read (&cheader, in, cancellable, error))
-        goto end;
+        return FALSE;
 
     if (cheader.reserved)
         g_object_set (self, "reserved",
@@ -432,48 +418,40 @@ gcab_cabinet_load (GCabCabinet *self,
     for (guint i = 0; i < cheader.nfolders; i++) {
         cfolder_t cfolder = { 0, };
         if (!cfolder_read (&cfolder, cheader.res_folder, in, cancellable, error))
-            goto end;
+            return FALSE;
 
         GCabFolder *folder = gcab_folder_new_with_cfolder (&cfolder, stream);
         if (cfolder.reserved)
             g_object_set (folder, "reserved",
                           g_byte_array_new_take (cfolder.reserved, cheader.res_folder),
                           NULL);
-        g_ptr_array_add (folders, folder);
+        g_ptr_array_add (self->folders, folder);
         cfolder.reserved = NULL;
     }
 
     for (guint i = 0; i < cheader.nfiles; i++) {
         cfile_t cfile = { 0, };
         if (!cfile_read (&cfile, in, cancellable, error))
-            goto end;
+            return FALSE;
 
-        if (cfile.index >= folders->len) {
+        if (cfile.index >= self->folders->len) {
             g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT,
                          "Invalid folder index");
-            goto end;
+            return FALSE;
         }
 
-        GCabFolder *folder = g_ptr_array_index (folders, cfile.index);
+        GCabFolder *folder = g_ptr_array_index (self->folders, cfile.index);
         if (folder == NULL) {
             g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT,
                          "Invalid folder pointer");
-            goto end;
+            return FALSE;
         }
 
-        GCabFile *file = gcab_file_new_with_cfile (&cfile);
-        if (!gcab_folder_add_file (folder, file, FALSE, cancellable, error)) {
-            g_object_unref (file);
-            goto end;
-        }
+        g_autoptr(GCabFile) file = gcab_file_new_with_cfile (&cfile);
+        if (!gcab_folder_add_file (folder, file, FALSE, cancellable, error))
+            return FALSE;
     }
-
-    success = TRUE;
-
-end:
-    if (in)
-        g_object_unref (in);
-    return success;
+    return TRUE;
 }
 
 /**
diff --git a/libgcab/gcab-cabinet.h b/libgcab/gcab-cabinet.h
index e63763f..a880aa0 100644
--- a/libgcab/gcab-cabinet.h
+++ b/libgcab/gcab-cabinet.h
@@ -29,12 +29,13 @@
 
 G_BEGIN_DECLS
 
+/**
+ * GCabCabinet:
+ *
+ * An opaque object holding a Cabinet file reference.
+ **/
 #define GCAB_TYPE_CABINET                (gcab_cabinet_get_type ())
-#define GCAB_CABINET(cabinet)            (G_TYPE_CHECK_INSTANCE_CAST ((cabinet), GCAB_TYPE_CABINET, 
GCabCabinet))
-#define GCAB_CABINET_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), GCAB_TYPE_CABINET, 
GCabCabinetClass))
-#define GCAB_IS_CABINET(cabinet)         (G_TYPE_CHECK_INSTANCE_TYPE ((cabinet), GCAB_TYPE_CABINET))
-#define GCAB_IS_CABINET_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), GCAB_TYPE_CABINET))
-#define GCAB_CABINET_GET_CLASS(cabinet)  (G_TYPE_INSTANCE_GET_CLASS ((cabinet), GCAB_TYPE_CABINET, 
GCabCabinetClass))
+G_DECLARE_FINAL_TYPE(GCabCabinet, gcab_cabinet, GCAB, CABINET, GObject)
 
 /**
  * GCAB_ERROR:
@@ -58,17 +59,6 @@ typedef enum GCabError
     GCAB_ERROR_FAILED,
 } GCabError;
 
-typedef struct _GCabCabinetClass GCabCabinetClass;
-
-/**
- * GCabCabinet:
- *
- * An opaque object holding a Cabinet file reference.
- **/
-typedef struct _GCabCabinet GCabCabinet;
-
-GType gcab_cabinet_get_type (void) G_GNUC_CONST;
-
 GCabCabinet *      gcab_cabinet_new           (void);
 gboolean           gcab_cabinet_load          (GCabCabinet *cabinet,
                                                GInputStream *stream,
@@ -110,8 +100,6 @@ const GByteArray * gcab_cabinet_get_signature (GCabCabinet *cabinet,
                                                GCancellable *cancellable,
                                                GError **error);
 
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GCabCabinet, g_object_unref)
-
 G_END_DECLS
 
 #endif /* _GCAB_CABINET_H_ */
diff --git a/libgcab/gcab-file.c b/libgcab/gcab-file.c
index 39284e4..72a6744 100644
--- a/libgcab/gcab-file.c
+++ b/libgcab/gcab-file.c
@@ -1,6 +1,7 @@
 /*
  * LibGCab
  * Copyright (c) 2012, Marc-André Lureau <marcandre lureau gmail com>
+ * Copyright (c) 2017, Richard Hughes <richard hughsie com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -38,9 +39,14 @@
  * must return a valid handle.
  */
 
-struct _GCabFileClass
+struct _GCabFile
 {
-    GObjectClass parent_class;
+    GObject parent_instance;
+
+    gchar *name;
+    gchar *extract_name;
+    GFile *file;
+    cfile_t cfile;
 };
 
 enum {
@@ -181,6 +187,41 @@ gcab_file_set_uoffset (GCabFile *self, guint32 uoffset)
     return TRUE;
 }
 
+G_GNUC_INTERNAL guint32
+gcab_file_get_uoffset (GCabFile *self)
+{
+    g_return_val_if_fail (GCAB_IS_FILE (self), 0);
+    return self->cfile.uoffset;
+}
+
+G_GNUC_INTERNAL guint32
+gcab_file_get_usize (GCabFile *self)
+{
+    g_return_val_if_fail (GCAB_IS_FILE (self), 0);
+    return self->cfile.usize;
+}
+
+G_GNUC_INTERNAL GFile *
+gcab_file_get_gfile (GCabFile *self)
+{
+    g_return_val_if_fail (GCAB_IS_FILE (self), NULL);
+    return self->file;
+}
+
+G_GNUC_INTERNAL void
+gcab_file_add_attribute (GCabFile *self, guint32 attribute)
+{
+    g_return_if_fail (GCAB_IS_FILE (self));
+    self->cfile.fattr |= attribute;
+}
+
+G_GNUC_INTERNAL cfile_t *
+gcab_file_get_cfile (GCabFile *self)
+{
+    g_return_val_if_fail (GCAB_IS_FILE (self), NULL);
+    return &self->cfile;
+}
+
 /**
  * gcab_file_get_size:
  * @file: a #GCabFile
diff --git a/libgcab/gcab-file.h b/libgcab/gcab-file.h
index b7579f4..60e59d1 100644
--- a/libgcab/gcab-file.h
+++ b/libgcab/gcab-file.h
@@ -26,14 +26,13 @@
 
 G_BEGIN_DECLS
 
+/**
+ * GCabFile:
+ *
+ * An opaque object, referencing a file in a Cabinet.
+ **/
 #define GCAB_TYPE_FILE             (gcab_file_get_type ())
-#define GCAB_FILE(file)            (G_TYPE_CHECK_INSTANCE_CAST ((file), GCAB_TYPE_FILE, GCabFile))
-#define GCAB_FILE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GCAB_TYPE_FILE, GCabFileClass))
-#define GCAB_IS_FILE(file)         (G_TYPE_CHECK_INSTANCE_TYPE ((file), GCAB_TYPE_FILE))
-#define GCAB_IS_FILE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GCAB_TYPE_FILE))
-#define GCAB_FILE_GET_CLASS(file)  (G_TYPE_INSTANCE_GET_CLASS ((file), GCAB_TYPE_FILE, GCabFileClass))
-
-typedef struct _GCabFileClass GCabFileClass;
+G_DECLARE_FINAL_TYPE(GCabFile, gcab_file, GCAB, FILE, GObject)
 
 /**
  * GCabFileAttribute:
@@ -57,13 +56,6 @@ typedef enum
 } GCabFileAttribute;
 
 /**
- * GCabFile:
- *
- * An opaque object, referencing a file in a Cabinet.
- **/
-typedef struct _GCabFile GCabFile;
-
-/**
  * GCabFileCallback:
  * @file: the file being processed
  * @user_data: user data passed to the callback.
@@ -73,8 +65,6 @@ typedef struct _GCabFile GCabFile;
  **/
 typedef gboolean (*GCabFileCallback) (GCabFile *file, gpointer user_data);
 
-GType gcab_file_get_type (void) G_GNUC_CONST;
-
 GCabFile *      gcab_file_new_with_file             (const gchar *name, GFile *file);
 GFile *         gcab_file_get_file                  (GCabFile *file);
 const gchar *   gcab_file_get_name                  (GCabFile *file);
@@ -84,8 +74,6 @@ void            gcab_file_get_date                  (GCabFile *file, GTimeVal *r
 const gchar *   gcab_file_get_extract_name          (GCabFile *file);
 void            gcab_file_set_extract_name          (GCabFile *file, const gchar *name);
 
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GCabFile, g_object_unref)
-
 G_END_DECLS
 
 #endif /* _GCAB_FILE_H_ */
diff --git a/libgcab/gcab-folder.c b/libgcab/gcab-folder.c
index 10acd9a..f834753 100644
--- a/libgcab/gcab-folder.c
+++ b/libgcab/gcab-folder.c
@@ -1,6 +1,7 @@
 /*
  * LibGCab
  * Copyright (c) 2012, Marc-André Lureau <marcandre lureau gmail com>
+ * Copyright (c) 2017, Richard Hughes <richard hughsie com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -44,9 +45,16 @@
  * gcab_folder_add_file().
  */
 
-struct _GCabFolderClass
+struct _GCabFolder
 {
-    GObjectClass parent_class;
+    GObject parent_instance;
+
+    GSList *files;
+    GHashTable *hash;
+    gint comptype;
+    GByteArray *reserved;
+    cfolder_t cfolder;
+    GInputStream *stream;
 };
 
 enum {
@@ -160,12 +168,20 @@ gcab_folder_get_ndatablocks (GCabFolder *self)
     gsize total_size = 0;
     GSList *l;
 
-    for (l = self->files; l != NULL; l = l->next)
-        total_size += GCAB_FILE (l->data)->cfile.usize;
+    for (l = self->files; l != NULL; l = l->next) {
+        GCabFile *file = GCAB_FILE (l->data);
+        total_size += gcab_file_get_usize (file);
+    }
 
     return total_size / DATABLOCKSIZE + 1 ;
 }
 
+G_GNUC_INTERNAL gint
+gcab_folder_get_comptype (GCabFolder *self)
+{
+    return self->comptype;
+}
+
 static gboolean
 add_file (GCabFolder *self, GCabFile *file, GError **error)
 {
@@ -194,33 +210,25 @@ add_file_info (GCabFolder *self, GCabFile *file, GFileInfo *info,
         if (!recurse)
             return TRUE;
 
-        GFileEnumerator *dir = g_file_enumerate_children (file->file, FILE_ATTRS, 0, NULL, error);
-        if (*error) {
+        g_autoptr(GFileEnumerator) dir = g_file_enumerate_children (gcab_file_get_gfile (file), FILE_ATTRS, 
0, NULL, error);
+        if (dir == NULL) {
             g_warning ("Couldn't enumerate directory %s: %s", name, (*error)->message);
             g_clear_error (error);
             return TRUE;
         }
 
         while ((info = g_file_enumerator_next_file (dir, NULL, error)) != NULL) {
-            GFile *child = g_file_get_child (file->file, g_file_info_get_name (info));
-            gchar *child_name = g_build_path ("\\", name, g_file_info_get_name (info), NULL);
-            GCabFile *child_file = gcab_file_new_with_file (child_name, child);
-
-            add_file_info (self, child_file, info, child_name, recurse, error);
-            if (*error) {
+            g_autoptr(GFile) child = g_file_get_child (gcab_file_get_gfile (file), g_file_info_get_name 
(info));
+            g_autofree gchar *child_name = g_build_path ("\\", name, g_file_info_get_name (info), NULL);
+            g_autoptr(GCabFile) child_file = gcab_file_new_with_file (child_name, child);
+            if (!add_file_info (self, child_file, info, child_name, recurse, error)) {
                 g_warning ("Couldn't add file %s: %s",
                            child_name, (*error)->message);
                 g_clear_error (error);
             }
-
-            g_object_unref (child_file);
-            g_free (child_name);
-            g_object_unref (child);
             g_object_unref (info);
         }
 
-        g_object_unref (dir);
-
     } else if (file_type == G_FILE_TYPE_REGULAR) {
         gcab_file_update_info (file, info);
         if (!add_file (self, file, error))
@@ -263,13 +271,11 @@ gcab_folder_add_file (GCabFolder *self, GCabFile *file,
     if (gfile) {
         g_return_val_if_fail (G_IS_FILE (gfile), FALSE);
 
-        GFileInfo *info = g_file_query_info (gfile, FILE_ATTRS, 0, NULL, error);
+        g_autoptr(GFileInfo) info = g_file_query_info (gfile, FILE_ATTRS, 0, NULL, error);
         if (info == NULL)
             return FALSE;
-
         success = add_file_info (self, file, info,
                                  gcab_file_get_name (file), recurse, error);
-        g_object_unref (info);
     } else {
         success = add_file (self, file, error);
     }
@@ -346,7 +352,7 @@ sort_by_offset (GCabFile *a, GCabFile *b)
     g_return_val_if_fail (a != NULL, 0);
     g_return_val_if_fail (b != NULL, 0);
 
-    return (gint64)a->cfile.uoffset - (gint64)b->cfile.uoffset;
+    return (gint64) gcab_file_get_uoffset (a) - (gint64) gcab_file_get_uoffset (b);
 }
 
 G_GNUC_INTERNAL gboolean
@@ -361,9 +367,10 @@ gcab_folder_extract (GCabFolder *self,
 {
     GError *my_error = NULL;
     gboolean success = FALSE;
-    GDataInputStream *data = NULL;
-    GFileOutputStream *out = NULL;
-    GSList *f, *files = NULL;
+    g_autoptr(GDataInputStream) data = NULL;
+    g_autoptr(GFileOutputStream) out = NULL;
+    GSList *f = NULL;
+    g_autoptr(GSList) files = NULL;
     cdata_t cdata = { 0, };
     guint32 nubytes = 0;
 
@@ -382,52 +389,45 @@ gcab_folder_extract (GCabFolder *self,
         if (file_callback && !file_callback (file, callback_data))
             continue;
 
-        gchar *fname = g_strdup (gcab_file_get_extract_name (file));
+        g_autofree gchar *fname = g_strdup (gcab_file_get_extract_name (file));
         int i = 0, len = strlen (fname);
         for (i = 0; i < len; i++)
             if (fname[i] == '\\')
                 fname[i] = '/';
 
-        GFile *gfile = g_file_resolve_relative_path (path, fname);
-        g_free (fname);
+        g_autoptr(GFile) gfile = g_file_resolve_relative_path (path, fname);
 
         if (!g_file_has_prefix (gfile, path)) {
             // "Rebase" the file in the given path, to ensure we never escape it
-            char *rawpath = g_file_get_path (gfile);
+            g_autofree gchar *rawpath = g_file_get_path (gfile);
             if (rawpath != NULL) {
                 char *newpath = rawpath;
                 while (*newpath != 0 && *newpath == G_DIR_SEPARATOR) {
                     newpath++;
                 }
-                GFile *newgfile = g_file_resolve_relative_path (path, newpath);
-                g_free (rawpath);
-                g_object_unref (gfile);
-                gfile = newgfile;
+                g_autoptr(GFile) newgfile = g_file_resolve_relative_path (path, newpath);
+                g_set_object (&gfile, newgfile);
             }
         }
 
-        GFile *parent = g_file_get_parent (gfile);
+        g_autoptr(GFile) parent = g_file_get_parent (gfile);
 
         if (!g_file_make_directory_with_parents (parent, cancellable, &my_error)) {
             if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
                 g_clear_error (&my_error);
             else {
-                g_object_unref (gfile);
-                g_object_unref (parent);
                 g_propagate_error (error, my_error);
                 goto end;
             }
         }
-        g_object_unref (parent);
 
-        g_clear_object (&out);
-        out = g_file_replace (gfile, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, cancellable, error);
-        g_object_unref (gfile);
-        if (!out)
+        g_autoptr(GFileOutputStream) out2 = NULL;
+        out2 = g_file_replace (gfile, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, cancellable, error);
+        if (!out2)
             goto end;
 
-        guint32 usize = file->cfile.usize;
-        guint32 uoffset = file->cfile.uoffset;
+        guint32 usize = gcab_file_get_usize (file);
+        guint32 uoffset = gcab_file_get_uoffset (file);
 
         /* let's rewind if need be */
         if (uoffset < nubytes) {
@@ -446,11 +446,11 @@ gcab_folder_extract (GCabFolder *self,
                     goto end;
                 continue;
             } else {
-                gsize offset = file->cfile.uoffset > nubytes ?
-                    file->cfile.uoffset - nubytes : 0;
+                gsize offset = gcab_file_get_uoffset (file) > nubytes ?
+                    gcab_file_get_uoffset (file) - nubytes : 0;
                 const void *p = &cdata.out[offset];
                 gsize count = MIN (usize, cdata.nubytes - offset);
-                if (!g_output_stream_write_all (G_OUTPUT_STREAM (out), p, count,
+                if (!g_output_stream_write_all (G_OUTPUT_STREAM (out2), p, count,
                                                 NULL, cancellable, error))
                     goto end;
                 usize -= count;
@@ -462,10 +462,6 @@ gcab_folder_extract (GCabFolder *self,
     success = TRUE;
 
 end:
-    g_slist_free (files);
-
-    g_clear_object (&data);
-    g_clear_object (&out);
     cdata_finish (&cdata, NULL);
 
     return success;
diff --git a/libgcab/gcab-folder.h b/libgcab/gcab-folder.h
index f858686..12a191b 100644
--- a/libgcab/gcab-folder.h
+++ b/libgcab/gcab-folder.h
@@ -27,21 +27,13 @@
 
 G_BEGIN_DECLS
 
-#define GCAB_TYPE_FOLDER              (gcab_folder_get_type ())
-#define GCAB_FOLDER(folder)           (G_TYPE_CHECK_INSTANCE_CAST ((folder), GCAB_TYPE_FOLDER, GCabFolder))
-#define GCAB_FOLDER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GCAB_TYPE_FOLDER, GCabFolderClass))
-#define GCAB_IS_FOLDER(folder)        (G_TYPE_CHECK_INSTANCE_TYPE ((folder), GCAB_TYPE_FOLDER))
-#define GCAB_IS_FOLDER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GCAB_TYPE_FOLDER))
-#define GCAB_FOLDER_GET_CLASS(folder) (G_TYPE_INSTANCE_GET_CLASS ((folder), GCAB_TYPE_FOLDER, 
GCabFolderClass))
-
-typedef struct _GCabFolderClass GCabFolderClass;
-
 /**
  * GCabFolder:
  *
  * An opaque object, referencing a folder in a Cabinet.
  **/
-typedef struct _GCabFolder GCabFolder;
+#define GCAB_TYPE_FOLDER              (gcab_folder_get_type ())
+G_DECLARE_FINAL_TYPE(GCabFolder, gcab_folder, GCAB, FOLDER, GObject)
 
 /**
  * GCabCompression:
@@ -63,8 +55,6 @@ typedef enum
     GCAB_COMPRESSION_MASK = 0xf,
 } GCabCompression;
 
-GType gcab_folder_get_type (void) G_GNUC_CONST;
-
 GCabFolder *    gcab_folder_new               (gint comptype);
 gboolean        gcab_folder_add_file          (GCabFolder *cabfolder,
                                                GCabFile *cabfile,
@@ -74,8 +64,6 @@ gboolean        gcab_folder_add_file          (GCabFolder *cabfolder,
 guint           gcab_folder_get_nfiles        (GCabFolder *cabfolder);
 GSList *        gcab_folder_get_files         (GCabFolder *cabfolder);
 
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GCabFolder, g_object_unref)
-
 G_END_DECLS
 
 #endif /* _GCAB_FILE_H_ */
diff --git a/libgcab/gcab-priv.h b/libgcab/gcab-priv.h
index 349735b..b2cb232 100644
--- a/libgcab/gcab-priv.h
+++ b/libgcab/gcab-priv.h
@@ -40,35 +40,18 @@
                                           _GCAB_GET (data, 1, 32,  8) |  \
                                           _GCAB_GET (data, 0, 32,  0))
 
-
-struct _GCabFile
-{
-    GObject parent_instance;
-
-    gchar *name;
-    gchar *extract_name;
-    GFile *file;
-    cfile_t cfile;
-};
-
-struct _GCabFolder
-{
-    GObject parent_instance;
-
-    GSList *files;
-    GHashTable *hash;
-    gint comptype;
-    GByteArray *reserved;
-    cfolder_t cfolder;
-    GInputStream *stream;
-};
-
 GCabFolder *     gcab_folder_new_with_cfolder        (const cfolder_t *folder, GInputStream *stream);
 GCabFile *       gcab_file_new_with_cfile            (const cfile_t *file);
 
 gboolean         gcab_file_update_info               (GCabFile *file, GFileInfo *info);
+guint32          gcab_file_get_uoffset               (GCabFile *file);
 gboolean         gcab_file_set_uoffset               (GCabFile *file, guint32 uoffset);
+guint32          gcab_file_get_usize                 (GCabFile *file);
+GFile           *gcab_file_get_gfile                 (GCabFile *file);
+cfile_t         *gcab_file_get_cfile                 (GCabFile *file);
+void             gcab_file_add_attribute             (GCabFile *file, guint32 attribute);
 
+gint             gcab_folder_get_comptype            (GCabFolder *folder);
 gsize            gcab_folder_get_ndatablocks         (GCabFolder *folder);
 gboolean         gcab_folder_extract                 (GCabFolder *self,
                                                       GFile *path,



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