summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Mueller <github@johannes-mueller.org>2020-04-05 15:37:04 +0200
committerJohannes Mueller <github@johannes-mueller.org>2020-04-05 16:34:48 +0200
commitc74cc2675e099e494ce13de2e3d7d36af0a310f0 (patch)
treecf4c4b6cc2be869588361bea9f8ee360826db960
parent419af8264579ebbfe6c350010697771f5c800ee9 (diff)
Extend FileArchive to import archive entries individually
This is needed primarily for a workaround for #7971. When importing a template that has been exported on Ardour5 on MacOS we need to fix the paths of the archive entries. Later we can use this functionality also to handle imported templates if templates with the same name already exist. This commit only adds methods and members to FileArchive, it does not modify anything to make regressions unlikely. This, however, leads to some duplicated code. Eventually we should consolidate this a bit.
-rw-r--r--libs/pbd/file_archive.cc95
-rw-r--r--libs/pbd/pbd/file_archive.h9
2 files changed, 104 insertions, 0 deletions
diff --git a/libs/pbd/file_archive.cc b/libs/pbd/file_archive.cc
index 292c62dba9..68d5f0cebf 100644
--- a/libs/pbd/file_archive.cc
+++ b/libs/pbd/file_archive.cc
@@ -153,6 +153,8 @@ setup_archive ()
FileArchive::FileArchive (const std::string& url)
: _req (url)
+ , _current_entry (0)
+ , _archive (0)
{
if (!_req.url) {
fprintf (stderr, "Invalid Archive URL/filename\n");
@@ -166,6 +168,14 @@ FileArchive::FileArchive (const std::string& url)
}
}
+FileArchive::~FileArchive ()
+{
+ if (_archive) {
+ archive_read_close (_archive);
+ archive_read_free (_archive);
+ }
+}
+
int
FileArchive::inflate (const std::string& destdir)
{
@@ -197,6 +207,73 @@ FileArchive::contents ()
}
}
+std::string
+FileArchive::next_file_name ()
+{
+ assert (!_req.is_remote () && "FileArchive: Iterating over archive files not supported for remote archives.\n");
+
+ if (!_archive) {
+ _archive = setup_file_archive();
+ if (!_archive) {
+ return std::string();
+ }
+ }
+
+ int r = archive_read_next_header (_archive, &_current_entry);
+ if (!_req.mp.progress) {
+ // file i/o -- not URL
+ const uint64_t read = archive_filter_bytes (_archive, -1);
+ progress (read, _req.mp.length);
+ }
+
+ if (r == ARCHIVE_EOF) {
+ goto no_next;
+ }
+
+ if (r != ARCHIVE_OK) {
+ fprintf (stderr, "Error reading archive: %s\n", archive_error_string(_archive));
+ goto no_next;
+ }
+
+ return archive_entry_pathname (_current_entry);
+
+no_next:
+ _current_entry = 0;
+ return std::string();
+}
+
+int
+FileArchive::extract_current_file (const std::string& destpath)
+{
+ if (!_archive || !_current_entry) {
+ return 0;
+ }
+
+ int flags = ARCHIVE_EXTRACT_TIME;
+
+ struct archive *ext;
+
+ ext = archive_write_disk_new();
+ archive_write_disk_set_options(ext, flags);
+
+ archive_entry_set_pathname(_current_entry, destpath.c_str());
+ int r = archive_write_header(ext, _current_entry);
+ _current_entry = 0;
+ if (r != ARCHIVE_OK) {
+ fprintf (stderr, "Error reading archive: %s\n", archive_error_string(_archive));
+ return -1;
+ }
+
+ ar_copy_data (_archive, ext);
+ r = archive_write_finish_entry (ext);
+ if (r != ARCHIVE_OK) {
+ fprintf (stderr, "Error reading archive: %s\n", archive_error_string(_archive));
+ return -1;
+ }
+
+ return 0;
+}
+
std::vector<std::string>
FileArchive::contents_file ()
{
@@ -456,3 +533,21 @@ FileArchive::create (const std::map<std::string, std::string>& filemap, Compress
return 0;
}
+
+struct archive*
+FileArchive::setup_file_archive ()
+{
+ struct archive* a = setup_archive ();
+ GStatBuf statbuf;
+ if (!g_stat (_req.url, &statbuf)) {
+ _req.mp.length = statbuf.st_size;
+ } else {
+ _req.mp.length = -1;
+ }
+ if (ARCHIVE_OK != archive_read_open_filename (a, _req.url, 8192)) {
+ fprintf (stderr, "Error opening archive: %s\n", archive_error_string(a));
+ return 0;
+ }
+
+ return a;
+}
diff --git a/libs/pbd/pbd/file_archive.h b/libs/pbd/pbd/file_archive.h
index 85c75e52a7..7244a4e16e 100644
--- a/libs/pbd/pbd/file_archive.h
+++ b/libs/pbd/pbd/file_archive.h
@@ -33,10 +33,14 @@ class LIBPBD_API FileArchive
{
public:
FileArchive (const std::string& url);
+ ~FileArchive ();
int inflate (const std::string& destdir);
std::vector<std::string> contents ();
+ std::string next_file_name ();
+ int extract_current_file (const std::string& destpath);
+
/* these are mapped to libarchive's lzmaz
* compression level 0..9
*/
@@ -147,8 +151,13 @@ class LIBPBD_API FileArchive
bool is_url ();
+ struct archive* setup_file_archive ();
+
Request _req;
pthread_t _tid;
+
+ struct archive_entry* _current_entry;
+ struct archive* _archive;
};
} /* namespace */