binaryninja/database/
undo.rs

1use crate::disassembly::InstructionTextToken;
2use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
3use crate::string::BnString;
4use binaryninjacore_sys::{
5    BNFreeUndoAction, BNFreeUndoActionList, BNFreeUndoEntry, BNFreeUndoEntryList,
6    BNNewUndoActionReference, BNNewUndoEntryReference, BNUndoAction, BNUndoActionGetSummary,
7    BNUndoActionGetSummaryText, BNUndoEntry, BNUndoEntryGetActions, BNUndoEntryGetId,
8    BNUndoEntryGetTimestamp,
9};
10use std::fmt::Debug;
11use std::ptr::NonNull;
12use std::time::{Duration, SystemTime, UNIX_EPOCH};
13
14#[repr(transparent)]
15pub struct UndoEntry {
16    handle: NonNull<BNUndoEntry>,
17}
18
19impl UndoEntry {
20    pub(crate) unsafe fn from_raw(handle: NonNull<BNUndoEntry>) -> Self {
21        Self { handle }
22    }
23
24    #[allow(dead_code)]
25    pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNUndoEntry>) -> Ref<Self> {
26        Ref::new(Self { handle })
27    }
28
29    pub fn id(&self) -> String {
30        let result = unsafe { BNUndoEntryGetId(self.handle.as_ptr()) };
31        assert!(!result.is_null());
32        unsafe { BnString::into_string(result) }
33    }
34
35    pub fn actions(&self) -> Array<UndoAction> {
36        let mut count = 0;
37        let result = unsafe { BNUndoEntryGetActions(self.handle.as_ptr(), &mut count) };
38        assert!(!result.is_null());
39        unsafe { Array::new(result, count, ()) }
40    }
41
42    pub fn time(&self) -> SystemTime {
43        let m = Duration::from_secs(unsafe { BNUndoEntryGetTimestamp(self.handle.as_ptr()) });
44        UNIX_EPOCH + m
45    }
46}
47
48impl Debug for UndoEntry {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        f.debug_struct("UndoEntry")
51            .field("id", &self.id())
52            .field("time", &self.time())
53            .field("actions", &self.actions().to_vec())
54            .finish()
55    }
56}
57
58impl ToOwned for UndoEntry {
59    type Owned = Ref<Self>;
60
61    fn to_owned(&self) -> Self::Owned {
62        unsafe { RefCountable::inc_ref(self) }
63    }
64}
65
66unsafe impl RefCountable for UndoEntry {
67    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
68        Ref::new(Self {
69            handle: NonNull::new(BNNewUndoEntryReference(handle.handle.as_ptr())).unwrap(),
70        })
71    }
72
73    unsafe fn dec_ref(handle: &Self) {
74        BNFreeUndoEntry(handle.handle.as_ptr());
75    }
76}
77
78impl CoreArrayProvider for UndoEntry {
79    type Raw = *mut BNUndoEntry;
80    type Context = ();
81    type Wrapped<'a> = Guard<'a, UndoEntry>;
82}
83
84unsafe impl CoreArrayProviderInner for UndoEntry {
85    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
86        BNFreeUndoEntryList(raw, count);
87    }
88
89    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
90        let raw_ptr = NonNull::new(*raw).unwrap();
91        Guard::new(Self::from_raw(raw_ptr), context)
92    }
93}
94
95#[repr(transparent)]
96pub struct UndoAction {
97    handle: NonNull<BNUndoAction>,
98}
99
100impl UndoAction {
101    pub(crate) unsafe fn from_raw(handle: NonNull<BNUndoAction>) -> Self {
102        Self { handle }
103    }
104
105    #[allow(dead_code)]
106    pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNUndoAction>) -> Ref<Self> {
107        Ref::new(Self { handle })
108    }
109
110    pub fn summary(&self) -> Array<InstructionTextToken> {
111        let mut count = 0;
112        let result = unsafe { BNUndoActionGetSummary(self.handle.as_ptr(), &mut count) };
113        assert!(!result.is_null());
114        unsafe { Array::new(result, count, ()) }
115    }
116
117    /// Gets the [`UndoAction`] summary as text rather than [`InstructionTextToken`]'s.
118    pub fn summary_as_string(&self) -> String {
119        let result = unsafe { BNUndoActionGetSummaryText(self.handle.as_ptr()) };
120        assert!(!result.is_null());
121        unsafe { BnString::into_string(result) }
122    }
123}
124
125impl Debug for UndoAction {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        f.debug_struct("UndoAction")
128            .field("summary", &self.summary_as_string())
129            .finish()
130    }
131}
132
133impl ToOwned for UndoAction {
134    type Owned = Ref<Self>;
135
136    fn to_owned(&self) -> Self::Owned {
137        unsafe { RefCountable::inc_ref(self) }
138    }
139}
140
141unsafe impl RefCountable for UndoAction {
142    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
143        Ref::new(Self {
144            handle: NonNull::new(BNNewUndoActionReference(handle.handle.as_ptr())).unwrap(),
145        })
146    }
147
148    unsafe fn dec_ref(handle: &Self) {
149        BNFreeUndoAction(handle.handle.as_ptr());
150    }
151}
152
153impl CoreArrayProvider for UndoAction {
154    type Raw = *mut BNUndoAction;
155    type Context = ();
156    type Wrapped<'a> = Guard<'a, UndoAction>;
157}
158
159unsafe impl CoreArrayProviderInner for UndoAction {
160    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
161        BNFreeUndoActionList(raw, count);
162    }
163
164    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
165        let raw_ptr = NonNull::new(*raw).unwrap();
166        Guard::new(Self::from_raw(raw_ptr), context)
167    }
168}