Addl fix #299: File Compression and Archiving
[geeqie.git] / src / misc.c
index d8b1440..50a0a6b 100644 (file)
@@ -22,6 +22,8 @@
 #include "misc.h"
 #include "ui_fileops.h"
 
+#include <archive.h>
+#include <archive_entry.h>
 #include <langinfo.h>
 #include <locale.h>
 
@@ -408,4 +410,161 @@ void tree_path_free_wrapper(void *data, void *useradata)
        gtk_tree_path_free(data);
 }
 
+/* Copied from the libarchive .repo. examples */
+
+static void errmsg(const char *);
+static gboolean extract(const char *filename, int do_extract, int flags);
+static int copy_data(struct archive *, struct archive *);
+static void msg(const char *);
+static int verbose = 0;
+
+gchar *open_archive(FileData *fd)
+{
+       int flags;
+       gchar *current_dir;
+       gchar *destination_dir;
+       gboolean success;
+
+       destination_dir = g_build_filename(g_get_tmp_dir(), GQ_ARCHIVE_DIR, instance_identifier, fd->path, NULL);
+
+       recursive_mkdir_if_not_exists(destination_dir, 0755);
+
+       current_dir = g_get_current_dir();
+       chdir(destination_dir);
+
+       flags = ARCHIVE_EXTRACT_TIME;
+       success = extract(fd->path, 1, flags);
+
+       chdir(current_dir);
+       g_free(current_dir);
+
+       if (!success)
+               {
+               g_free(destination_dir);
+               destination_dir = NULL;
+               }
+
+       return destination_dir;
+}
+
+static gboolean extract(const char *filename, int do_extract, int flags)
+{
+       struct archive *a;
+       struct archive *ext;
+       struct archive_entry *entry;
+       int r;
+
+       a = archive_read_new();
+       ext = archive_write_disk_new();
+       archive_write_disk_set_options(ext, flags);
+       archive_write_disk_set_standard_lookup(ext);
+       archive_read_support_filter_all(a);
+       archive_read_support_format_all(a);
+
+       if (filename != NULL && strcmp(filename, "-") == 0)
+               {
+               filename = NULL;
+               }
+       if ((r = archive_read_open_filename(a, filename, 10240)))
+               {
+               errmsg(archive_error_string(a));
+               errmsg("\n");
+               return(FALSE);
+               }
+       for (;;)
+               {
+               int needcr = 0;
+
+               r = archive_read_next_header(a, &entry);
+               if (r == ARCHIVE_EOF)
+                       {
+                       break;
+                       }
+               if (r != ARCHIVE_OK)
+                       {
+                       errmsg(archive_error_string(a));
+                       errmsg("\n");
+                       return(FALSE);
+                       }
+               if (verbose && do_extract)
+                       {
+                       msg("x ");
+                       }
+               if (verbose || !do_extract)
+                       {
+                       msg(archive_entry_pathname(entry));
+                       msg(" ");
+                       needcr = 1;
+                       }
+               if (do_extract)
+                       {
+                       r = archive_write_header(ext, entry);
+                       if (r != ARCHIVE_OK)
+                               {
+                               errmsg(archive_error_string(a));
+                               needcr = 1;
+                               }
+                       else
+                               {
+                               r = copy_data(a, ext);
+                               if (r != ARCHIVE_OK)
+                                       {
+                                       needcr = 1;
+                                       }
+                               }
+                       }
+               if (needcr)
+                       {
+                       msg("\n");
+                       }
+               }
+       archive_read_close(a);
+       archive_read_free(a);
+
+       archive_write_close(ext);
+       archive_write_free(ext);
+       return(TRUE);
+}
+
+static int
+copy_data(struct archive *ar, struct archive *aw)
+{
+       int r;
+       const void *buff;
+       size_t size;
+       int64_t offset;
+
+       for (;;)
+               {
+               r = archive_read_data_block(ar, &buff, &size, &offset);
+               if (r == ARCHIVE_EOF)
+                       return (ARCHIVE_OK);
+               if (r != ARCHIVE_OK)
+                       {
+                       errmsg(archive_error_string(ar));
+                       return (r);
+                       }
+               r = archive_write_data_block(aw, buff, size, offset);
+               if (r != ARCHIVE_OK)
+                       {
+                       errmsg(archive_error_string(ar));
+                       return (r);
+                       }
+               }
+}
+
+static void msg(const char *m)
+{
+       log_printf("%s \n", m);
+}
+
+static void errmsg(const char *m)
+{
+       if (m == NULL)
+               {
+               m = "Error: No error description provided.\n";
+               }
+       log_printf("%s \n", m);
+}
+
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */