diff --git a/include/system.hpp b/include/system.hpp index c4519498..c482f0b2 100644 --- a/include/system.hpp +++ b/include/system.hpp @@ -47,6 +47,11 @@ The launched process will continue running if the current process is closed. */ void runProcessDetached(const std::string& path); std::string getOperatingSystemInfo(); +/** Unzips a ZIP file to a folder. +The folder must exist. +Returns 0 if successful. +*/ +int unzipToFolder(const std::string& zipPath, const std::string& dir); } // namespace system diff --git a/src/plugin.cpp b/src/plugin.cpp index 3f80e06f..91c0d0fd 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -17,8 +17,6 @@ #include #include -#define ZIP_STATIC -#include #include #if defined ARCH_WIN @@ -174,74 +172,6 @@ static void loadPlugins(std::string path) { } } -/** Returns 0 if successful */ -static int extractZipHandle(zip_t* za, std::string dir) { - int err; - for (int i = 0; i < zip_get_num_entries(za, 0); i++) { - zip_stat_t zs; - err = zip_stat_index(za, i, 0, &zs); - if (err) { - WARN("zip_stat_index() failed: error %d", err); - return err; - } - - std::string path = dir + "/" + zs.name; - - if (path[path.size() - 1] == '/') { - system::createDirectory(path); - // HACK - // Create and delete file to update the directory's mtime. - std::string tmpPath = path + "/.tmp"; - FILE* tmpFile = fopen(tmpPath.c_str(), "w"); - fclose(tmpFile); - std::remove(tmpPath.c_str()); - } - else { - zip_file_t* zf = zip_fopen_index(za, i, 0); - if (!zf) { - WARN("zip_fopen_index() failed"); - return -1; - } - - FILE* outFile = fopen(path.c_str(), "wb"); - if (!outFile) - continue; - - while (1) { - char buffer[1 << 15]; - int len = zip_fread(zf, buffer, sizeof(buffer)); - if (len <= 0) - break; - fwrite(buffer, 1, len, outFile); - } - - err = zip_fclose(zf); - if (err) { - WARN("zip_fclose() failed: error %d", err); - return err; - } - fclose(outFile); - } - } - return 0; -} - -/** Returns 0 if successful */ -static int extractZip(std::string filename, std::string path) { - int err; - zip_t* za = zip_open(filename.c_str(), 0, &err); - if (!za) { - WARN("Could not open zip %s: error %d", filename.c_str(), err); - return err; - } - DEFER({ - zip_close(za); - }); - - err = extractZipHandle(za, path); - return err; -} - static void extractPackages(std::string path) { std::string message; @@ -250,7 +180,7 @@ static void extractPackages(std::string path) { continue; INFO("Extracting package %s", packagePath.c_str()); // Extract package - if (extractZip(packagePath, path)) { + if (system::unzipToFolder(packagePath, path)) { WARN("Package %s failed to extract", packagePath.c_str()); message += string::f("Could not extract package %s\n", packagePath.c_str()); continue; @@ -289,7 +219,7 @@ void init() { std::string fundamentalDir = asset::pluginsPath + "/Fundamental"; if (!settings::devMode && !getPlugin("Fundamental") && system::isFile(fundamentalSrc)) { INFO("Extracting bundled Fundamental package"); - extractZip(fundamentalSrc.c_str(), asset::pluginsPath.c_str()); + system::unzipToFolder(fundamentalSrc.c_str(), asset::pluginsPath.c_str()); loadPlugin(fundamentalDir); } diff --git a/src/system.cpp b/src/system.cpp index 920bae0f..f0d78093 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -27,6 +27,9 @@ #include #endif +#define ZIP_STATIC +#include + namespace rack { namespace system { @@ -324,5 +327,73 @@ std::string getOperatingSystemInfo() { } +int unzipToFolder(const std::string& zipPath, const std::string& dir) { + int err; + // Open ZIP file + zip_t* za = zip_open(zipPath.c_str(), 0, &err); + if (!za) { + WARN("Could not open ZIP file %s: error %d", zipPath.c_str(), err); + return err; + } + DEFER({ + zip_close(za); + }); + + // Iterate ZIP entries + for (int i = 0; i < zip_get_num_entries(za, 0); i++) { + zip_stat_t zs; + err = zip_stat_index(za, i, 0, &zs); + if (err) { + WARN("zip_stat_index() failed: error %d", err); + return err; + } + + std::string path = dir + "/" + zs.name; + + if (path[path.size() - 1] == '/') { + // Create directory + system::createDirectory(path); + // HACK + // Create and delete file to update the directory's mtime. + std::string tmpPath = path + "/.tmp"; + FILE* tmpFile = fopen(tmpPath.c_str(), "w"); + fclose(tmpFile); + std::remove(tmpPath.c_str()); + } + else { + // Open ZIP entry + zip_file_t* zf = zip_fopen_index(za, i, 0); + if (!zf) { + WARN("zip_fopen_index() failed"); + return -1; + } + DEFER({ + zip_fclose(zf); + }); + + // Create file + FILE* outFile = fopen(path.c_str(), "wb"); + if (!outFile) { + WARN("Could not create file %s", path.c_str()); + return -1; + } + DEFER({ + fclose(outFile); + }); + + // Read buffer and copy to file + while (true) { + char buffer[1 << 15]; + int len = zip_fread(zf, buffer, sizeof(buffer)); + if (len <= 0) + break; + fwrite(buffer, 1, len, outFile); + } + } + } + return 0; +} + + } // namespace system } // namespace rack