use core::{ffi, mem, ptr};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use binaryninjacore_sys::*;
use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner};
use crate::string::BnString;
pub type UpdateResult = BNUpdateResult;
#[repr(C)]
pub struct UpdateChannel {
pub name: BnString,
pub description: BnString,
pub latest_version: BnString,
_lock: core::marker::PhantomData<()>,
}
impl UpdateChannel {
pub(crate) unsafe fn ref_from_raw(handle: &BNUpdateChannel) -> &Self {
mem::transmute(handle)
}
pub fn all() -> Result<Array<UpdateChannel>, BnString> {
let mut count = 0;
let mut errors = ptr::null_mut();
let result = unsafe { BNGetUpdateChannels(&mut count, &mut errors) };
if !errors.is_null() {
Err(unsafe { BnString::from_raw(errors) })
} else {
assert!(!result.is_null());
Ok(unsafe { Array::new(result, count, ()) })
}
}
pub fn versions(&self) -> Result<Array<UpdateVersion>, BnString> {
let mut count = 0;
let mut errors = ptr::null_mut();
let result =
unsafe { BNGetUpdateChannelVersions(self.name.as_ptr(), &mut count, &mut errors) };
if !errors.is_null() {
Err(unsafe { BnString::from_raw(errors) })
} else {
assert!(!result.is_null());
Ok(unsafe { Array::new(result, count, ()) })
}
}
pub fn latest_version(&self) -> Result<UpdateVersion, BnString> {
let last_version = &self.latest_version;
let versions = self.versions()?;
for version in &versions {
if &version.version == last_version {
return Ok(version.clone());
}
}
panic!();
}
pub fn updates_available(&self) -> Result<bool, BnString> {
let mut errors = ptr::null_mut();
let result = unsafe {
BNAreUpdatesAvailable(
self.name.as_ptr(),
ptr::null_mut(),
ptr::null_mut(),
&mut errors,
)
};
if !errors.is_null() {
Err(unsafe { BnString::from_raw(errors) })
} else {
Ok(result)
}
}
pub fn update_to_latest(&self) -> Result<UpdateResult, BnString> {
let mut errors = ptr::null_mut();
let result = unsafe {
BNUpdateToLatestVersion(
self.name.as_ptr(),
&mut errors,
Some(cb_progress_nop),
ptr::null_mut(),
)
};
if !errors.is_null() {
Err(unsafe { BnString::from_raw(errors) })
} else {
Ok(result)
}
}
pub fn update_to_latest_with_progress<F>(
&self,
mut progress: F,
) -> Result<UpdateResult, BnString>
where
F: FnMut(usize, usize) -> bool,
{
let mut errors = ptr::null_mut();
let result = unsafe {
BNUpdateToLatestVersion(
self.name.as_ptr(),
&mut errors,
Some(cb_progress::<F>),
&mut progress as *mut _ as *mut ffi::c_void,
)
};
if !errors.is_null() {
Err(unsafe { BnString::from_raw(errors) })
} else {
Ok(result)
}
}
pub fn update(&self, version: &UpdateVersion) -> Result<UpdateResult, BnString> {
let mut errors = ptr::null_mut();
let result = unsafe {
BNUpdateToVersion(
self.name.as_ptr(),
version.version.as_ptr(),
&mut errors,
Some(cb_progress_nop),
ptr::null_mut(),
)
};
if !errors.is_null() {
Err(unsafe { BnString::from_raw(errors) })
} else {
Ok(result)
}
}
pub fn update_with_progress<F>(
&self,
version: &UpdateVersion,
mut progress: F,
) -> Result<UpdateResult, BnString>
where
F: FnMut(usize, usize) -> bool,
{
let mut errors = ptr::null_mut();
let result = unsafe {
BNUpdateToVersion(
self.name.as_ptr(),
version.version.as_ptr(),
&mut errors,
Some(cb_progress::<F>),
&mut progress as *mut _ as *mut ffi::c_void,
)
};
if !errors.is_null() {
Err(unsafe { BnString::from_raw(errors) })
} else {
Ok(result)
}
}
}
impl CoreArrayProvider for UpdateChannel {
type Raw = BNUpdateChannel;
type Context = ();
type Wrapped<'a> = &'a Self;
}
unsafe impl CoreArrayProviderInner for UpdateChannel {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeUpdateChannelList(raw, count)
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
UpdateChannel::ref_from_raw(raw)
}
}
#[repr(C)]
#[derive(Clone)]
pub struct UpdateVersion {
pub version: BnString,
pub notes: BnString,
time: u64,
_lock: core::marker::PhantomData<()>,
}
impl UpdateVersion {
pub(crate) unsafe fn ref_from_raw(handle: &BNUpdateVersion) -> &Self {
mem::transmute(handle)
}
pub fn time(&self) -> SystemTime {
UNIX_EPOCH + Duration::from_secs(self.time)
}
pub fn set_time(&mut self, time: SystemTime) {
let epoch = time.duration_since(UNIX_EPOCH).unwrap();
self.time = epoch.as_secs();
}
}
impl CoreArrayProvider for UpdateVersion {
type Raw = BNUpdateVersion;
type Context = ();
type Wrapped<'a> = &'a Self;
}
unsafe impl CoreArrayProviderInner for UpdateVersion {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeUpdateChannelVersionList(raw, count)
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
UpdateVersion::ref_from_raw(raw)
}
}
pub fn are_auto_updates_enabled() -> bool {
unsafe { BNAreAutoUpdatesEnabled() }
}
pub fn set_auto_updates_enabled(enabled: bool) {
unsafe { BNSetAutoUpdatesEnabled(enabled) }
}
pub fn get_time_since_last_update_check() -> u64 {
unsafe { BNGetTimeSinceLastUpdateCheck() }
}
pub fn is_update_installation_pending() -> bool {
unsafe { BNIsUpdateInstallationPending() }
}
pub fn install_pending_update() -> Result<(), BnString> {
let mut errors = ptr::null_mut();
unsafe { BNInstallPendingUpdate(&mut errors) };
if !errors.is_null() {
Err(unsafe { BnString::from_raw(errors) })
} else {
Ok(())
}
}
pub fn updates_checked() {
unsafe { BNUpdatesChecked() }
}
unsafe extern "C" fn cb_progress_nop(
_ctxt: *mut ::std::os::raw::c_void,
_progress: usize,
_total: usize,
) -> bool {
true
}
unsafe extern "C" fn cb_progress<F: FnMut(usize, usize) -> bool>(
ctxt: *mut ::std::os::raw::c_void,
progress: usize,
total: usize,
) -> bool {
let ctxt: &mut F = &mut *(ctxt as *mut F);
ctxt(progress, total)
}