2 * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include "pbd/gstdio_compat.h"
27 #include <archive_entry.h>
28 #include <curl/curl.h>
30 #include "pbd/failed_constructor.h"
31 #include "pbd/file_archive.h"
36 write_callback (void* buffer, size_t size, size_t nmemb, void* d)
38 FileArchive::MemPipe* p = (FileArchive::MemPipe*)d;
39 size_t realsize = size * nmemb;
42 p->data = (uint8_t*) realloc ((void*) p->data, p->size + realsize);
43 memcpy (&p->data[p->size], buffer, realsize);
53 FileArchive::Request* r = (FileArchive::Request*) arg;
56 curl = curl_easy_init ();
57 curl_easy_setopt (curl, CURLOPT_URL, r->url);
59 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, write_callback);
60 curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void*) &r->mp);
61 curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L);
63 curl_easy_perform (curl);
64 curl_easy_cleanup (curl);
75 ar_read (struct archive* a, void* d, const void** buff)
77 FileArchive::MemPipe* p = (FileArchive::MemPipe*)d;
81 while (p->size == 0) {
89 rv = p->size > 8192 ? 8192 : p->size;
90 memcpy (p->buf, p->data, rv);
92 memmove (p->data, &p->data[rv], p->size - rv);
101 ar_copy_data (struct archive *ar, struct archive *aw)
108 r = archive_read_data_block (ar, &buff, &size, &offset);
109 if (r == ARCHIVE_EOF) {
112 if (r != ARCHIVE_OK) {
115 r = archive_write_data_block (aw, buff, size, offset);
116 if (r != ARCHIVE_OK) {
117 fprintf (stderr, "Extract/Write Archive: %s", archive_error_string(aw));
123 static struct archive*
127 a = archive_read_new ();
128 archive_read_support_filter_all (a);
129 archive_read_support_format_all (a);
134 FileArchive::FileArchive (const std::string& url)
138 fprintf (stderr, "Invalid Archive URL/filename\n");
139 throw failed_constructor ();
144 FileArchive::inflate (const std::string& destdir)
147 std::string pwd (Glib::get_current_dir ());
149 if (g_chdir (destdir.c_str ())) {
150 fprintf (stderr, "Archive: cannot chdir to '%s'\n", destdir.c_str ());
154 if (_req.is_remote ()) {
157 rv = extract_file ();
160 g_chdir (pwd.c_str());
164 std::vector<std::string>
165 FileArchive::contents ()
167 if (_req.is_remote ()) {
168 return contents_url ();
170 return contents_file ();
174 std::vector<std::string>
175 FileArchive::contents_file ()
177 struct archive* a = setup_archive ();
178 if (ARCHIVE_OK != archive_read_open_filename (a, _req.url, 8192)) {
179 fprintf (stderr, "Error opening archive: %s\n", archive_error_string(a));
180 return std::vector<std::string> ();
182 return get_contents (a);
185 std::vector<std::string>
186 FileArchive::contents_url ()
189 pthread_create (&_tid, NULL, get_url, (void*)&_req);
191 struct archive* a = setup_archive ();
192 archive_read_open (a, (void*)&_req.mp, NULL, ar_read, NULL);
193 std::vector<std::string> rv (get_contents (a));
195 pthread_join (_tid, NULL);
200 FileArchive::extract_file ()
202 struct archive* a = setup_archive ();
203 if (ARCHIVE_OK != archive_read_open_filename (a, _req.url, 8192)) {
204 fprintf (stderr, "Error opening archive: %s\n", archive_error_string(a));
207 return do_extract (a);
211 FileArchive::extract_url ()
214 pthread_create (&_tid, NULL, get_url, (void*)&_req);
216 struct archive* a = setup_archive ();
217 archive_read_open (a, (void*)&_req.mp, NULL, ar_read, NULL);
218 int rv = do_extract (a);
220 pthread_join (_tid, NULL);
224 std::vector<std::string>
225 FileArchive::get_contents (struct archive* a)
227 std::vector<std::string> rv;
228 struct archive_entry* entry;
230 int r = archive_read_next_header (a, &entry);
231 if (r == ARCHIVE_EOF) {
234 if (r != ARCHIVE_OK) {
235 fprintf (stderr, "Error reading archive: %s\n", archive_error_string(a));
238 rv.push_back (archive_entry_pathname (entry));
241 archive_read_close (a);
242 archive_read_free (a);
247 FileArchive::do_extract (struct archive* a)
249 int flags = ARCHIVE_EXTRACT_TIME;
252 struct archive_entry* entry;
255 ext = archive_write_disk_new();
256 archive_write_disk_set_options(ext, flags);
259 int r = archive_read_next_header (a, &entry);
260 if (r == ARCHIVE_EOF) {
263 if (r != ARCHIVE_OK) {
264 fprintf (stderr, "Error reading archive: %s\n", archive_error_string(a));
268 #if 0 // hacky alternative to chdir
269 const std::string full_path = Glib::build_filename (destdir, archive_entry_pathname (entry));
270 archive_entry_set_pathname (entry, full_path.c_str());
273 r = archive_write_header(ext, entry);
274 if (r != ARCHIVE_OK) {
275 fprintf (stderr, "Extracting archive: %s\n", archive_error_string(ext));
277 ar_copy_data (a, ext);
278 r = archive_write_finish_entry (ext);
279 if (r != ARCHIVE_OK) {
280 fprintf (stderr, "Extracting archive: %s\n", archive_error_string(ext));
287 archive_read_close (a);
288 archive_read_free (a);
289 archive_write_close(ext);
290 archive_write_free(ext);