| @@ -27,7 +27,7 @@ E.g. | |||
| DEPRECATED void foo(); | |||
| */ | |||
| #if defined(__GNUC__) || defined(__clang__) | |||
| #define DEPRECATED __attribute__ ((deprecated)) | |||
| #define DEPRECATED __attribute__((deprecated)) | |||
| #elif defined(_MSC_VER) | |||
| #define DEPRECATED __declspec(deprecated) | |||
| #endif | |||
| @@ -168,6 +168,10 @@ Can be subclassed to throw/catch specific custom exceptions. | |||
| */ | |||
| struct Exception : std::exception { | |||
| std::string msg; | |||
| // Attribute index 1 refers to `Exception*` argument so use 2. | |||
| __attribute__((format(printf, 2, 3))) | |||
| Exception(const char* format, ...); | |||
| Exception(const std::string& msg) : msg(msg) {} | |||
| const char* what() const noexcept override { | |||
| return msg.c_str(); | |||
| @@ -35,7 +35,7 @@ void destroy(); | |||
| /** Do not use this function directly. Use the macros above. | |||
| Thread-safe, meaning messages cannot overlap each other in the log. | |||
| */ | |||
| __attribute__ ((format(printf, 5, 6))) | |||
| __attribute__((format(printf, 5, 6))) | |||
| void log(Level level, const char* filename, int line, const char* func, const char* format, ...); | |||
| /** Returns whether the current log file failed to end properly, due to a possible crash. | |||
| Must be called *before* init(). | |||
| @@ -100,7 +100,7 @@ | |||
| #undef PRIVATE | |||
| #define PRIVATE __attribute__ ((warning ("Using private function or symbol"))) | |||
| #define PRIVATE __attribute__((warning ("Using private function or symbol"))) | |||
| namespace rack { | |||
| @@ -1,4 +1,5 @@ | |||
| #pragma once | |||
| #include <stdarg.h> | |||
| #include <vector> | |||
| #include <common.hpp> | |||
| @@ -15,7 +16,9 @@ namespace string { | |||
| /** Converts a `printf()` format string and optional arguments into a std::string. | |||
| Remember that "%s" must reference a `char *`, so use `.c_str()` for `std::string`s, otherwise you might get binary garbage. | |||
| */ | |||
| __attribute__((format(printf, 1, 2))) | |||
| std::string f(const char* format, ...); | |||
| std::string fV(const char* format, va_list args); | |||
| /** Replaces all characters to lowercase letters */ | |||
| std::string lowercase(const std::string& s); | |||
| /** Replaces all characters to uppercase letters */ | |||
| @@ -737,7 +737,7 @@ void ModuleWidget::pasteClipboardAction() { | |||
| void ModuleWidget::load(std::string filename) { | |||
| FILE* file = std::fopen(filename.c_str(), "r"); | |||
| if (!file) | |||
| throw Exception(string::f("Could not load patch file %s", filename.c_str())); | |||
| throw Exception("Could not load patch file %s", filename.c_str()); | |||
| DEFER({std::fclose(file);}); | |||
| INFO("Loading preset %s", filename.c_str()); | |||
| @@ -745,7 +745,7 @@ void ModuleWidget::load(std::string filename) { | |||
| json_error_t error; | |||
| json_t* moduleJ = json_loadf(file, 0, &error); | |||
| if (!moduleJ) | |||
| throw Exception(string::f("File is not a valid patch file. JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text)); | |||
| throw Exception("File is not a valid patch file. JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | |||
| DEFER({json_decref(moduleJ);}); | |||
| // Don't use IDs from JSON | |||
| @@ -21,6 +21,14 @@ const std::string API_URL = "https://api.vcvrack.com"; | |||
| const std::string API_VERSION = "2"; | |||
| Exception::Exception(const char* format, ...) { | |||
| va_list args; | |||
| va_start(args, format); | |||
| msg = string::fV(format, args); | |||
| va_end(args); | |||
| } | |||
| } // namespace rack | |||
| @@ -48,7 +48,7 @@ static void* loadLibrary(std::string libraryPath) { | |||
| SetErrorMode(0); | |||
| if (!handle) { | |||
| int error = GetLastError(); | |||
| throw Exception(string::f("Failed to load library %s: code %d", libraryPath.c_str(), error)); | |||
| throw Exception("Failed to load library %s: code %d", libraryPath.c_str(), error); | |||
| } | |||
| #else | |||
| // As of Rack v2.0, plugins are linked with `-rpath=.` so change current directory so it can find libRack. | |||
| @@ -59,7 +59,7 @@ static void* loadLibrary(std::string libraryPath) { | |||
| // Load library with dlopen | |||
| void* handle = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_LOCAL); | |||
| if (!handle) | |||
| throw Exception(string::f("Failed to load library %s: %s", libraryPath.c_str(), dlerror())); | |||
| throw Exception("Failed to load library %s: %s", libraryPath.c_str(), dlerror()); | |||
| #endif | |||
| return handle; | |||
| } | |||
| @@ -80,7 +80,7 @@ static InitCallback loadPluginCallback(Plugin* plugin) { | |||
| // Check file existence | |||
| if (!system::isFile(libraryPath)) | |||
| throw Exception(string::f("Plugin binary not found at %s", libraryPath.c_str())); | |||
| throw Exception("Plugin binary not found at %s", libraryPath.c_str()); | |||
| // Load dynamic/shared library | |||
| plugin->handle = loadLibrary(libraryPath); | |||
| @@ -93,7 +93,7 @@ static InitCallback loadPluginCallback(Plugin* plugin) { | |||
| initCallback = (InitCallback) dlsym(plugin->handle, "init"); | |||
| #endif | |||
| if (!initCallback) | |||
| throw Exception(string::f("Failed to read init() symbol in %s", libraryPath.c_str())); | |||
| throw Exception("Failed to read init() symbol in %s", libraryPath.c_str()); | |||
| return initCallback; | |||
| } | |||
| @@ -124,13 +124,13 @@ static Plugin* loadPlugin(std::string path) { | |||
| std::string manifestFilename = (path == "") ? asset::system("Core.json") : system::join(path, "plugin.json"); | |||
| FILE* file = std::fopen(manifestFilename.c_str(), "r"); | |||
| if (!file) | |||
| throw Exception(string::f("Manifest file %s does not exist", manifestFilename.c_str())); | |||
| throw Exception("Manifest file %s does not exist", manifestFilename.c_str()); | |||
| DEFER({std::fclose(file);}); | |||
| json_error_t error; | |||
| json_t* rootJ = json_loadf(file, 0, &error); | |||
| if (!rootJ) | |||
| throw Exception(string::f("JSON parsing error at %s %d:%d %s", manifestFilename.c_str(), error.line, error.column, error.text)); | |||
| throw Exception("JSON parsing error at %s %d:%d %s", manifestFilename.c_str(), error.line, error.column, error.text); | |||
| DEFER({json_decref(rootJ);}); | |||
| // Call init callback | |||
| @@ -149,7 +149,7 @@ static Plugin* loadPlugin(std::string path) { | |||
| // Reject plugin if slug already exists | |||
| Plugin* oldPlugin = getPlugin(plugin->slug); | |||
| if (oldPlugin) | |||
| throw Exception(string::f("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str())); | |||
| throw Exception("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str()); | |||
| plugins.push_back(plugin); | |||
| INFO("Loaded plugin %s v%s from %s", plugin->slug.c_str(), plugin->version.c_str(), plugin->path.c_str()); | |||
| @@ -288,7 +288,7 @@ Model* modelFromJson(json_t* moduleJ) { | |||
| // Get Model | |||
| Model* model = getModel(pluginSlug, modelSlug); | |||
| if (!model) | |||
| throw Exception(string::f("Could not find module \"%s\" of plugin \"%s\"", modelSlug.c_str(), pluginSlug.c_str())); | |||
| throw Exception("Could not find module \"%s\" of plugin \"%s\"", modelSlug.c_str(), pluginSlug.c_str()); | |||
| return model; | |||
| } | |||
| @@ -19,7 +19,7 @@ void Model::fromJson(json_t* rootJ) { | |||
| if (nameJ) | |||
| name = json_string_value(nameJ); | |||
| if (name == "") | |||
| throw Exception(string::f("No module name for slug %s", slug.c_str())); | |||
| throw Exception("No module name for slug %s", slug.c_str()); | |||
| json_t* descriptionJ = json_object_get(rootJ, "description"); | |||
| if (descriptionJ) | |||
| @@ -39,14 +39,14 @@ void Plugin::fromJson(json_t* rootJ) { | |||
| if (slug == "") | |||
| throw Exception("No plugin slug"); | |||
| if (!isSlugValid(slug)) | |||
| throw Exception(string::f("Plugin slug \"%s\" is invalid", slug.c_str())); | |||
| throw Exception("Plugin slug \"%s\" is invalid", slug.c_str()); | |||
| // version | |||
| json_t* versionJ = json_object_get(rootJ, "version"); | |||
| if (versionJ) | |||
| version = json_string_value(versionJ); | |||
| if (!string::startsWith(version, ABI_VERSION + ".")) | |||
| throw Exception(string::f("Plugin version %s does not match Rack ABI version %s", version.c_str(), ABI_VERSION.c_str())); | |||
| throw Exception("Plugin version %s does not match Rack ABI version %s", version.c_str(), ABI_VERSION.c_str()); | |||
| if (version == "") | |||
| throw Exception("No plugin version"); | |||
| @@ -120,26 +120,26 @@ void Plugin::fromJson(json_t* rootJ) { | |||
| // Get model slug | |||
| json_t* modelSlugJ = json_object_get(moduleJ, "slug"); | |||
| if (!modelSlugJ) { | |||
| throw Exception(string::f("No slug found for module entry %d", moduleId)); | |||
| throw Exception("No slug found for module entry %" PRId64, moduleId); | |||
| } | |||
| std::string modelSlug = json_string_value(modelSlugJ); | |||
| // Check model slug | |||
| if (!isSlugValid(modelSlug)) { | |||
| throw Exception(string::f("Module slug \"%s\" is invalid", modelSlug.c_str())); | |||
| throw Exception("Module slug \"%s\" is invalid", modelSlug.c_str()); | |||
| } | |||
| // Get model | |||
| Model* model = getModel(modelSlug); | |||
| if (!model) { | |||
| throw Exception(string::f("Manifest contains module %s but it is not defined in the plugin", modelSlug.c_str())); | |||
| throw Exception("Manifest contains module %s but it is not defined in the plugin", modelSlug.c_str()); | |||
| } | |||
| model->fromJson(moduleJ); | |||
| } | |||
| } | |||
| else { | |||
| WARN("No modules in plugin %s", slug.c_str()); | |||
| WARN("No modules in plugin manifest %s", slug.c_str()); | |||
| } | |||
| // Remove models without names | |||
| @@ -32,7 +32,7 @@ struct RtAudioDevice : audio::Device { | |||
| rtAudio = new RtAudio(api); | |||
| rtAudio->showWarnings(false); | |||
| if (!rtAudio) { | |||
| throw Exception(string::f("Failed to create RtAudio driver %d", api)); | |||
| throw Exception("Failed to create RtAudio driver %d", api); | |||
| } | |||
| rtAudio->showWarnings(false); | |||
| @@ -40,7 +40,7 @@ struct RtAudioDevice : audio::Device { | |||
| deviceInfo = rtAudio->getDeviceInfo(deviceId); | |||
| } | |||
| catch (RtAudioError& e) { | |||
| throw Exception(string::f("Failed to query RtAudio device: %s", e.what())); | |||
| throw Exception("Failed to query RtAudio device: %s", e.what()); | |||
| } | |||
| this->deviceId = deviceId; | |||
| @@ -61,7 +61,7 @@ struct RtAudioDevice : audio::Device { | |||
| void openStream() { | |||
| // Open new device | |||
| if (deviceInfo.outputChannels == 0 && deviceInfo.inputChannels == 0) { | |||
| throw Exception(string::f("RtAudio device %d has 0 inputs and 0 outputs", deviceId)); | |||
| throw Exception("RtAudio device %d has 0 inputs and 0 outputs", deviceId); | |||
| } | |||
| inputParameters = RtAudio::StreamParameters(); | |||
| @@ -103,7 +103,7 @@ struct RtAudioDevice : audio::Device { | |||
| &rtAudioCallback, this, &options, NULL); | |||
| } | |||
| catch (RtAudioError& e) { | |||
| throw Exception(string::f("Failed to open RtAudio stream: %s", e.what())); | |||
| throw Exception("Failed to open RtAudio stream: %s", e.what()); | |||
| } | |||
| INFO("Starting RtAudio stream %d", deviceId); | |||
| @@ -111,7 +111,7 @@ struct RtAudioDevice : audio::Device { | |||
| rtAudio->startStream(); | |||
| } | |||
| catch (RtAudioError& e) { | |||
| throw Exception(string::f("Failed to start RtAudio stream: %s", e.what())); | |||
| throw Exception("Failed to start RtAudio stream: %s", e.what()); | |||
| } | |||
| // Update sample rate to actual value | |||
| @@ -127,7 +127,7 @@ struct RtAudioDevice : audio::Device { | |||
| rtAudio->stopStream(); | |||
| } | |||
| catch (RtAudioError& e) { | |||
| throw Exception(string::f("Failed to stop RtAudio stream %s", e.what())); | |||
| throw Exception("Failed to stop RtAudio stream %s", e.what()); | |||
| } | |||
| } | |||
| if (rtAudio->isStreamOpen()) { | |||
| @@ -136,7 +136,7 @@ struct RtAudioDevice : audio::Device { | |||
| rtAudio->closeStream(); | |||
| } | |||
| catch (RtAudioError& e) { | |||
| throw Exception(string::f("Failed to close RtAudio stream %s", e.what())); | |||
| throw Exception("Failed to close RtAudio stream %s", e.what()); | |||
| } | |||
| } | |||
| INFO("Closed RtAudio stream"); | |||
| @@ -35,7 +35,7 @@ struct RtMidiInputDevice : midi::InputDevice { | |||
| rtMidiIn = new RtMidiIn((RtMidi::Api) driverId, "VCV Rack"); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to create RtMidi input driver %d: %s", driverId, e.what())); | |||
| throw Exception("Failed to create RtMidi input driver %d: %s", driverId, e.what()); | |||
| } | |||
| rtMidiIn->setErrorCallback(rtMidiErrorCallback); | |||
| rtMidiIn->ignoreTypes(false, false, false); | |||
| @@ -45,14 +45,14 @@ struct RtMidiInputDevice : midi::InputDevice { | |||
| name = rtMidiIn->getPortName(deviceId); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to get RtMidi input device name: %s", e.what())); | |||
| throw Exception("Failed to get RtMidi input device name: %s", e.what()); | |||
| } | |||
| try { | |||
| rtMidiIn->openPort(deviceId, "VCV Rack input"); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to open RtMidi input device: %s", e.what())); | |||
| throw Exception("Failed to open RtMidi input device: %s", e.what()); | |||
| } | |||
| } | |||
| @@ -105,7 +105,7 @@ struct RtMidiOutputDevice : midi::OutputDevice { | |||
| rtMidiOut = new RtMidiOut((RtMidi::Api) driverId, "VCV Rack"); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to create RtMidi output driver %d: %s", driverId, e.what())); | |||
| throw Exception("Failed to create RtMidi output driver %d: %s", driverId, e.what()); | |||
| } | |||
| rtMidiOut->setErrorCallback(rtMidiErrorCallback); | |||
| @@ -113,14 +113,14 @@ struct RtMidiOutputDevice : midi::OutputDevice { | |||
| name = rtMidiOut->getPortName(deviceId); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to get RtMidi output device name: %s", e.what())); | |||
| throw Exception("Failed to get RtMidi output device name: %s", e.what()); | |||
| } | |||
| try { | |||
| rtMidiOut->openPort(deviceId, "VCV Rack output"); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to get RtMidi output device name: %s", e.what())); | |||
| throw Exception("Failed to get RtMidi output device name: %s", e.what()); | |||
| } | |||
| startThread(); | |||
| @@ -211,7 +211,7 @@ struct RtMidiDriver : midi::Driver { | |||
| rtMidiIn = new RtMidiIn((RtMidi::Api) driverId); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to create RtMidi input driver %d: %s", driverId, e.what())); | |||
| throw Exception("Failed to create RtMidi input driver %d: %s", driverId, e.what()); | |||
| } | |||
| rtMidiIn->setErrorCallback(rtMidiErrorCallback); | |||
| @@ -219,7 +219,7 @@ struct RtMidiDriver : midi::Driver { | |||
| rtMidiOut = new RtMidiOut((RtMidi::Api) driverId); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to create RtMidi output driver %d: %s", driverId, e.what())); | |||
| throw Exception("Failed to create RtMidi output driver %d: %s", driverId, e.what()); | |||
| } | |||
| rtMidiOut->setErrorCallback(rtMidiErrorCallback); | |||
| } | |||
| @@ -250,7 +250,7 @@ struct RtMidiDriver : midi::Driver { | |||
| count = rtMidiIn->getPortCount(); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to get RtMidi input device count: %s", e.what())); | |||
| throw Exception("Failed to get RtMidi input device count: %s", e.what()); | |||
| } | |||
| std::vector<int> deviceIds; | |||
| @@ -266,7 +266,7 @@ struct RtMidiDriver : midi::Driver { | |||
| return rtMidiIn->getPortName(deviceId); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to get RtMidi input device name: %s", e.what())); | |||
| throw Exception("Failed to get RtMidi input device name: %s", e.what()); | |||
| } | |||
| } | |||
| @@ -279,7 +279,7 @@ struct RtMidiDriver : midi::Driver { | |||
| inputDevices[deviceId] = device = new RtMidiInputDevice(driverId, deviceId); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to create RtMidi input device: %s", e.what())); | |||
| throw Exception("Failed to create RtMidi input device: %s", e.what()); | |||
| } | |||
| } | |||
| @@ -301,7 +301,7 @@ struct RtMidiDriver : midi::Driver { | |||
| delete device; | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to delete RtMidi input device: %s", e.what())); | |||
| throw Exception("Failed to delete RtMidi input device: %s", e.what()); | |||
| } | |||
| } | |||
| } | |||
| @@ -313,7 +313,7 @@ struct RtMidiDriver : midi::Driver { | |||
| count = rtMidiOut->getPortCount(); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to get RtMidi output device count: %s", e.what())); | |||
| throw Exception("Failed to get RtMidi output device count: %s", e.what()); | |||
| } | |||
| std::vector<int> deviceIds; | |||
| @@ -329,7 +329,7 @@ struct RtMidiDriver : midi::Driver { | |||
| return rtMidiOut->getPortName(deviceId); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to get RtMidi output device count: %s", e.what())); | |||
| throw Exception("Failed to get RtMidi output device count: %s", e.what()); | |||
| } | |||
| } | |||
| @@ -342,7 +342,7 @@ struct RtMidiDriver : midi::Driver { | |||
| outputDevices[deviceId] = device = new RtMidiOutputDevice(driverId, deviceId); | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to create RtMidi output device: %s", e.what())); | |||
| throw Exception("Failed to create RtMidi output device: %s", e.what()); | |||
| } | |||
| } | |||
| @@ -364,7 +364,7 @@ struct RtMidiDriver : midi::Driver { | |||
| delete device; | |||
| } | |||
| catch (RtMidiError& e) { | |||
| throw Exception(string::f("Failed to delete RtMidi output device: %s", e.what())); | |||
| throw Exception("Failed to delete RtMidi output device: %s", e.what()); | |||
| } | |||
| } | |||
| } | |||
| @@ -356,7 +356,7 @@ void load(const std::string& path) { | |||
| json_error_t error; | |||
| json_t* rootJ = json_loadf(file, 0, &error); | |||
| if (!rootJ) | |||
| throw Exception(string::f("Settings file has invalid JSON at %d:%d %s", error.line, error.column, error.text)); | |||
| throw Exception("Settings file has invalid JSON at %d:%d %s", error.line, error.column, error.text); | |||
| fromJson(rootJ); | |||
| json_decref(rootJ); | |||
| @@ -1,6 +1,7 @@ | |||
| #include <cctype> // for tolower and toupper | |||
| #include <algorithm> // for transform and equal | |||
| #include <libgen.h> // for dirname and basename | |||
| #include <stdarg.h> | |||
| #if defined ARCH_WIN | |||
| #include <windows.h> // for MultiByteToWideChar | |||
| @@ -16,17 +17,24 @@ namespace string { | |||
| std::string f(const char* format, ...) { | |||
| va_list args; | |||
| va_start(args, format); | |||
| std::string s = fV(format, args); | |||
| va_end(args); | |||
| return s; | |||
| } | |||
| std::string fV(const char* format, va_list args) { | |||
| // va_lists cannot be reused but we need it twice, so clone args. | |||
| va_list args2; | |||
| va_copy(args2, args); | |||
| // Compute size of required buffer | |||
| int size = vsnprintf(NULL, 0, format, args); | |||
| va_end(args); | |||
| if (size < 0) | |||
| return ""; | |||
| // Create buffer | |||
| std::string s; | |||
| s.resize(size); | |||
| va_start(args, format); | |||
| vsnprintf(&s[0], size + 1, format, args); | |||
| va_end(args); | |||
| vsnprintf(&s[0], size + 1, format, args2); | |||
| return s; | |||
| } | |||
| @@ -303,7 +303,7 @@ void archiveFolder(const std::string& archivePath, const std::string& folderPath | |||
| assert(0 <= compressionLevel && compressionLevel <= 19); | |||
| r = archive_write_set_filter_option(a, NULL, "compression-level", std::to_string(compressionLevel).c_str()); | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Archiver could not set filter option: %s", archive_error_string(a))); | |||
| throw Exception("Archiver could not set filter option: %s", archive_error_string(a)); | |||
| #if defined ARCH_WIN | |||
| r = archive_write_open_filename_w(a, string::U8toU16(archivePath).c_str()); | |||
| @@ -311,7 +311,7 @@ void archiveFolder(const std::string& archivePath, const std::string& folderPath | |||
| r = archive_write_open_filename(a, archivePath.c_str()); | |||
| #endif | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Archiver could not open archive %s for writing: %s", archivePath.c_str(), archive_error_string(a))); | |||
| throw Exception("Archiver could not open archive %s for writing: %s", archivePath.c_str(), archive_error_string(a)); | |||
| DEFER({archive_write_close(a);}); | |||
| // Open folder for reading | |||
| @@ -323,7 +323,7 @@ void archiveFolder(const std::string& archivePath, const std::string& folderPath | |||
| r = archive_read_disk_open(disk, folderPath.c_str()); | |||
| #endif | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Archiver could not open folder %s for reading: %s", folderPath.c_str(), archive_error_string(a))); | |||
| throw Exception("Archiver could not open folder %s for reading: %s", folderPath.c_str(), archive_error_string(a)); | |||
| DEFER({archive_read_close(a);}); | |||
| // Iterate folder | |||
| @@ -335,7 +335,7 @@ void archiveFolder(const std::string& archivePath, const std::string& folderPath | |||
| if (r == ARCHIVE_EOF) | |||
| break; | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Archiver could not get next entry from archive: %s", archive_error_string(disk))); | |||
| throw Exception("Archiver could not get next entry from archive: %s", archive_error_string(disk)); | |||
| // Recurse dirs | |||
| archive_read_disk_descend(disk); | |||
| @@ -358,7 +358,7 @@ void archiveFolder(const std::string& archivePath, const std::string& folderPath | |||
| // Write file to archive | |||
| r = archive_write_header(a, entry); | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Archiver could not write entry to archive: %s", archive_error_string(a))); | |||
| throw Exception("Archiver could not write entry to archive: %s", archive_error_string(a)); | |||
| // Manually copy data | |||
| #if defined ARCH_WIN | |||
| @@ -394,7 +394,7 @@ void unarchiveToFolder(const std::string& archivePath, const std::string& folder | |||
| r = archive_read_open_filename(a, archivePath.c_str(), 1 << 14); | |||
| #endif | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Unarchiver could not open archive %s: %s", archivePath.c_str(), archive_error_string(a))); | |||
| throw Exception("Unarchiver could not open archive %s: %s", archivePath.c_str(), archive_error_string(a)); | |||
| DEFER({archive_read_close(a);}); | |||
| // Open folder for writing | |||
| @@ -412,12 +412,12 @@ void unarchiveToFolder(const std::string& archivePath, const std::string& folder | |||
| if (r == ARCHIVE_EOF) | |||
| break; | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Unarchiver could not read entry from archive: %s", archive_error_string(a))); | |||
| throw Exception("Unarchiver could not read entry from archive: %s", archive_error_string(a)); | |||
| // Convert relative pathname to absolute based on folderPath | |||
| std::string entryPath = archive_entry_pathname(entry); | |||
| if (!fs::u8path(entryPath).is_relative()) | |||
| throw Exception(string::f("Unarchiver does not support absolute tar paths: %s", entryPath.c_str())); | |||
| throw Exception("Unarchiver does not support absolute tar paths: %s", entryPath.c_str()); | |||
| entryPath = (fs::u8path(folderPath) / fs::u8path(entryPath)).generic_u8string(); | |||
| #if defined ARCH_WIN | |||
| archive_entry_copy_pathname_w(entry, string::U8toU16(entryPath).c_str()); | |||
| @@ -428,7 +428,7 @@ void unarchiveToFolder(const std::string& archivePath, const std::string& folder | |||
| // Write entry to disk | |||
| r = archive_write_header(disk, entry); | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Unarchiver could not write file to folder: %s", archive_error_string(disk))); | |||
| throw Exception("Unarchiver could not write file to folder: %s", archive_error_string(disk)); | |||
| // Copy data to file | |||
| for (;;) { | |||
| @@ -440,18 +440,18 @@ void unarchiveToFolder(const std::string& archivePath, const std::string& folder | |||
| if (r == ARCHIVE_EOF) | |||
| break; | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Unarchiver could not read data from archive", archive_error_string(a))); | |||
| throw Exception("Unarchiver could not read data from archive: %s", archive_error_string(a)); | |||
| // Write data to file | |||
| r = archive_write_data_block(disk, buf, size, offset); | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Unarchiver could not write data to file", archive_error_string(disk))); | |||
| throw Exception("Unarchiver could not write data to file: %s", archive_error_string(disk)); | |||
| } | |||
| // Close file | |||
| r = archive_write_finish_entry(disk); | |||
| if (r < ARCHIVE_OK) | |||
| throw Exception(string::f("Unarchiver could not close file", archive_error_string(disk))); | |||
| throw Exception("Unarchiver could not close file: %s", archive_error_string(disk)); | |||
| } | |||
| } | |||