Q-W5: persist → session/ext_state_io/prune_fs (deletion authority concentrated); one GetProjExtState grow-loop in bridge_marshal (T2-04, ×3 rewired); bank_book JSON codec → bank_book_json via private static nameKey; persist.h stays umbrella. 61/61 green.
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "core/version/app_version.h" // vstPluginName / vstOutputName (channel name needles)
|
||||
#include "core/instrument/map/bridge_marshal.h" // readProjExtStateGrowing (T2-04: the ONE grow-loop policy)
|
||||
#include "ext_keys.h" // kProjExtNamespace / kProjExtUsageKeyPrefix
|
||||
#include "core/wire/instrument_drop.h" // vstClassIdHex — the frozen channel class-UID hex
|
||||
#include "core/wire/sample_usage.h" // identityMatches, foldUsageRecords (the pure decisions)
|
||||
@@ -166,22 +167,23 @@ bool itemHasInstance(MediaItem* item, const FxIdentityNeedles& id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Growing GetProjExtState read (the persist.cpp idiom): the usage record scales with
|
||||
// the hold count, so a fixed buffer risks a truncated decode. Returns nullopt when the
|
||||
// key cannot be read WHOLE — absent-after-enumeration (rv <= 0) or pathologically large
|
||||
// (> 16 MB give-up). The caller only queries keys the enumeration just listed, so a
|
||||
// nullopt here is a PRESENT-BUT-UNREADABLE record: it folds to abortPrune (fail-safe —
|
||||
// silently reduced protection is the delete direction).
|
||||
// Growing GetProjExtState read: the usage record scales with the hold count, so a
|
||||
// fixed buffer risks a truncated decode. The retry policy is the SHARED pure
|
||||
// instrument::map::readProjExtStateGrowing (Q-W5 rider T2-04 — one loop for persist,
|
||||
// this prune-safety-adjacent read, and the VST bridge; the rules cannot drift).
|
||||
// Returns nullopt when the key cannot be read WHOLE — absent-after-enumeration
|
||||
// (rv <= 0) or pathologically large (> 16 MB give-up). The caller only queries keys
|
||||
// the enumeration just listed, so a nullopt here is a PRESENT-BUT-UNREADABLE record:
|
||||
// it folds to abortPrune (fail-safe — silently reduced protection is the delete
|
||||
// direction).
|
||||
std::optional<std::string> readExtStateValue(ReaProject* proj, const char* key) {
|
||||
for (int cap = 1 << 12; cap <= (1 << 24); cap <<= 2) {
|
||||
std::vector<char> buf(static_cast<std::size_t>(cap), '\0');
|
||||
const int rv = GetProjExtState(proj, kProjExtNamespace(), key, buf.data(), cap);
|
||||
if (rv <= 0) return std::nullopt;
|
||||
std::string s(buf.data());
|
||||
if (static_cast<int>(s.size()) + 1 < cap) return s;
|
||||
// else possibly truncated -> grow and retry
|
||||
}
|
||||
return std::nullopt; // > 16 MB — unreadable whole, never "absent"
|
||||
using instrument::map::GrowingExtStateRead;
|
||||
const GrowingExtStateRead read = instrument::map::readProjExtStateGrowing(
|
||||
[&](char* buf, int cap) {
|
||||
return GetProjExtState(proj, kProjExtNamespace(), key, buf, cap);
|
||||
});
|
||||
if (read.status != GrowingExtStateRead::Status::Complete) return std::nullopt;
|
||||
return read.value;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user