binaryninja/download/
provider.rs1use crate::download::{CustomDownloadInstance, DownloadInstance};
2use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref};
3use crate::settings::Settings;
4use crate::string::{BnString, IntoCStr};
5use binaryninjacore_sys::*;
6use std::ffi::c_void;
7use std::fmt::Debug;
8use std::mem::MaybeUninit;
9
10pub fn register_download_provider<C>(name: &str) -> &'static mut C
12where
13 C: CustomDownloadProvider,
14{
15 let name = name.to_cstr();
16 let provider_uninit = MaybeUninit::uninit();
17 let leaked_provider = Box::leak(Box::new(provider_uninit));
19 let result = unsafe {
20 BNRegisterDownloadProvider(
21 name.as_ptr(),
22 &mut BNDownloadProviderCallbacks {
23 context: leaked_provider as *mut _ as *mut c_void,
24 createInstance: Some(cb_create_instance::<C>),
25 },
26 )
27 };
28
29 let provider_core = DownloadProvider::from_raw(result);
30 leaked_provider.write(C::from_core(provider_core));
32 unsafe { leaked_provider.assume_init_mut() }
33}
34
35pub trait CustomDownloadProvider: 'static + Sync {
36 type Instance: CustomDownloadInstance;
37
38 fn handle(&self) -> DownloadProvider;
39
40 fn from_core(core: DownloadProvider) -> Self;
42
43 fn create_instance(&self) -> Result<Ref<DownloadInstance>, ()> {
44 Self::Instance::new_with_provider(self.handle())
45 }
46}
47
48#[derive(Copy, Clone)]
49pub struct DownloadProvider {
50 pub(crate) handle: *mut BNDownloadProvider,
51}
52
53impl DownloadProvider {
54 pub(crate) fn from_raw(handle: *mut BNDownloadProvider) -> DownloadProvider {
55 Self { handle }
56 }
57
58 pub fn get(name: &str) -> Option<DownloadProvider> {
59 let name = name.to_cstr();
60 let result = unsafe { BNGetDownloadProviderByName(name.as_ptr()) };
61 if result.is_null() {
62 return None;
63 }
64 Some(DownloadProvider { handle: result })
65 }
66
67 pub fn list() -> Result<Array<DownloadProvider>, ()> {
68 let mut count = 0;
69 let list: *mut *mut BNDownloadProvider = unsafe { BNGetDownloadProviderList(&mut count) };
70
71 if list.is_null() {
72 return Err(());
73 }
74
75 Ok(unsafe { Array::new(list, count, ()) })
76 }
77
78 pub fn try_default() -> Result<DownloadProvider, ()> {
80 let s = Settings::new();
81 let dp_name = s.get_string("network.downloadProviderName");
82 Self::get(&dp_name).ok_or(())
83 }
84
85 pub fn name(&self) -> String {
86 unsafe { BnString::into_string(BNGetDownloadProviderName(self.handle)) }
87 }
88
89 pub fn create_instance(&self) -> Result<Ref<DownloadInstance>, ()> {
90 let result: *mut BNDownloadInstance =
91 unsafe { BNCreateDownloadProviderInstance(self.handle) };
92 if result.is_null() {
93 return Err(());
94 }
95
96 Ok(unsafe { DownloadInstance::ref_from_raw(result) })
97 }
98}
99
100impl Debug for DownloadProvider {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 f.debug_struct("DownloadProvider")
103 .field("name", &self.name())
104 .finish()
105 }
106}
107
108impl CoreArrayProvider for DownloadProvider {
109 type Raw = *mut BNDownloadProvider;
110 type Context = ();
111 type Wrapped<'a> = Guard<'a, DownloadProvider>;
112}
113
114unsafe impl CoreArrayProviderInner for DownloadProvider {
115 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
116 BNFreeDownloadProviderList(raw);
117 }
118
119 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
120 Guard::new(DownloadProvider::from_raw(*raw), &())
121 }
122}
123
124unsafe impl Send for DownloadProvider {}
125unsafe impl Sync for DownloadProvider {}
126
127unsafe extern "C" fn cb_create_instance<C: CustomDownloadProvider>(
128 ctxt: *mut c_void,
129) -> *mut BNDownloadInstance {
130 ffi_wrap!("CustomDownloadProvider::cb_create_instance", unsafe {
131 let provider = &*(ctxt as *const C);
132 match provider.create_instance() {
133 Ok(instance) => Ref::into_raw(instance).handle,
134 Err(_) => std::ptr::null_mut(),
135 }
136 })
137}