diff options
author | Johannes Mueller <github@johannes-mueller.org> | 2020-04-05 15:37:04 +0200 |
---|---|---|
committer | Johannes Mueller <github@johannes-mueller.org> | 2020-04-05 16:34:48 +0200 |
commit | c74cc2675e099e494ce13de2e3d7d36af0a310f0 (patch) | |
tree | cf4c4b6cc2be869588361bea9f8ee360826db960 | |
parent | 419af8264579ebbfe6c350010697771f5c800ee9 (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.cc | 95 | ||||
-rw-r--r-- | libs/pbd/pbd/file_archive.h | 9 |
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 */ |