// Copyright (c) 2015-2026 Vector 35 Inc
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
#include
#include "binaryninjaapi.h"
using namespace BinaryNinja;
using namespace Json;
using namespace std;
KeyValueStore::KeyValueStore()
{
m_object = BNCreateKeyValueStore();
}
KeyValueStore::KeyValueStore(const DataBuffer& buffer)
{
m_object = BNCreateKeyValueStoreFromDataBuffer(buffer.GetBufferObject());
}
KeyValueStore::KeyValueStore(BNKeyValueStore* store)
{
m_object = store;
}
std::vector<:string> KeyValueStore::GetKeys() const
{
size_t count;
char** keys = BNGetKeyValueStoreKeys(m_object, &count);
std::vector<:string> strings;
strings.reserve(count);
for (size_t i = 0; i < count; ++i)
{
strings.push_back(keys[i]);
}
BNFreeStringList(keys, count);
return strings;
}
bool KeyValueStore::HasValue(const std::string& name) const
{
return BNKeyValueStoreHasValue(m_object, name.c_str());
}
Json::Value KeyValueStore::GetValue(const std::string& name) const
{
BNDataBuffer* bnBuffer = BNGetKeyValueStoreBuffer(m_object, name.c_str());
if (bnBuffer == nullptr)
{
throw DatabaseException("BNGetKeyValueStoreBuffer");
}
DataBuffer value = DataBuffer(bnBuffer);
Json::Value json;
std::unique_ptr<:charreader> reader(Json::CharReaderBuilder().newCharReader());
std::string errors;
if (!reader->parse(static_cast(value.GetData()),
static_cast(value.GetDataAt(value.GetLength())), &json, &errors))
{
throw DatabaseException(errors);
}
return json;
}
DataBuffer KeyValueStore::GetValueHash(const std::string& name) const
{
BNDataBuffer* buffer = BNGetKeyValueStoreValueHash(m_object, name.c_str());
if (buffer == nullptr)
{
throw DatabaseException("Unknown key");
}
return DataBuffer(buffer);
}
DataBuffer KeyValueStore::GetBuffer(const std::string& name) const
{
BNDataBuffer* buffer = BNGetKeyValueStoreBuffer(m_object, name.c_str());
if (buffer == nullptr)
{
throw DatabaseException("Unknown key");
}
return DataBuffer(buffer);
}
void KeyValueStore::SetValue(const std::string& name, const Json::Value& value)
{
Json::StreamWriterBuilder builder;
builder["indentation"] = "";
string json = Json::writeString(builder, value);
if (!BNSetKeyValueStoreValue(m_object, name.c_str(), json.c_str()))
{
throw DatabaseException("BNSetKeyValueStoreValue");
}
}
void KeyValueStore::SetBuffer(const std::string& name, const DataBuffer& value)
{
if (!BNSetKeyValueStoreBuffer(m_object, name.c_str(), value.GetBufferObject()))
{
throw DatabaseException("BNSetKeyValueStoreBuffer");
}
}
DataBuffer KeyValueStore::GetSerializedData() const
{
return DataBuffer(BNGetKeyValueStoreSerializedData(m_object));
}
void KeyValueStore::BeginNamespace(const std::string& name)
{
BNBeginKeyValueStoreNamespace(m_object, name.c_str());
}
void KeyValueStore::EndNamespace()
{
BNEndKeyValueStoreNamespace(m_object);
}
bool KeyValueStore::IsEmpty() const
{
return BNIsKeyValueStoreEmpty(m_object);
}
size_t KeyValueStore::ValueSize() const
{
return BNGetKeyValueStoreValueSize(m_object);
}
size_t KeyValueStore::DataSize() const
{
return BNGetKeyValueStoreDataSize(m_object);
}
size_t KeyValueStore::ValueStorageSize() const
{
return BNGetKeyValueStoreValueStorageSize(m_object);
}
size_t KeyValueStore::NamespaceSize() const
{
return BNGetKeyValueStoreNamespaceSize(m_object);
}
Snapshot::Snapshot(BNSnapshot* snapshot)
{
m_object = snapshot;
}
Ref Snapshot::GetDatabase()
{
return new Database(BNGetSnapshotDatabase(m_object));
}
int64_t Snapshot::GetId()
{
return BNGetSnapshotId(m_object);
}
std::string Snapshot::GetName()
{
char* cstr = BNGetSnapshotName(m_object);
std::string str {cstr};
BNFreeString(cstr);
return str;
}
void Snapshot::SetName(const std::string& name)
{
BNSetSnapshotName(m_object, name.c_str());
}
bool Snapshot::IsAutoSave()
{
return BNIsSnapshotAutoSave(m_object);
}
bool Snapshot::HasContents()
{
return BNSnapshotHasContents(m_object);
}
bool Snapshot::HasData()
{
return GetDatabase()->SnapshotHasData(GetId());
}
bool Snapshot::HasUndo()
{
return BNSnapshotHasUndo(m_object);
}
Ref Snapshot::GetFirstParent()
{
BNSnapshot* snap = BNGetSnapshotFirstParent(m_object);
if (snap == nullptr)
return nullptr;
return new Snapshot(snap);
}
vector[> Snapshot::GetParents()
{
size_t count;
BNSnapshot** parents = BNGetSnapshotParents(m_object, &count);
vector][> result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
{
result.push_back(new Snapshot(BNNewSnapshotReference(parents[i])));
}
BNFreeSnapshotList(parents, count);
return result;
}
vector][> Snapshot::GetChildren()
{
size_t count;
BNSnapshot** children = BNGetSnapshotChildren(m_object, &count);
vector][> result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
{
result.push_back(new Snapshot(BNNewSnapshotReference(children[i])));
}
BNFreeSnapshotList(children, count);
return result;
}
DataBuffer Snapshot::GetFileContents()
{
BNDataBuffer* buffer = BNGetSnapshotFileContents(m_object);
if (buffer == nullptr)
{
throw DatabaseException("BNGetSnapshotFileContents");
}
return DataBuffer(buffer);
}
DataBuffer Snapshot::GetFileContentsHash()
{
BNDataBuffer* buffer = BNGetSnapshotFileContentsHash(m_object);
if (buffer == nullptr)
{
throw DatabaseException("BNGetSnapshotFileContentsHash");
}
return DataBuffer(buffer);
}
DataBuffer Snapshot::GetUndoData()
{
BNDataBuffer* buffer = BNGetSnapshotUndoData(m_object);
if (buffer == nullptr)
{
throw DatabaseException("BNGetSnapshotUndoData");
}
return DataBuffer(buffer);
}
vector][> Snapshot::GetUndoEntries()
{
return GetUndoEntries([](size_t, size_t) { return true; });
}
vector][> Snapshot::GetUndoEntries(const ProgressFunction& progress)
{
ProgressContext pctxt;
pctxt.callback = progress;
size_t count;
BNUndoEntry** entries = BNGetSnapshotUndoEntriesWithProgress(m_object, &pctxt, ProgressCallback, &count);
if (entries == nullptr)
{
throw DatabaseException("BNGetSnapshotUndoEntriesWithProgress");
}
vector][> result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
{
result.push_back(new UndoEntry(BNNewUndoEntryReference(entries[i])));
}
BNFreeUndoEntryList(entries, count);
return result;
}
Ref Snapshot::ReadData()
{
return ReadData([](size_t, size_t) { return true; });
}
Ref Snapshot::ReadData(const ProgressFunction& progress)
{
ProgressContext pctxt;
pctxt.callback = progress;
BNKeyValueStore* store = BNReadSnapshotDataWithProgress(m_object, &pctxt, ProgressCallback);
if (store == nullptr)
{
throw DatabaseException("BNReadSnapshotData");
}
return new KeyValueStore(store);
}
bool Snapshot::StoreData(const Ref& data, const ProgressFunction& progress)
{
ProgressContext pctxt;
pctxt.callback = progress;
bool result = BNSnapshotStoreData(m_object, data->GetObject(), &pctxt, ProgressCallback);
if (!result)
{
throw DatabaseException("BNSnapshotStoreData");
}
return result;
}
bool Snapshot::HasAncestor(Ref other)
{
return BNSnapshotHasAncestor(m_object, other->GetObject());
}
Database::Database(BNDatabase* database)
{
m_object = database;
}
Ref Database::GetSnapshot(int64_t id)
{
BNSnapshot* snap = BNGetDatabaseSnapshot(m_object, id);
if (snap == nullptr)
return nullptr;
return new Snapshot(snap);
}
vector][> Database::GetSnapshots()
{
size_t count;
BNSnapshot** snapshots = BNGetDatabaseSnapshots(m_object, &count);
vector][> result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.push_back(new Snapshot(BNNewSnapshotReference(snapshots[i])));
BNFreeSnapshotList(snapshots, count);
return result;
}
void Database::SetCurrentSnapshot(int64_t id)
{
BNSetDatabaseCurrentSnapshot(m_object, id);
}
Ref Database::GetCurrentSnapshot()
{
BNSnapshot* snap = BNGetDatabaseCurrentSnapshot(m_object);
if (snap == nullptr)
return nullptr;
return new Snapshot(snap);
}
int64_t Database::WriteSnapshotData(std::vector parents, Ref file, const std::string& name,
const Ref& data, bool autoSave, const ProgressFunction& progress)
{
ProgressContext pctxt;
pctxt.callback = progress;
int64_t result = BNWriteDatabaseSnapshotData(m_object, parents.data(), parents.size(), file->GetObject(),
name.c_str(), data->GetObject(), autoSave, &pctxt, ProgressCallback);
if (result < 0)
{
throw DatabaseException("BNWriteDatabaseSnapshotData");
}
return result;
}
void Database::TrimSnapshot(int64_t id)
{
if (!BNTrimDatabaseSnapshot(m_object, id))
{
throw DatabaseException("BNTrimDatabaseSnapshot");
}
}
void Database::RemoveSnapshot(int64_t id)
{
if (!BNRemoveDatabaseSnapshot(m_object, id))
{
throw DatabaseException("BNRemoveDatabaseSnapshot");
}
}
std::vector<:string> Database::GetGlobalKeys() const
{
size_t count;
char** value = BNGetDatabaseGlobalKeys(m_object, &count);
if (value == nullptr)
{
throw DatabaseException("BNDatabaseHasGlobal");
}
std::vector<:string> result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
{
result.push_back(value[i]);
}
BNFreeStringList(value, count);
return result;
}
bool Database::HasGlobal(const std::string& key) const
{
// 0 - false, 1 - true, <0 - exception
int value = BNDatabaseHasGlobal(m_object, key.c_str());
if (value < 0)
{
throw DatabaseException("BNDatabaseHasGlobal");
}
return value == 1;
}
Json::Value Database::ReadGlobal(const std::string& key) const
{
char* value = BNReadDatabaseGlobal(m_object, key.c_str());
if (value == nullptr)
{
throw DatabaseException("BNReadDatabaseGlobal");
}
Json::Value json;
std::unique_ptr<:charreader> reader(Json::CharReaderBuilder().newCharReader());
std::string errors;
if (!reader->parse(value, value + strlen(value), &json, &errors))
{
throw DatabaseException(errors);
}
BNFreeString(value);
return json;
}
void Database::WriteGlobal(const std::string& key, const Json::Value& val)
{
Json::StreamWriterBuilder builder;
builder["indentation"] = "";
string json = Json::writeString(builder, val);
if (!BNWriteDatabaseGlobal(m_object, key.c_str(), json.c_str()))
{
throw DatabaseException("BNWriteDatabaseGlobal");
}
}
DataBuffer Database::ReadGlobalData(const std::string& key) const
{
BNDataBuffer* value = BNReadDatabaseGlobalData(m_object, key.c_str());
if (value == nullptr)
{
throw DatabaseException("BNReadDatabaseGlobalData");
}
return DataBuffer(value);
}
void Database::WriteGlobalData(const std::string& key, const DataBuffer& val)
{
if (!BNWriteDatabaseGlobalData(m_object, key.c_str(), val.GetBufferObject()))
{
throw DatabaseException("BNWriteDatabaseGlobalData");
}
}
Ref Database::GetFile()
{
return new FileMetadata(BNGetDatabaseFile(m_object));
}
void Database::ReloadConnection()
{
BNDatabaseReloadConnection(m_object);
}
Ref Database::ReadAnalysisCache() const
{
BNKeyValueStore* store = BNReadDatabaseAnalysisCache(m_object);
if (store == nullptr)
{
throw DatabaseException("BNReadDatabaseAnalysisCache");
}
return new KeyValueStore(store);
}
void Database::WriteAnalysisCache(Ref val)
{
if (!BNWriteDatabaseAnalysisCache(m_object, val->GetObject()))
{
throw DatabaseException("BNWriteDatabaseAnalysisCache");
}
}
bool Database::SnapshotHasData(int64_t id)
{
return BNSnapshotHasData(m_object, id);
}
]