add ActionManager::get_actions() to fetch all actions created in ActionGroups with...
[ardour.git] / libs / pbd / file_archive.cc
index 4afc9abad98f9fe93907a85f97c37774e777f147..ccc19c05417fe0a2b972a507f7155b9a852295cc 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
+#ifndef NDEBUG
+#include <iostream>
+#include <iomanip>
+#endif
+
 #include <stdlib.h>
 #include <string.h>
 #include <cstdio>
+#include <fcntl.h>
+#include <sys/stat.h>
 
+#include <glib.h>
 #include "pbd/gstdio_compat.h"
 #include <glibmm.h>
 
@@ -29,6 +37,7 @@
 
 #include "pbd/failed_constructor.h"
 #include "pbd/file_archive.h"
+#include "pbd/file_utils.h"
 
 using namespace PBD;
 
@@ -330,3 +339,120 @@ FileArchive::do_extract (struct archive* a)
        archive_write_free(ext);
        return rv;
 }
+
+
+int
+FileArchive::create (const std::string& srcdir, CompressionLevel compression_level)
+{
+       if (_req.is_remote ()) {
+               return -1;
+       }
+
+       std::string parent = Glib::path_get_dirname (srcdir);
+       size_t p_len = parent.size () + 1;
+
+       Searchpath sp (srcdir);
+       std::vector<std::string> files;
+       find_files_matching_pattern (files, sp, "*");
+
+       std::map<std::string, std::string> filemap;
+
+       for (std::vector<std::string>::const_iterator f = files.begin (); f != files.end (); ++f) {
+               assert (f->size () > p_len);
+               filemap[*f] = f->substr (p_len);
+       }
+
+       return create (filemap, compression_level);
+}
+
+int
+FileArchive::create (const std::map<std::string, std::string>& filemap, CompressionLevel compression_level)
+{
+       struct archive *a;
+       struct archive_entry *entry;
+
+       size_t read_bytes = 0;
+       size_t total_bytes = 0;
+
+       for (std::map<std::string, std::string>::const_iterator f = filemap.begin (); f != filemap.end (); ++f) {
+               GStatBuf statbuf;
+               if (g_stat (f->first.c_str(), &statbuf)) {
+                       continue;
+               }
+               total_bytes += statbuf.st_size;
+       }
+
+       if (total_bytes == 0) {
+               return -1;
+       }
+
+       progress (0, total_bytes);
+
+       a = archive_write_new ();
+       archive_write_set_format_pax_restricted (a);
+
+       if (compression_level != CompressNone) {
+               archive_write_add_filter_lzma (a);
+               char buf[48];
+               sprintf (buf, "lzma:compression-level=%u,lzma:threads=0", (uint32_t) compression_level);
+               archive_write_set_options (a, buf);
+       }
+
+       archive_write_open_filename (a, _req.url);
+       entry = archive_entry_new ();
+
+#ifndef NDEBUG
+         const int64_t archive_start_time = g_get_monotonic_time();
+#endif
+
+       for (std::map<std::string, std::string>::const_iterator f = filemap.begin (); f != filemap.end (); ++f) {
+               char buf[8192];
+               const char* filepath = f->first.c_str ();
+               const char* filename = f->second.c_str ();
+
+               GStatBuf statbuf;
+               if (g_stat (filepath, &statbuf)) {
+                       continue;
+               }
+
+               archive_entry_clear (entry);
+
+#ifdef PLATFORM_WINDOWS
+               archive_entry_set_size (entry, statbuf.st_size);
+               archive_entry_set_atime (entry, statbuf.st_atime, 0);
+               archive_entry_set_ctime (entry, statbuf.st_ctime, 0);
+               archive_entry_set_mtime (entry, statbuf.st_mtime, 0);
+#else
+               archive_entry_copy_stat (entry, &statbuf);
+#endif
+
+               archive_entry_set_pathname (entry, filename);
+               archive_entry_set_filetype (entry, AE_IFREG);
+               archive_entry_set_perm (entry, 0644);
+
+               archive_write_header (a, entry);
+
+               int fd = g_open (filepath, O_RDONLY, 0444);
+               assert (fd >= 0);
+
+               ssize_t len = read (fd, buf, sizeof (buf));
+               while (len > 0) {
+                       read_bytes += len;
+                       archive_write_data (a, buf, len);
+                       progress (read_bytes, total_bytes);
+                       len = read (fd, buf, sizeof (buf));
+               }
+               close (fd);
+       }
+
+       archive_entry_free (entry);
+       archive_write_close (a);
+       archive_write_free (a);
+
+#ifndef NDEBUG
+       const int64_t elapsed_time_us = g_get_monotonic_time() - archive_start_time;
+       std::cerr << "archived in " << std::fixed << std::setprecision (2) << elapsed_time_us / 1000000. << " sec\n";
+#endif
+
+       return 0;
+}