Browse Source

Add `Exception::Exception(const char* format, ...)` so you can create Exception objects using C format strings.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
86f3658b51
14 changed files with 83 additions and 60 deletions
  1. +5
    -1
      include/common.hpp
  2. +1
    -1
      include/logger.hpp
  3. +1
    -1
      include/rack.hpp
  4. +3
    -0
      include/string.hpp
  5. +2
    -2
      src/app/ModuleWidget.cpp
  6. +8
    -0
      src/common.cpp
  7. +8
    -8
      src/plugin.cpp
  8. +1
    -1
      src/plugin/Model.cpp
  9. +6
    -6
      src/plugin/Plugin.cpp
  10. +7
    -7
      src/rtaudio.cpp
  11. +16
    -16
      src/rtmidi.cpp
  12. +1
    -1
      src/settings.cpp
  13. +12
    -4
      src/string.cpp
  14. +12
    -12
      src/system.cpp

+ 5
- 1
include/common.hpp View File

@@ -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();


+ 1
- 1
include/logger.hpp View File

@@ -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().


+ 1
- 1
include/rack.hpp View File

@@ -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 {


+ 3
- 0
include/string.hpp View File

@@ -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 */


+ 2
- 2
src/app/ModuleWidget.cpp View File

@@ -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


+ 8
- 0
src/common.cpp View File

@@ -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




+ 8
- 8
src/plugin.cpp View File

@@ -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;
}



+ 1
- 1
src/plugin/Model.cpp View File

@@ -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)


+ 6
- 6
src/plugin/Plugin.cpp View File

@@ -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


+ 7
- 7
src/rtaudio.cpp View File

@@ -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");


+ 16
- 16
src/rtmidi.cpp View File

@@ -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());
}
}
}


+ 1
- 1
src/settings.cpp View File

@@ -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);


+ 12
- 4
src/string.cpp View File

@@ -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;
}



+ 12
- 12
src/system.cpp View File

@@ -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));
}
}



Loading…
Cancel
Save