summaryrefslogtreecommitdiff
path: root/database.cpp
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2020-09-14 17:15:37 -0400
committerGlenn Smith <glenn@vector35.com>2021-07-13 15:04:49 -0400
commitce08fff22e4bed3d977cfd662ed2a6d8caa82997 (patch)
tree9fed8c3070837f38099d13ff78a7577fbc4ac168 /database.cpp
parent10e668db4d76658882bee7b75d47063b054a730d (diff)
Database api
Co-Authored-By: Josh Ferrell <josh@vector35.com>
Diffstat (limited to 'database.cpp')
-rw-r--r--database.cpp511
1 files changed, 511 insertions, 0 deletions
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");
+ }
+}