summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.cpp40
-rw-r--r--binaryninjaapi.h128
-rw-r--r--binaryninjacore.h67
-rw-r--r--database.cpp511
-rw-r--r--databuffer.cpp22
-rw-r--r--filemetadata.cpp33
-rw-r--r--ui/uitypes.h4
7 files changed, 804 insertions, 1 deletions
diff --git a/binaryninjaapi.cpp b/binaryninjaapi.cpp
index 6b2497a9..d2815e8f 100644
--- a/binaryninjaapi.cpp
+++ b/binaryninjaapi.cpp
@@ -19,6 +19,7 @@
// IN THE SOFTWARE.
#include "binaryninjaapi.h"
+#include <numeric>
using namespace BinaryNinja;
using namespace std;
@@ -385,4 +386,41 @@ map<string, uint64_t> BinaryNinja::GetMemoryUsageInfo()
result[info[i].name] = info[i].value;
BNFreeMemoryUsageInfo(info, count);
return result;
-} \ No newline at end of file
+}
+
+
+std::function<bool(size_t, size_t)>
+BinaryNinja::SplitProgress(std::function<bool(size_t, size_t)> originalFn, size_t subpart, size_t subpartCount)
+{
+ return SplitProgress(originalFn, subpart, std::vector<double>(subpartCount, 1.0 / (double)subpartCount));
+}
+
+
+std::function<bool(size_t, size_t)>
+BinaryNinja::SplitProgress(std::function<bool(size_t, size_t)> originalFn, size_t subpart, std::vector<double> subpartWeights)
+{
+ if (!originalFn)
+ return [](size_t, size_t){ return true; };
+
+ // Normalize weights
+ double weightSum = std::accumulate(subpartWeights.begin(), subpartWeights.end(), 0.0);
+ if (weightSum < 0.0001f)
+ return [](size_t, size_t){ return true; };
+ // Keep a running count of weights for the start
+ std::vector<double> subpartStarts;
+ double start = 0.0;
+ for (auto i = 0; i < subpartWeights.size(); ++i)
+ {
+ subpartStarts.push_back(start);
+ subpartWeights[i] /= weightSum;
+ start += subpartWeights[i];
+ }
+
+ return [=](size_t current, size_t max) {
+ // Just use a large number for easy divisibility
+ size_t steps = 1000000;
+ double subpartSize = steps * subpartWeights[subpart];
+ double subpartProgress = ((double)current / (double)max) * subpartSize;
+ return originalFn(subpartStarts[subpart] * steps + subpartProgress, steps);
+ };
+}
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 7927ede9..5a0773ef 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -724,6 +724,42 @@ __attribute__ ((format (printf, 1, 2)))
BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text,
BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon);
+ /*!
+ Split a single progress function into equally sized subparts.
+ This function takes the original progress function and returns a new function whose signature
+ is the same but whose output is shortened to correspond to the specified subparts.
+
+ E.g. If subpart = 0 and subpartCount = 3, this returns a function that calls originalFn and has
+ all of its progress multiplied by 1/3 and 0/3 added.
+
+ Internally this works by calling originalFn with total = 1000000 and doing math on the current value
+
+ \param originalFn Original progress function (usually updates a UI)
+ \param subpart Index of subpart whose function to return, from 0 to (subpartCount - 1)
+ \param subpartCount Total number of subparts
+ \return A function that will call originalFn() within a modified progress region
+ */
+ std::function<bool(size_t, size_t)> SplitProgress(std::function<bool(size_t, size_t)> originalFn, size_t subpart, size_t subpartCount);
+
+
+ /*!
+ Split a single progress function into subparts.
+ This function takes the original progress function and returns a new function whose signature
+ is the same but whose output is shortened to correspond to the specified subparts.
+
+ The length of a subpart is proportional to the sum of all the weights.
+ E.g. If subpart = 1 and subpartWeights = { 0.25, 0.5, 0.25 }, this will return a function that calls
+ originalFn and maps its progress to the range [0.25, 0.75]
+
+ Internally this works by calling originalFn with total = 1000000 and doing math on the current value
+
+ \param originalFn Original progress function (usually updates a UI)
+ \param subpart Index of subpart whose function to return, from 0 to (subpartWeights.size() - 1)
+ \param subpartWeights Weights of subparts, described above
+ \return A function that will call originalFn() within a modified progress region
+ */
+ std::function<bool(size_t, size_t)> SplitProgress(std::function<bool(size_t, size_t)> originalFn, size_t subpart, std::vector<double> subpartWeights);
+
std::string GetUniqueIdentifierString();
std::map<std::string, uint64_t> GetMemoryUsageInfo();
@@ -763,6 +799,9 @@ __attribute__ ((format (printf, 1, 2)))
uint8_t& operator[](size_t offset);
const uint8_t& operator[](size_t offset) const;
+ bool operator==(const DataBuffer& other) const;
+ bool operator!=(const DataBuffer& other) const;
+
std::string ToEscapedString() const;
static DataBuffer FromEscapedString(const std::string& src);
std::string ToBase64() const;
@@ -819,6 +858,89 @@ __attribute__ ((format (printf, 1, 2)))
};
struct InstructionTextToken;
+ struct UndoEntry;
+
+ struct DatabaseException: std::runtime_error
+ {
+ DatabaseException(const std::string& desc): std::runtime_error(desc.c_str()) {}
+ };
+
+ class KeyValueStore: public CoreRefCountObject<BNKeyValueStore, BNNewKeyValueStoreReference, BNFreeKeyValueStore>
+ {
+ public:
+ KeyValueStore();
+ KeyValueStore(const DataBuffer& buffer);
+ KeyValueStore(BNKeyValueStore* store);
+
+ std::vector<std::string> GetKeys() const;
+
+ bool HasValue(const std::string& name) const;
+ Json::Value GetValue(const std::string& name) const;
+ DataBuffer GetBuffer(const std::string& name) const;
+ void SetValue(const std::string& name, const Json::Value& value);
+ void SetBuffer(const std::string& name, const DataBuffer& value);
+
+ DataBuffer GetSerializedData() const;
+
+ void BeginNamespace(const std::string& name);
+ void EndNamespace();
+
+ bool IsEmpty() const;
+ size_t ValueSize() const;
+ size_t DataSize() const;
+ size_t ValueStorageSize() const;
+ size_t NamespaceSize() const;
+ };
+
+ class Database;
+
+ class Snapshot: public CoreRefCountObject<BNSnapshot, BNNewSnapshotReference, BNFreeSnapshot>
+ {
+ public:
+ Snapshot(BNSnapshot* snapshot);
+
+ Ref<Database> GetDatabase();
+ int64_t GetId();
+ std::string GetName();
+ bool IsAutoSave();
+ Ref<Snapshot> GetFirstParent();
+ std::vector<Ref<Snapshot>> GetParents();
+ std::vector<Ref<Snapshot>> GetChildren();
+ DataBuffer GetFileContents();
+ DataBuffer GetFileContentsHash();
+ std::vector<UndoEntry> GetUndoEntries();
+ std::vector<UndoEntry> GetUndoEntries(const std::function<void(size_t, size_t)>& progress);
+ Ref<KeyValueStore> ReadData();
+ Ref<KeyValueStore> ReadData(const std::function<void(size_t, size_t)>& progress);
+ bool HasAncestor(Ref<Snapshot> other);
+ };
+
+ class FileMetadata;
+
+ class Database: public CoreRefCountObject<BNDatabase, BNNewDatabaseReference, BNFreeDatabase>
+ {
+ public:
+ Database(BNDatabase* database);
+
+ Ref<Snapshot> GetSnapshot(int64_t id);
+ std::vector<Ref<Snapshot>> GetSnapshots();
+ void SetCurrentSnapshot(int64_t id);
+ Ref<Snapshot> GetCurrentSnapshot();
+ int64_t WriteSnapshotData(std::vector<int64_t> parents, Ref<BinaryView> file, const std::string& name, const Ref<KeyValueStore>& data, bool autoSave, const std::function<void(size_t, size_t)>& progress);
+ void RemoveSnapshot(int64_t id);
+
+ std::vector<std::string> GetGlobalKeys() const;
+ bool HasGlobal(const std::string& key) const;
+ Json::Value ReadGlobal(const std::string& key) const;
+ void WriteGlobal(const std::string& key, const Json::Value& val);
+ DataBuffer ReadGlobalData(const std::string& key) const;
+ void WriteGlobalData(const std::string& key, const DataBuffer& val);
+
+ Ref<FileMetadata> GetFile();
+
+ Ref<KeyValueStore> ReadAnalysisCache() const;
+ void WriteAnalysisCache(Ref<KeyValueStore> val);
+ };
struct UndoAction
{
@@ -893,6 +1015,11 @@ __attribute__ ((format (printf, 1, 2)))
bool SaveAutoSnapshot(BinaryView* data, Ref<SaveSettings> settings);
bool SaveAutoSnapshot(BinaryView* data,
const std::function<void(size_t progress, size_t total)>& progressCallback, Ref<SaveSettings> settings);
+ void GetSnapshotData(Ref<KeyValueStore> data, Ref<KeyValueStore> cache,
+ const std::function<void(size_t, size_t)>& progress);
+ void ApplySnapshotData(BinaryView* file, Ref<KeyValueStore> data, Ref<KeyValueStore> cache,
+ const std::function<void(size_t, size_t)>& progress, bool openForConfiguration = false, bool restoreRawView = true);
+ Ref<Database> GetDatabase();
bool Rebase(BinaryView* data, uint64_t address);
bool Rebase(BinaryView* data, uint64_t address, const std::function<void(size_t progress, size_t total)>& progressCallback);
@@ -908,6 +1035,7 @@ __attribute__ ((format (printf, 1, 2)))
std::vector<Ref<User>> GetUsers();
std::vector<UndoEntry> GetUndoEntries();
+ void ClearUndoEntries();
bool OpenProject();
void CloseProject();
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 8af593c5..35b26d2a 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -156,6 +156,9 @@ extern "C"
struct BNBinaryViewType;
struct BNBinaryReader;
struct BNBinaryWriter;
+ struct BNKeyValueStore;
+ struct BNSnapshot;
+ struct BNDatabase;
struct BNFileMetadata;
struct BNTransform;
struct BNArchitecture;
@@ -2767,6 +2770,69 @@ __attribute__ ((format (printf, 1, 2)))
BINARYNINJACOREAPI bool BNSaveAutoSnapshot(BNBinaryView* data, BNSaveSettings* settings);
BINARYNINJACOREAPI bool BNSaveAutoSnapshotWithProgress(BNBinaryView* data, void* ctxt,
void (*progress)(void* ctxt, size_t progress, size_t total), BNSaveSettings* settings);
+ BINARYNINJACOREAPI void BNGetSnapshotData(BNFileMetadata* file, BNKeyValueStore* data, BNKeyValueStore* cache, void* ctxt, void (*progress)(void* ctxt, size_t current, size_t total));
+ BINARYNINJACOREAPI void BNApplySnapshotData(BNFileMetadata* file, BNBinaryView* view, BNKeyValueStore* data, BNKeyValueStore* cache, void* ctxt, void (*progress)(void* ctxt, size_t current, size_t total), bool openForConfiguration, bool restoreRawView);
+ BINARYNINJACOREAPI BNDatabase* BNGetFileMetadataDatabase(BNFileMetadata* file);
+
+ // Key value store
+ BINARYNINJACOREAPI BNKeyValueStore* BNCreateKeyValueStore(void);
+ BINARYNINJACOREAPI BNKeyValueStore* BNCreateKeyValueStoreFromDataBuffer(BNDataBuffer* buffer);
+ BINARYNINJACOREAPI BNKeyValueStore* BNNewKeyValueStoreReference(BNKeyValueStore* store);
+ BINARYNINJACOREAPI void BNFreeKeyValueStore(BNKeyValueStore* store);
+
+ BINARYNINJACOREAPI char** BNGetKeyValueStoreKeys(BNKeyValueStore* store, size_t* count);
+ BINARYNINJACOREAPI bool BNKeyValueStoreHasValue(BNKeyValueStore* store, const char* name);
+ BINARYNINJACOREAPI char* BNGetKeyValueStoreValue(BNKeyValueStore* store, const char* name);
+ BINARYNINJACOREAPI BNDataBuffer* BNGetKeyValueStoreBuffer(BNKeyValueStore* store, const char* name);
+ BINARYNINJACOREAPI bool BNSetKeyValueStoreValue(BNKeyValueStore* store, const char* name, const char* value);
+ BINARYNINJACOREAPI bool BNSetKeyValueStoreBuffer(BNKeyValueStore* store, const char* name, const BNDataBuffer* value);
+ BINARYNINJACOREAPI BNDataBuffer* BNGetKeyValueStoreSerializedData(BNKeyValueStore* store);
+ BINARYNINJACOREAPI void BNBeginKeyValueStoreNamespace(BNKeyValueStore* store, const char* name);
+ BINARYNINJACOREAPI void BNEndKeyValueStoreNamespace(BNKeyValueStore* store);
+ BINARYNINJACOREAPI bool BNIsKeyValueStoreEmpty(BNKeyValueStore* store);
+ BINARYNINJACOREAPI size_t BNGetKeyValueStoreValueSize(BNKeyValueStore* store);
+ BINARYNINJACOREAPI size_t BNGetKeyValueStoreDataSize(BNKeyValueStore* store);
+ BINARYNINJACOREAPI size_t BNGetKeyValueStoreValueStorageSize(BNKeyValueStore* store);
+ BINARYNINJACOREAPI size_t BNGetKeyValueStoreNamespaceSize(BNKeyValueStore* store);
+
+ // Database object
+ BINARYNINJACOREAPI BNDatabase* BNNewDatabaseReference(BNDatabase* database);
+ BINARYNINJACOREAPI void BNFreeDatabase(BNDatabase* database);
+ BINARYNINJACOREAPI void BNSetDatabaseCurrentSnapshot(BNDatabase* database, int64_t id);
+ BINARYNINJACOREAPI BNSnapshot* BNGetDatabaseCurrentSnapshot(BNDatabase* database);
+ BINARYNINJACOREAPI BNSnapshot** BNGetDatabaseSnapshots(BNDatabase* database, size_t* count);
+ BINARYNINJACOREAPI BNSnapshot* BNGetDatabaseSnapshot(BNDatabase* database, int64_t id);
+ BINARYNINJACOREAPI int64_t BNWriteDatabaseSnapshotData(BNDatabase* database, int64_t* parents, size_t parentCount, BNBinaryView* file, const char* name, BNKeyValueStore* data, bool autoSave, void* ctxt, void(*progress)(void*, size_t, size_t));
+ BINARYNINJACOREAPI bool BNRemoveDatabaseSnapshot(BNDatabase* database, int64_t id);
+ BINARYNINJACOREAPI char** BNGetDatabaseGlobalKeys(BNDatabase* database, size_t* count);
+ BINARYNINJACOREAPI int BNDatabaseHasGlobal(BNDatabase* database, const char* key);
+ BINARYNINJACOREAPI char* BNReadDatabaseGlobal(BNDatabase* database, const char* key);
+ BINARYNINJACOREAPI bool BNWriteDatabaseGlobal(BNDatabase* database, const char* key, const char* val);
+ BINARYNINJACOREAPI BNDataBuffer* BNReadDatabaseGlobalData(BNDatabase* database, const char* key);
+ BINARYNINJACOREAPI bool BNWriteDatabaseGlobalData(BNDatabase* database, const char* key, BNDataBuffer* val);
+ BINARYNINJACOREAPI BNFileMetadata* BNGetDatabaseFile(BNDatabase* database);
+ BINARYNINJACOREAPI BNKeyValueStore* BNReadDatabaseAnalysisCache(BNDatabase* database);
+ BINARYNINJACOREAPI bool BNWriteDatabaseAnalysisCache(BNDatabase* database, BNKeyValueStore* val);
+
+ // Database snapshots
+ BINARYNINJACOREAPI BNSnapshot* BNNewSnapshotReference(BNSnapshot* snapshot);
+ BINARYNINJACOREAPI void BNFreeSnapshot(BNSnapshot* snapshot);
+ BINARYNINJACOREAPI void BNFreeSnapshotList(BNSnapshot** snapshots, size_t count);
+ BINARYNINJACOREAPI BNDatabase* BNGetSnapshotDatabase(BNSnapshot* snapshot);
+ BINARYNINJACOREAPI int64_t BNGetSnapshotId(BNSnapshot* snapshot);
+ BINARYNINJACOREAPI BNSnapshot* BNGetSnapshotFirstParent(BNSnapshot* snapshot);
+ BINARYNINJACOREAPI BNSnapshot** BNGetSnapshotParents(BNSnapshot* snapshot, size_t* count);
+ BINARYNINJACOREAPI BNSnapshot** BNGetSnapshotChildren(BNSnapshot* snapshot, size_t* count);
+ BINARYNINJACOREAPI char* BNGetSnapshotName(BNSnapshot* snapshot);
+ BINARYNINJACOREAPI bool BNIsSnapshotAutoSave(BNSnapshot* snapshot);
+ BINARYNINJACOREAPI BNDataBuffer* BNGetSnapshotFileContents(BNSnapshot* snapshot);
+ BINARYNINJACOREAPI BNDataBuffer* BNGetSnapshotFileContentsHash(BNSnapshot* snapshot);
+ BINARYNINJACOREAPI BNKeyValueStore* BNReadSnapshotData(BNSnapshot* snapshot);
+ BINARYNINJACOREAPI BNKeyValueStore* BNReadSnapshotDataWithProgress(BNSnapshot* snapshot, void* ctxt, void (*progress)(void* ctxt, size_t progress, size_t total));
+ BINARYNINJACOREAPI BNUndoEntry* BNGetSnapshotUndoEntries(BNSnapshot* snapshot, size_t* count);
+ BINARYNINJACOREAPI BNUndoEntry* BNGetSnapshotUndoEntriesWithProgress(BNSnapshot* snapshot, void* ctxt, void (*progress)(void* ctxt, size_t progress, size_t total), size_t* count);
+ BINARYNINJACOREAPI bool BNSnapshotHasAncestor(BNSnapshot* snapshot, BNSnapshot* other);
+
BINARYNINJACOREAPI bool BNRebase(BNBinaryView* data, uint64_t address);
BINARYNINJACOREAPI bool BNRebaseWithProgress(BNBinaryView* data, uint64_t address, void* ctxt, void (*progress)(void* ctxt, size_t progress, size_t total));
@@ -2788,6 +2854,7 @@ __attribute__ ((format (printf, 1, 2)))
BINARYNINJACOREAPI BNUndoEntry* BNGetUndoEntries(BNFileMetadata* file, size_t* count);
BINARYNINJACOREAPI void BNFreeUndoEntries(BNUndoEntry* entries, size_t count);
+ BINARYNINJACOREAPI void BNClearUndoEntries(BNFileMetadata* file);
BINARYNINJACOREAPI BNUser* BNNewUserReference(BNUser* user);
BINARYNINJACOREAPI void BNFreeUser(BNUser* user);
diff --git a/database.cpp b/database.cpp
new file mode 100644
index 00000000..ee7dd289
--- /dev/null
+++ b/database.cpp
@@ -0,0 +1,511 @@
+// Copyright (c) 2015-2020 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 <cstring>
+#include "binaryninjaapi.h"
+
+using namespace BinaryNinja;
+using namespace Json;
+using namespace std;
+
+
+struct ProgressContext
+{
+ std::function<void(size_t, size_t)> callback;
+};
+
+
+void ProgressCallback(void* ctxt, size_t current, size_t total)
+{
+ ProgressContext* pctxt = reinterpret_cast<ProgressContext*>(ctxt);
+ pctxt->callback(current, total);
+}
+
+
+KeyValueStore::KeyValueStore()
+{
+ m_object = BNCreateKeyValueStore();
+}
+
+
+KeyValueStore::KeyValueStore(const DataBuffer& buffer)
+{
+ m_object = BNCreateKeyValueStoreFromDataBuffer(buffer.GetBufferObject());
+}
+
+
+KeyValueStore::KeyValueStore(BNKeyValueStore* store)
+{
+ m_object = store;
+}
+
+
+std::vector<std::string> KeyValueStore::GetKeys() const
+{
+ size_t count;
+ char** keys = BNGetKeyValueStoreKeys(m_object, &count);
+
+ std::vector<std::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<Json::CharReader> reader(Json::CharReaderBuilder().newCharReader());
+ std::string errors;
+ if (!reader->parse(static_cast<const char*>(value.GetData()),
+ static_cast<const char*>(value.GetDataAt(value.GetLength())),
+ &json, &errors))
+ {
+ throw DatabaseException(errors);
+ }
+ return json;
+}
+
+
+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<Database> 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;
+}
+
+
+bool Snapshot::IsAutoSave()
+{
+ return BNIsSnapshotAutoSave(m_object);
+}
+
+
+Ref<Snapshot> Snapshot::GetFirstParent()
+{
+ BNSnapshot* snap = BNGetSnapshotFirstParent(m_object);
+ if (snap == nullptr)
+ return nullptr;
+ return new Snapshot(snap);
+}
+
+
+vector<Ref<Snapshot>> Snapshot::GetParents()
+{
+ size_t count;
+ BNSnapshot** parents = BNGetSnapshotParents(m_object, &count);
+ vector<Ref<Snapshot>> result;
+ for (size_t i = 0; i < count; i++)
+ {
+ result.push_back(new Snapshot(BNNewSnapshotReference(parents[i])));
+ }
+ BNFreeSnapshotList(parents, count);
+ return result;
+}
+
+
+vector<Ref<Snapshot>> Snapshot::GetChildren()
+{
+ size_t count;
+ BNSnapshot** children = BNGetSnapshotChildren(m_object, &count);
+ vector<Ref<Snapshot>> result;
+ 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);
+}
+
+
+vector<UndoEntry> Snapshot::GetUndoEntries()
+{
+ return GetUndoEntries([](size_t, size_t){});
+}
+
+
+vector<UndoEntry> Snapshot::GetUndoEntries(const std::function<void(size_t, size_t)>& progress)
+{
+ ProgressContext pctxt;
+ pctxt.callback = progress;
+
+ size_t numEntries;
+ BNUndoEntry* entries = BNGetSnapshotUndoEntriesWithProgress(m_object, &pctxt, ProgressCallback, &numEntries);
+ if (entries == nullptr)
+ {
+ throw DatabaseException("BNGetSnapshotUndoEntries");
+ }
+
+ vector<UndoEntry> result;
+ result.reserve(numEntries);
+ for (size_t i = 0; i < numEntries; i++)
+ {
+ UndoEntry temp;
+ temp.timestamp = entries[i].timestamp;
+ temp.hash = entries[i].hash;
+ temp.user = new User(BNNewUserReference(entries[i].user));
+ size_t actionCount = entries[i].actionCount;
+ for (size_t actionIndex = 0; actionIndex < actionCount; actionIndex++)
+ {
+ temp.actions.emplace_back(entries[i].actions[actionIndex]);
+ }
+ result.push_back(temp);
+ }
+
+ BNFreeUndoEntries(entries, numEntries);
+ return result;
+}
+
+
+Ref<KeyValueStore> Snapshot::ReadData()
+{
+ return ReadData([](size_t, size_t){});
+}
+
+
+Ref<KeyValueStore> Snapshot::ReadData(const std::function<void(size_t, size_t)>& 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::HasAncestor(Ref<Snapshot> other)
+{
+ return BNSnapshotHasAncestor(m_object, other->GetObject());
+}
+
+
+Database::Database(BNDatabase* database)
+{
+ m_object = database;
+}
+
+
+Ref<Snapshot> Database::GetSnapshot(int64_t id)
+{
+ BNSnapshot* snap = BNGetDatabaseSnapshot(m_object, id);
+ if (snap == nullptr)
+ return nullptr;
+ return new Snapshot(snap);
+}
+
+vector<Ref<Snapshot>> Database::GetSnapshots()
+{
+ size_t count;
+ BNSnapshot** snapshots = BNGetDatabaseSnapshots(m_object, &count);
+ vector<Ref<Snapshot>> result;
+ 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<Snapshot> Database::GetCurrentSnapshot()
+{
+ BNSnapshot* snap = BNGetDatabaseCurrentSnapshot(m_object);
+ if (snap == nullptr)
+ return nullptr;
+ return new Snapshot(snap);
+}
+
+
+int64_t Database::WriteSnapshotData(std::vector<int64_t> parents, Ref<BinaryView> file, const std::string& name, const Ref<KeyValueStore>& data, bool autoSave, const std::function<void(size_t, size_t)>& 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::RemoveSnapshot(int64_t id)
+{
+ if (!BNRemoveDatabaseSnapshot(m_object, id))
+ {
+ throw DatabaseException("BNRemoveDatabaseSnapshot");
+ }
+}
+
+
+std::vector<std::string> Database::GetGlobalKeys() const
+{
+ size_t count;
+ char** value = BNGetDatabaseGlobalKeys(m_object, &count);
+ if (value == nullptr)
+ {
+ throw DatabaseException("BNDatabaseHasGlobal");
+ }
+
+ std::vector<std::string> result;
+ 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<Json::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<FileMetadata> Database::GetFile()
+{
+ return new FileMetadata(BNGetDatabaseFile(m_object));
+}
+
+
+Ref<KeyValueStore> Database::ReadAnalysisCache() const
+{
+ BNKeyValueStore* store = BNReadDatabaseAnalysisCache(m_object);
+ if (store == nullptr)
+ {
+ throw DatabaseException("BNReadDatabaseAnalysisCache");
+ }
+ return new KeyValueStore(store);
+}
+
+
+void Database::WriteAnalysisCache(Ref<KeyValueStore> val)
+{
+ if (!BNWriteDatabaseAnalysisCache(m_object, val->GetObject()))
+ {
+ throw DatabaseException("BNWriteDatabaseAnalysisCache");
+ }
+}
diff --git a/databuffer.cpp b/databuffer.cpp
index 001ef8e9..cf4a608a 100644
--- a/databuffer.cpp
+++ b/databuffer.cpp
@@ -89,6 +89,28 @@ DataBuffer& DataBuffer::operator=(DataBuffer&& buf)
return *this;
}
+bool DataBuffer::operator==(const DataBuffer& other) const
+{
+ uint8_t* data = (uint8_t*)GetData();
+ uint8_t* otherData = (uint8_t*)other.GetData();
+ if (GetLength() != other.GetLength())
+ return false;
+ if (data == otherData)
+ return true;
+
+ for (size_t i = 0; i < GetLength(); i++)
+ {
+ if (data[i] != otherData[i])
+ return false;
+ }
+ return true;
+}
+
+bool DataBuffer::operator!=(const DataBuffer& other) const
+{
+ return !(*this == other);
+}
+
void* DataBuffer::GetData()
{
return BNGetDataBufferContents(m_buffer);
diff --git a/filemetadata.cpp b/filemetadata.cpp
index 00711b57..4ca10e64 100644
--- a/filemetadata.cpp
+++ b/filemetadata.cpp
@@ -223,6 +223,33 @@ bool FileMetadata::SaveAutoSnapshot(BinaryView* data,
}
+void FileMetadata::GetSnapshotData(Ref<KeyValueStore> data, Ref<KeyValueStore> cache,
+ const std::function<void(size_t, size_t)>& progress)
+{
+ DatabaseProgressCallbackContext cb;
+ cb.func = progress;
+ BNGetSnapshotData(GetObject(), data->GetObject(), cache->GetObject(), &cb, DatabaseProgressCallback);
+}
+
+
+void FileMetadata::ApplySnapshotData(BinaryView* file, Ref<KeyValueStore> data, Ref<KeyValueStore> cache,
+ const std::function<void(size_t, size_t)>& progress, bool openForConfiguration, bool restoreRawView)
+{
+ DatabaseProgressCallbackContext cb;
+ cb.func = progress;
+ BNApplySnapshotData(GetObject(), file->GetObject(), data->GetObject(), cache->GetObject(), &cb, DatabaseProgressCallback, openForConfiguration, restoreRawView);
+}
+
+
+Ref<Database> FileMetadata::GetDatabase()
+{
+ BNDatabase* db = BNGetFileMetadataDatabase(m_object);
+ if (db == nullptr)
+ return nullptr;
+ return new Database(db);
+}
+
+
bool FileMetadata::Rebase(BinaryView* data, uint64_t address)
{
return BNRebase(data->GetObject(), address);
@@ -320,6 +347,12 @@ vector<UndoEntry> FileMetadata::GetUndoEntries()
}
+void FileMetadata::ClearUndoEntries()
+{
+ BNClearUndoEntries(m_object);
+}
+
+
bool FileMetadata::OpenProject()
{
return BNOpenProject(m_object);
diff --git a/ui/uitypes.h b/ui/uitypes.h
index 921ee8fe..7fd92298 100644
--- a/ui/uitypes.h
+++ b/ui/uitypes.h
@@ -65,7 +65,9 @@ typedef BinaryNinja::Ref<BinaryNinja::BasicBlock> BasicBlockRef;
typedef BinaryNinja::Ref<BinaryNinja::BinaryData> BinaryDataRef;
typedef BinaryNinja::Ref<BinaryNinja::BinaryView> BinaryViewRef;
typedef BinaryNinja::Ref<BinaryNinja::BinaryViewType> BinaryViewTypeRef;
+typedef BinaryNinja::Ref<BinaryNinja::Database> DatabaseRef;
typedef BinaryNinja::Ref<BinaryNinja::DisassemblySettings> DisassemblySettingsRef;
+typedef BinaryNinja::Ref<BinaryNinja::DownloadInstance> DownloadInstanceRef;
typedef BinaryNinja::Ref<BinaryNinja::DownloadProvider> DownloadProviderRef;
typedef BinaryNinja::Ref<BinaryNinja::Enumeration> EnumerationRef;
typedef BinaryNinja::Ref<BinaryNinja::FileMetadata> FileMetadataRef;
@@ -73,6 +75,7 @@ typedef BinaryNinja::Ref<BinaryNinja::FlowGraph> FlowGraphRef;
typedef BinaryNinja::Ref<BinaryNinja::FlowGraphLayoutRequest> FlowGraphLayoutRequestRef;
typedef BinaryNinja::Ref<BinaryNinja::FlowGraphNode> FlowGraphNodeRef;
typedef BinaryNinja::Ref<BinaryNinja::Function> FunctionRef;
+typedef BinaryNinja::Ref<BinaryNinja::KeyValueStore> KeyValueStoreRef;
typedef BinaryNinja::Ref<BinaryNinja::LowLevelILFunction> LowLevelILFunctionRef;
typedef BinaryNinja::Ref<BinaryNinja::MainThreadAction> MainThreadActionRef;
typedef BinaryNinja::Ref<BinaryNinja::MediumLevelILFunction> MediumLevelILFunctionRef;
@@ -85,6 +88,7 @@ typedef BinaryNinja::Ref<BinaryNinja::ScriptingProvider> ScriptingProviderRef;
typedef BinaryNinja::Ref<BinaryNinja::Section> SectionRef;
typedef BinaryNinja::Ref<BinaryNinja::Segment> SegmentRef;
typedef BinaryNinja::Ref<BinaryNinja::Settings> SettingsRef;
+typedef BinaryNinja::Ref<BinaryNinja::Snapshot> SnapshotRef;
typedef BinaryNinja::Ref<BinaryNinja::Structure> StructureRef;
typedef BinaryNinja::Ref<BinaryNinja::Symbol> SymbolRef;
typedef BinaryNinja::Ref<BinaryNinja::Tag> TagRef;