454f67b3bc
Clamps insertSuffix's underflow, floors uniqueEntryName's validity guard, suppresses the redundant overwrite confirm via a picker out-param, adds a PayloadBuffer high-water mark, and corrects stale CLAUDE.md/CMake claims.
67 lines
2.4 KiB
C++
67 lines
2.4 KiB
C++
// package_pickers.cpp — see package_pickers.h. GetUserFileName cannot be null here:
|
|
// main.cpp defines REAPERAPI_IMPLEMENT without REAPERAPI_MINIMAL, so the generated
|
|
// resolver walks the FULL table, and it aborts the extension load if any single name
|
|
// fails to resolve. A fallback picker would be unreachable code.
|
|
|
|
#include "shell/package/package_pickers.h"
|
|
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
|
|
#define REAPERAPI_MINIMAL
|
|
#define REAPERAPI_WANT_GetUserFileName
|
|
#include "reaper_plugin_functions.h"
|
|
|
|
namespace reasampler {
|
|
|
|
namespace {
|
|
|
|
// GetUserFileName's documented pair format: label|pattern|label|pattern.
|
|
const char kExtList[] =
|
|
"ReaSampler bank package (*.rsbank)|*.rsbank|All files (*.*)|*.*";
|
|
|
|
bool runPicker(int mode, const char* caption, const char* initial,
|
|
std::string& outAbsPath) {
|
|
outAbsPath.clear();
|
|
char buf[4096];
|
|
buf[0] = '\0';
|
|
if (!GetUserFileName(mode, caption, initial, kExtList, buf,
|
|
static_cast<int>(sizeof(buf)))) {
|
|
return false;
|
|
}
|
|
outAbsPath = buf;
|
|
return !outAbsPath.empty();
|
|
}
|
|
|
|
bool hasCaseInsensitiveSuffix(const std::string& path, const std::string& suffix) {
|
|
if (path.size() < suffix.size()) return false;
|
|
return std::equal(suffix.rbegin(), suffix.rend(), path.rbegin(),
|
|
[](unsigned char a, unsigned char b) {
|
|
return std::tolower(a) == std::tolower(b);
|
|
});
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool pickPackageForImport(std::string& outAbsPath) {
|
|
return runPicker(1, "Import bank package", "", outAbsPath);
|
|
}
|
|
|
|
bool pickPackageSavePath(const std::string& suggestedPath, std::string& outAbsPath,
|
|
bool* outAppended) {
|
|
// [verify — DAW] GetUserFileName takes no owner window, so the dialog's parenting
|
|
// is REAPER's to do; the previous Win32 path passed GetMainHwnd() explicitly.
|
|
if (!runPicker(0, "Export bank package", suggestedPath.c_str(), outAbsPath)) {
|
|
return false;
|
|
}
|
|
// GetUserFileName has no lpstrDefExt equivalent (the old Win32 picker's
|
|
// ofn.lpstrDefExt = L"rsbank"); whether mode 0 appends one itself from
|
|
// kExtList is [verify — DAW], so append it ourselves whenever it's missing.
|
|
const bool appended = !hasCaseInsensitiveSuffix(outAbsPath, ".rsbank");
|
|
if (appended) outAbsPath += ".rsbank";
|
|
if (outAppended) *outAppended = appended;
|
|
return true;
|
|
}
|
|
|
|
} // namespace reasampler
|