summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.cpp25
-rw-r--r--binaryninjaapi.h20
-rw-r--r--binaryninjacore.h23
-rw-r--r--pluginmanager.cpp33
-rw-r--r--python/pluginmanager.py92
-rw-r--r--rust/src/repository.rs2
-rw-r--r--rust/src/repository/plugin.rs91
7 files changed, 248 insertions, 38 deletions
diff --git a/binaryninjaapi.cpp b/binaryninjaapi.cpp
index 58a4c0cd..34a86d41 100644
--- a/binaryninjaapi.cpp
+++ b/binaryninjaapi.cpp
@@ -207,31 +207,30 @@ string BinaryNinja::GetVersionString()
}
-VersionInfo BinaryNinja::GetVersionInfo()
+static VersionInfo VersionInfoFromCoreStruct(const BNVersionInfo& result)
{
- BNVersionInfo result = BNGetVersionInfo();
VersionInfo info;
info.major = result.major;
info.minor = result.minor;
info.build = result.build;
- info.channel = "";
- if (result.channel)
- info.channel = result.channel;
+ info.channel = result.channel ? result.channel : "";
+ return info;
+}
+
+
+VersionInfo BinaryNinja::GetVersionInfo()
+{
+ BNVersionInfo result = BNGetVersionInfo();
+ VersionInfo info = VersionInfoFromCoreStruct(result);
BNFreeString(result.channel);
return info;
}
-VersionInfo ParseVersionString(const string &version)
+VersionInfo BinaryNinja::ParseVersionString(const string &version)
{
BNVersionInfo result = BNParseVersionString(version.c_str());
- VersionInfo info;
- info.major = result.major;
- info.minor = result.minor;
- info.build = result.build;
- info.channel = "";
- if (result.channel)
- info.channel = result.channel;
+ VersionInfo info = VersionInfoFromCoreStruct(result);
BNFreeString(result.channel);
return info;
}
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 57f896dd..fe57d92d 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -1962,8 +1962,16 @@ namespace BinaryNinja {
{
char* smallerChan = BNAllocString(channel.c_str());
char* largerChan = BNAllocString(other.channel.c_str());
- BNVersionInfo smaller = { major, minor, build, smallerChan };
- BNVersionInfo larger = { other.major, other.minor, other.build, largerChan };
+ BNVersionInfo smaller = {};
+ smaller.major = major;
+ smaller.minor = minor;
+ smaller.build = build;
+ smaller.channel = smallerChan;
+ BNVersionInfo larger = {};
+ larger.major = other.major;
+ larger.minor = other.minor;
+ larger.build = other.build;
+ larger.channel = largerChan;
bool result = BNVersionLessThan(smaller, larger);
BNFreeString(smallerChan);
BNFreeString(largerChan);
@@ -19145,6 +19153,13 @@ namespace BinaryNinja {
struct ExtensionVersion
{
+ struct PlatformInfo
+ {
+ std::string name;
+ std::string downloadUrl;
+ std::string untrackedDownloadUrl;
+ };
+
std::string id;
std::string version;
@@ -19152,6 +19167,7 @@ namespace BinaryNinja {
std::string changelog;
uint64_t minimumClientVersion;
+ std::vector<PlatformInfo> platforms;
std::string created;
};
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 879b7e1e..283524c8 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -354,6 +354,20 @@ extern "C"
typedef struct BNStringRecognizer BNStringRecognizer;
typedef struct BNCustomStringType BNCustomStringType;
+ typedef struct BNVersionInfo {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t build;
+ char* channel;
+ } BNVersionInfo;
+
+ typedef struct BNPluginVersionPlatform
+ {
+ char* name;
+ char* downloadUrl;
+ char* untrackedDownloadUrl;
+ } BNPluginVersionPlatform;
+
typedef struct BNPluginVersion
{
char* id;
@@ -362,6 +376,8 @@ extern "C"
char* changelog;
uint64_t minimumClientVersion;
+ BNPluginVersionPlatform* platforms;
+ size_t platformCount;
char* created;
} BNPluginVersion;
@@ -2743,13 +2759,6 @@ extern "C"
char* latestVersion;
} BNUpdateChannel;
- typedef struct BNVersionInfo {
- uint32_t major;
- uint32_t minor;
- uint32_t build;
- char* channel;
- } BNVersionInfo;
-
typedef struct BNChangelogEntry {
BNVersionInfo version;
char* notes;
diff --git a/pluginmanager.cpp b/pluginmanager.cpp
index 774e43d3..9b24a464 100644
--- a/pluginmanager.cpp
+++ b/pluginmanager.cpp
@@ -70,14 +70,29 @@ string Extension::GetDescription() const
RETURN_STRING(BNPluginGetDescription(m_object));
}
-VersionInfo Extension::GetMinimumVersionInfo() const
+static VersionInfo ConvertVersionInfo(const BNVersionInfo& coreInfo)
{
- auto coreInfo = BNPluginGetMinimumVersionInfo(m_object);
VersionInfo result;
result.major = coreInfo.major;
result.minor = coreInfo.minor;
result.build = coreInfo.build;
- result.channel = coreInfo.channel;
+ result.channel = coreInfo.channel ? coreInfo.channel : "";
+ return result;
+}
+
+static ExtensionVersion::PlatformInfo ConvertVersionPlatform(const BNPluginVersionPlatform& corePlatform)
+{
+ ExtensionVersion::PlatformInfo result;
+ result.name = corePlatform.name ? corePlatform.name : "";
+ result.downloadUrl = corePlatform.downloadUrl ? corePlatform.downloadUrl : "";
+ result.untrackedDownloadUrl = corePlatform.untrackedDownloadUrl ? corePlatform.untrackedDownloadUrl : "";
+ return result;
+}
+
+VersionInfo Extension::GetMinimumVersionInfo() const
+{
+ auto coreInfo = BNPluginGetMinimumVersionInfo(m_object);
+ VersionInfo result = ConvertVersionInfo(coreInfo);
BNFreeString(coreInfo.channel);
return result;
}
@@ -85,11 +100,7 @@ VersionInfo Extension::GetMinimumVersionInfo() const
VersionInfo Extension::GetMaximumVersionInfo() const
{
auto coreInfo = BNPluginGetMaximumVersionInfo(m_object);
- VersionInfo result;
- result.major = coreInfo.major;
- result.minor = coreInfo.minor;
- result.build = coreInfo.build;
- result.channel = coreInfo.channel;
+ VersionInfo result = ConvertVersionInfo(coreInfo);
BNFreeString(coreInfo.channel);
return result;
}
@@ -146,6 +157,9 @@ std::vector<ExtensionVersion> Extension::GetVersions() const
version.longDescription = versionsPtr[i].longDescription ? versionsPtr[i].longDescription : "";
version.changelog = versionsPtr[i].changelog ? versionsPtr[i].changelog : "";
version.minimumClientVersion = versionsPtr[i].minimumClientVersion;
+ version.platforms.reserve(versionsPtr[i].platformCount);
+ for (size_t j = 0; j < versionsPtr[i].platformCount; j++)
+ version.platforms.push_back(ConvertVersionPlatform(versionsPtr[i].platforms[j]));
version.created = versionsPtr[i].created ? versionsPtr[i].created : "";
versions.push_back(version);
}
@@ -163,6 +177,9 @@ ExtensionVersion Extension::GetCurrentVersion() const
version.longDescription = currentVersion.longDescription ? currentVersion.longDescription : "";
version.changelog = currentVersion.changelog ? currentVersion.changelog : "";
version.minimumClientVersion = currentVersion.minimumClientVersion;
+ version.platforms.reserve(currentVersion.platformCount);
+ for (size_t i = 0; i < currentVersion.platformCount; i++)
+ version.platforms.push_back(ConvertVersionPlatform(currentVersion.platforms[i]));
version.created = currentVersion.created ? currentVersion.created : "";
BNPluginFreeVersion(currentVersion);
return version;
diff --git a/python/pluginmanager.py b/python/pluginmanager.py
index 5e32a79f..55315d12 100644
--- a/python/pluginmanager.py
+++ b/python/pluginmanager.py
@@ -20,6 +20,7 @@
import ctypes
import json
+from dataclasses import dataclass
from datetime import datetime, date
from typing import List, Dict, Optional
@@ -29,6 +30,24 @@ from . import deprecation
from .enums import PluginType
+@dataclass(frozen=True)
+class ExtensionVersionPlatform:
+ name: str
+ download_url: str
+ untracked_download_url: str
+
+
+@dataclass(frozen=True)
+class ExtensionVersion:
+ id: str
+ version: str
+ long_description: str
+ changelog: str
+ minimum_client_version: int
+ platforms: List[ExtensionVersionPlatform]
+ created: str
+
+
class Extension:
"""
``Extension`` is mostly read-only, however you can install/uninstall enable/disable plugins. Extensions are
@@ -152,13 +171,23 @@ class Extension:
def minimum_version_info(self) -> 'binaryninja.CoreVersionInfo':
"""Minimum version info the plugin was tested on"""
core_version_info = core.BNPluginGetMinimumVersionInfo(self.handle)
- return binaryninja.CoreVersionInfo(core_version_info.major, core_version_info.minor, core_version_info.build)
+ return binaryninja.CoreVersionInfo(
+ core_version_info.major,
+ core_version_info.minor,
+ core_version_info.build,
+ core_version_info.channel or ""
+ )
@property
def maximum_version_info(self) -> 'binaryninja.CoreVersionInfo':
"""Maximum version info the plugin will support"""
core_version_info = core.BNPluginGetMaximumVersionInfo(self.handle)
- return binaryninja.CoreVersionInfo(core_version_info.major, core_version_info.minor, core_version_info.build)
+ return binaryninja.CoreVersionInfo(
+ core_version_info.major,
+ core_version_info.minor,
+ core_version_info.build,
+ core_version_info.channel or ""
+ )
@property
def name(self) -> str:
@@ -206,14 +235,65 @@ class Extension:
@deprecation.deprecated(deprecated_in="5.3", details='Use :py:attr:`current_version` in combination with :py:attr:`versions` instead.')
def version(self) -> Optional[str]:
"""String version of the plugin"""
+ return self.current_version.version
+
+ @property
+ def current_version(self) -> ExtensionVersion:
+ """Current version metadata for the plugin"""
version: core.BNPluginVersion = core.BNPluginGetCurrentVersion(self.handle)
try:
- version_string = version.versionString
- except AttributeError:
- version_string = ""
+ platforms = []
+ for i in range(version.platformCount):
+ platform = version.platforms[i]
+ platforms.append(ExtensionVersionPlatform(
+ name=platform.name or "",
+ download_url=platform.downloadUrl or "",
+ untracked_download_url=platform.untrackedDownloadUrl or ""
+ ))
+ return ExtensionVersion(
+ id=version.id or "",
+ version=version.versionString or "",
+ long_description=version.longDescription or "",
+ changelog=version.changelog or "",
+ minimum_client_version=version.minimumClientVersion,
+ platforms=platforms,
+ created=version.created or ""
+ )
finally:
core.BNPluginFreeVersion(version)
- return version_string
+
+ @property
+ def versions(self) -> List[ExtensionVersion]:
+ """Version metadata for all available plugin versions"""
+ result = []
+ count = ctypes.c_ulonglong(0)
+ versions = core.BNPluginGetVersions(self.handle, count)
+ try:
+ if versions is None:
+ return result
+ for i in range(count.value):
+ version = versions[i]
+ platforms = []
+ for j in range(version.platformCount):
+ platform = version.platforms[j]
+ platforms.append(ExtensionVersionPlatform(
+ name=platform.name or "",
+ download_url=platform.downloadUrl or "",
+ untracked_download_url=platform.untrackedDownloadUrl or ""
+ ))
+ result.append(ExtensionVersion(
+ id=version.id or "",
+ version=version.versionString or "",
+ long_description=version.longDescription or "",
+ changelog=version.changelog or "",
+ minimum_client_version=version.minimumClientVersion,
+ platforms=platforms,
+ created=version.created or ""
+ ))
+ return result
+ finally:
+ if versions is not None:
+ core.BNFreePluginVersions(versions, count.value)
@property
def install_platforms(self) -> List[str]:
diff --git a/rust/src/repository.rs b/rust/src/repository.rs
index 2f1ab267..18946eac 100644
--- a/rust/src/repository.rs
+++ b/rust/src/repository.rs
@@ -11,10 +11,10 @@ use std::ptr::NonNull;
use binaryninjacore_sys::*;
use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
-use crate::repository::plugin::Extension;
use crate::string::{BnString, IntoCStr};
pub use manager::RepositoryManager;
+pub use plugin::{Extension, ExtensionVersion, ExtensionVersionPlatform};
pub type PluginType = BNPluginType;
pub type PluginStatus = BNPluginStatus;
diff --git a/rust/src/repository/plugin.rs b/rust/src/repository/plugin.rs
index ba95c29c..ac7c9d20 100644
--- a/rust/src/repository/plugin.rs
+++ b/rust/src/repository/plugin.rs
@@ -1,12 +1,71 @@
use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
use crate::repository::{PluginStatus, PluginType};
-use crate::string::{BnString, IntoCStr};
+use crate::string::{raw_to_string, BnString, IntoCStr};
use crate::VersionInfo;
use binaryninjacore_sys::*;
use std::ffi::c_char;
use std::fmt::Debug;
use std::path::PathBuf;
use std::ptr::NonNull;
+use std::slice;
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct ExtensionVersionPlatform {
+ pub name: String,
+ pub download_url: String,
+ pub untracked_download_url: String,
+}
+
+impl ExtensionVersionPlatform {
+ pub(crate) fn from_raw(value: &BNPluginVersionPlatform) -> Self {
+ Self {
+ name: raw_to_string(value.name as *mut _).unwrap_or_default(),
+ download_url: raw_to_string(value.downloadUrl as *mut _).unwrap_or_default(),
+ untracked_download_url: raw_to_string(value.untrackedDownloadUrl as *mut _)
+ .unwrap_or_default(),
+ }
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct ExtensionVersion {
+ pub id: String,
+ pub version: String,
+ pub long_description: String,
+ pub changelog: String,
+ pub minimum_client_version: u64,
+ pub platforms: Vec<ExtensionVersionPlatform>,
+ pub created: String,
+}
+
+impl ExtensionVersion {
+ pub(crate) fn from_raw(value: &BNPluginVersion) -> Self {
+ let platforms = if value.platforms.is_null() || value.platformCount == 0 {
+ Vec::new()
+ } else {
+ unsafe { slice::from_raw_parts(value.platforms, value.platformCount) }
+ .iter()
+ .map(ExtensionVersionPlatform::from_raw)
+ .collect()
+ };
+
+ Self {
+ id: raw_to_string(value.id as *mut _).unwrap_or_default(),
+ version: raw_to_string(value.versionString as *mut _).unwrap_or_default(),
+ long_description: raw_to_string(value.longDescription as *mut _).unwrap_or_default(),
+ changelog: raw_to_string(value.changelog as *mut _).unwrap_or_default(),
+ minimum_client_version: value.minimumClientVersion,
+ platforms,
+ created: raw_to_string(value.created as *mut _).unwrap_or_default(),
+ }
+ }
+
+ pub(crate) fn from_owned_raw(value: BNPluginVersion) -> Self {
+ let owned = Self::from_raw(&value);
+ unsafe { BNPluginFreeVersion(value) };
+ owned
+ }
+}
#[repr(transparent)]
pub struct Extension {
@@ -56,6 +115,20 @@ impl Extension {
VersionInfo::from_owned_raw(result)
}
+ /// Metadata for all available versions of this plugin
+ pub fn versions(&self) -> Array<ExtensionVersion> {
+ let mut count = 0;
+ let result = unsafe { BNPluginGetVersions(self.handle.as_ptr(), &mut count) };
+ assert!(!result.is_null());
+ unsafe { Array::new(result, count, ()) }
+ }
+
+ /// Metadata for the currently selected version of this plugin
+ pub fn current_version(&self) -> ExtensionVersion {
+ let result = unsafe { BNPluginGetCurrentVersion(self.handle.as_ptr()) };
+ ExtensionVersion::from_owned_raw(result)
+ }
+
/// String plugin name
pub fn name(&self) -> String {
let result = unsafe { BNPluginGetName(self.handle.as_ptr()) };
@@ -274,3 +347,19 @@ unsafe impl CoreArrayProviderInner for Extension {
Guard::new(Self::from_raw(NonNull::new(*raw).unwrap()), context)
}
}
+
+impl CoreArrayProvider for ExtensionVersion {
+ type Raw = BNPluginVersion;
+ type Context = ();
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for ExtensionVersion {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreePluginVersions(raw, count)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
+ ExtensionVersion::from_raw(raw)
+ }
+}