binaryninja/repository/
plugin.rs1use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
2use crate::repository::{PluginStatus, PluginType};
3use crate::string::{raw_to_string, BnString, IntoCStr};
4use crate::VersionInfo;
5use binaryninjacore_sys::*;
6use std::ffi::c_char;
7use std::fmt::Debug;
8use std::path::PathBuf;
9use std::ptr::NonNull;
10use std::slice;
11
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct ExtensionVersionPlatform {
14 pub name: String,
15 pub download_url: String,
16 pub untracked_download_url: String,
17}
18
19impl ExtensionVersionPlatform {
20 pub(crate) fn from_raw(value: &BNPluginVersionPlatform) -> Self {
21 Self {
22 name: raw_to_string(value.name as *mut _).unwrap_or_default(),
23 download_url: raw_to_string(value.downloadUrl as *mut _).unwrap_or_default(),
24 untracked_download_url: raw_to_string(value.untrackedDownloadUrl as *mut _)
25 .unwrap_or_default(),
26 }
27 }
28}
29
30#[derive(Clone, Debug, PartialEq, Eq)]
31pub struct ExtensionVersion {
32 pub id: String,
33 pub version: String,
34 pub long_description: String,
35 pub changelog: String,
36 pub minimum_client_version: u64,
37 pub platforms: Vec<ExtensionVersionPlatform>,
38 pub created: String,
39}
40
41impl ExtensionVersion {
42 pub(crate) fn from_raw(value: &BNPluginVersion) -> Self {
43 let platforms = if value.platforms.is_null() || value.platformCount == 0 {
44 Vec::new()
45 } else {
46 unsafe { slice::from_raw_parts(value.platforms, value.platformCount) }
47 .iter()
48 .map(ExtensionVersionPlatform::from_raw)
49 .collect()
50 };
51
52 Self {
53 id: raw_to_string(value.id as *mut _).unwrap_or_default(),
54 version: raw_to_string(value.versionString as *mut _).unwrap_or_default(),
55 long_description: raw_to_string(value.longDescription as *mut _).unwrap_or_default(),
56 changelog: raw_to_string(value.changelog as *mut _).unwrap_or_default(),
57 minimum_client_version: value.minimumClientVersion,
58 platforms,
59 created: raw_to_string(value.created as *mut _).unwrap_or_default(),
60 }
61 }
62
63 pub(crate) fn from_owned_raw(value: BNPluginVersion) -> Self {
64 let owned = Self::from_raw(&value);
65 unsafe { BNPluginFreeVersion(value) };
66 owned
67 }
68}
69
70#[repr(transparent)]
71pub struct Extension {
72 handle: NonNull<BNPlugin>,
73}
74
75impl Extension {
76 pub(crate) unsafe fn from_raw(handle: NonNull<BNPlugin>) -> Self {
77 Self { handle }
78 }
79
80 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNPlugin>) -> Ref<Self> {
81 Ref::new(Self { handle })
82 }
83
84 pub fn apis(&self) -> Array<BnString> {
86 let mut count = 0;
87 let result = unsafe { BNPluginGetApis(self.handle.as_ptr(), &mut count) };
88 assert!(!result.is_null());
89 unsafe { Array::new(result, count, ()) }
90 }
91
92 pub fn author(&self) -> String {
94 let result = unsafe { BNPluginGetAuthor(self.handle.as_ptr()) };
95 assert!(!result.is_null());
96 unsafe { BnString::into_string(result as *mut c_char) }
97 }
98
99 pub fn description(&self) -> String {
101 let result = unsafe { BNPluginGetDescription(self.handle.as_ptr()) };
102 assert!(!result.is_null());
103 unsafe { BnString::into_string(result as *mut c_char) }
104 }
105
106 pub fn license_text(&self) -> String {
108 let result = unsafe { BNPluginGetLicenseText(self.handle.as_ptr()) };
109 assert!(!result.is_null());
110 unsafe { BnString::into_string(result as *mut c_char) }
111 }
112
113 pub fn minimum_version_info(&self) -> VersionInfo {
115 let result = unsafe { BNPluginGetMinimumVersionInfo(self.handle.as_ptr()) };
116 VersionInfo::from_owned_raw(result)
117 }
118
119 pub fn maximum_version_info(&self) -> VersionInfo {
121 let result = unsafe { BNPluginGetMaximumVersionInfo(self.handle.as_ptr()) };
122 VersionInfo::from_owned_raw(result)
123 }
124
125 pub fn versions(&self) -> Array<ExtensionVersion> {
127 let mut count = 0;
128 let result = unsafe { BNPluginGetVersions(self.handle.as_ptr(), &mut count) };
129 assert!(!result.is_null());
130 unsafe { Array::new(result, count, ()) }
131 }
132
133 pub fn current_version(&self) -> ExtensionVersion {
135 let result = unsafe { BNPluginGetCurrentVersion(self.handle.as_ptr()) };
136 ExtensionVersion::from_owned_raw(result)
137 }
138
139 pub fn latest_version_id(&self) -> String {
141 let result = unsafe { BNPluginGetLatestVersionID(self.handle.as_ptr()) };
142 assert!(!result.is_null());
143 unsafe { BnString::into_string(result as *mut c_char) }
144 }
145
146 pub fn name(&self) -> String {
148 let result = unsafe { BNPluginGetName(self.handle.as_ptr()) };
149 assert!(!result.is_null());
150 unsafe { BnString::into_string(result as *mut c_char) }
151 }
152
153 pub fn project_url(&self) -> String {
155 let result = unsafe { BNPluginGetProjectUrl(self.handle.as_ptr()) };
156 assert!(!result.is_null());
157 unsafe { BnString::into_string(result as *mut c_char) }
158 }
159
160 pub fn package_url(&self) -> String {
162 let result = unsafe { BNPluginGetPackageUrl(self.handle.as_ptr()) };
163 assert!(!result.is_null());
164 unsafe { BnString::into_string(result as *mut c_char) }
165 }
166
167 pub fn is_paid(&self) -> bool {
169 unsafe { BNPluginGetIsPaid(self.handle.as_ptr()) }
170 }
171
172 pub fn author_url(&self) -> String {
174 let result = unsafe { BNPluginGetAuthorUrl(self.handle.as_ptr()) };
175 assert!(!result.is_null());
176 unsafe { BnString::into_string(result as *mut c_char) }
177 }
178
179 pub fn commit(&self) -> String {
181 let result = unsafe { BNPluginGetCommit(self.handle.as_ptr()) };
182 assert!(!result.is_null());
183 unsafe { BnString::into_string(result as *mut c_char) }
184 }
185
186 pub fn path(&self) -> PathBuf {
188 let result = unsafe { BNPluginGetPath(self.handle.as_ptr()) };
189 assert!(!result.is_null());
190 let result_str = unsafe { BnString::into_string(result as *mut c_char) };
191 PathBuf::from(result_str)
192 }
193
194 pub fn subdir(&self) -> PathBuf {
196 let result = unsafe { BNPluginGetSubdir(self.handle.as_ptr()) };
197 assert!(!result.is_null());
198 let result_str = unsafe { BnString::into_string(result as *mut c_char) };
199 PathBuf::from(result_str)
200 }
201
202 pub fn dependencies(&self) -> String {
204 let result = unsafe { BNPluginGetDependencies(self.handle.as_ptr()) };
205 assert!(!result.is_null());
206 unsafe { BnString::into_string(result as *mut c_char) }
207 }
208
209 pub fn is_installed(&self) -> bool {
211 unsafe { BNPluginIsInstalled(self.handle.as_ptr()) }
212 }
213
214 pub fn is_listed(&self) -> bool {
216 unsafe { BNPluginIsListed(self.handle.as_ptr()) }
217 }
218
219 pub fn is_deprecated(&self) -> bool {
221 unsafe { BNPluginIsDeprecated(self.handle.as_ptr()) }
222 }
223
224 pub fn is_enabled(&self) -> bool {
226 unsafe { BNPluginIsEnabled(self.handle.as_ptr()) }
227 }
228
229 pub fn status(&self) -> PluginStatus {
230 unsafe { BNPluginGetPluginStatus(self.handle.as_ptr()) }
231 }
232
233 pub fn types(&self) -> Array<PluginType> {
235 let mut count = 0;
236 let result = unsafe { BNPluginGetPluginTypes(self.handle.as_ptr(), &mut count) };
237 assert!(!result.is_null());
238 unsafe { Array::new(result, count, ()) }
239 }
240
241 pub fn enable(&self, force: bool) -> bool {
244 unsafe { BNPluginEnable(self.handle.as_ptr(), force) }
245 }
246
247 pub fn disable(&self) -> bool {
248 unsafe { BNPluginDisable(self.handle.as_ptr()) }
249 }
250
251 pub fn install(&self, version_id: &str) -> bool {
253 let version_id_raw = version_id.to_cstr();
254 unsafe { BNPluginInstall(self.handle.as_ptr(), version_id_raw.as_ptr()) }
255 }
256
257 pub fn install_dependencies(&self) -> bool {
258 unsafe { BNPluginInstallDependencies(self.handle.as_ptr()) }
259 }
260
261 pub fn uninstall(&self) -> bool {
263 unsafe { BNPluginUninstall(self.handle.as_ptr()) }
264 }
265
266 pub fn cancel_uninstall(&self) -> bool {
268 unsafe { BNPluginCancelUninstall(self.handle.as_ptr()) }
269 }
270
271 pub fn updated(&self, version_id: &str) -> bool {
272 let version_id_raw = version_id.to_cstr();
273 unsafe { BNPluginUpdate(self.handle.as_ptr(), version_id_raw.as_ptr()) }
274 }
275
276 pub fn platforms(&self) -> Array<BnString> {
278 let mut count = 0;
279 let result = unsafe { BNPluginGetPlatforms(self.handle.as_ptr(), &mut count) };
280 assert!(!result.is_null());
281 unsafe { Array::new(result, count, ()) }
282 }
283
284 pub fn repository(&self) -> String {
285 let result = unsafe { BNPluginGetRepository(self.handle.as_ptr()) };
286 assert!(!result.is_null());
287 unsafe { BnString::into_string(result as *mut c_char) }
288 }
289
290 pub fn is_being_deleted(&self) -> bool {
292 unsafe { BNPluginIsBeingDeleted(self.handle.as_ptr()) }
293 }
294
295 pub fn is_being_updated(&self) -> bool {
297 unsafe { BNPluginIsBeingUpdated(self.handle.as_ptr()) }
298 }
299
300 pub fn is_running(&self) -> bool {
302 unsafe { BNPluginIsRunning(self.handle.as_ptr()) }
303 }
304
305 pub fn is_update_pending(&self) -> bool {
307 unsafe { BNPluginIsUpdatePending(self.handle.as_ptr()) }
308 }
309
310 pub fn is_disable_pending(&self) -> bool {
312 unsafe { BNPluginIsDisablePending(self.handle.as_ptr()) }
313 }
314
315 pub fn is_delete_pending(&self) -> bool {
317 unsafe { BNPluginIsDeletePending(self.handle.as_ptr()) }
318 }
319
320 pub fn is_updated_available(&self) -> bool {
322 unsafe { BNPluginIsUpdateAvailable(self.handle.as_ptr()) }
323 }
324
325 pub fn are_dependencies_being_installed(&self) -> bool {
327 unsafe { BNPluginAreDependenciesBeingInstalled(self.handle.as_ptr()) }
328 }
329
330 pub fn project_data(&self) -> String {
332 let result = unsafe { BNPluginGetProjectData(self.handle.as_ptr()) };
333 assert!(!result.is_null());
334 unsafe { BnString::into_string(result) }
335 }
336}
337
338impl Debug for Extension {
339 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
340 f.debug_struct("Extension")
341 .field("name", &self.name())
342 .field("author", &self.author())
343 .field("description", &self.description())
344 .field("minimum_version_info", &self.minimum_version_info())
345 .field("maximum_version_info", &self.maximum_version_info())
346 .field("status", &self.status())
347 .finish()
348 }
349}
350
351impl ToOwned for Extension {
352 type Owned = Ref<Self>;
353
354 fn to_owned(&self) -> Self::Owned {
355 unsafe { RefCountable::inc_ref(self) }
356 }
357}
358
359unsafe impl RefCountable for Extension {
360 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
361 Self::ref_from_raw(NonNull::new(BNNewPluginReference(handle.handle.as_ptr())).unwrap())
362 }
363
364 unsafe fn dec_ref(handle: &Self) {
365 BNFreePlugin(handle.handle.as_ptr())
366 }
367}
368
369impl CoreArrayProvider for Extension {
370 type Raw = *mut BNPlugin;
371 type Context = ();
372 type Wrapped<'a> = Guard<'a, Self>;
373}
374
375unsafe impl CoreArrayProviderInner for Extension {
376 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
377 BNFreeRepositoryPluginList(raw)
378 }
379
380 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
381 Guard::new(Self::from_raw(NonNull::new(*raw).unwrap()), context)
382 }
383}
384
385impl CoreArrayProvider for ExtensionVersion {
386 type Raw = BNPluginVersion;
387 type Context = ();
388 type Wrapped<'a> = Self;
389}
390
391unsafe impl CoreArrayProviderInner for ExtensionVersion {
392 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
393 BNFreePluginVersions(raw, count)
394 }
395
396 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
397 ExtensionVersion::from_raw(raw)
398 }
399}