1use crate::binary_view::{BinaryReader, BinaryView};
2use crate::data_buffer::DataBuffer;
3use crate::metadata::Metadata;
4use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable};
5use crate::settings::Settings;
6use crate::string::{raw_to_string, strings_to_string_list, BnString, IntoCStr};
7use binaryninjacore_sys::*;
8use std::borrow::Cow;
9use std::collections::HashMap;
10use std::ffi::{c_char, c_void, CStr};
11use std::fmt::{Debug, Formatter};
12use std::mem::ManuallyDrop;
13use std::path::Path;
14
15pub type TransformType = BNTransformType;
16pub type TransformResult = BNTransformResult;
17pub type TransformSessionMode = BNTransformSessionMode;
18
19pub type TransformInputParameters = HashMap<String, DataBuffer>;
21
22bitflags::bitflags! {
23 pub struct TransformCapabilities: u32 {
24 const NONE = 0b00000000;
25 const SUPPORTS_DETECTION = 0b00000001;
26 const SUPPORTS_CONTEXT = 0b00000010;
27 }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum ProcessResult {
32 Incomplete,
35 Complete,
37}
38
39pub fn register_transform<C: CustomTransform>(custom: C) -> (&'static mut C, Transform) {
41 register_transform_with_callbacks(custom, TransformCapabilities::NONE, None, None)
42}
43
44pub fn register_transform_with_detection<C>(custom: C) -> (&'static mut C, Transform)
46where
47 C: CustomTransform + DetectionTransform,
48{
49 register_transform_with_callbacks(
50 custom,
51 TransformCapabilities::SUPPORTS_DETECTION,
52 Some(cb_can_decode::<C>),
53 None,
54 )
55}
56
57pub fn register_transform_with_context<C>(custom: C) -> (&'static mut C, Transform)
59where
60 C: CustomTransform + ContextTransform,
61{
62 register_transform_with_callbacks(
63 custom,
64 TransformCapabilities::SUPPORTS_CONTEXT,
65 None,
66 Some(cb_decode_with_context::<C>),
67 )
68}
69
70pub fn register_transform_with_detection_and_context<C>(custom: C) -> (&'static mut C, Transform)
72where
73 C: CustomTransform + DetectionTransform + ContextTransform,
74{
75 register_transform_with_callbacks(
76 custom,
77 TransformCapabilities::SUPPORTS_DETECTION | TransformCapabilities::SUPPORTS_CONTEXT,
78 Some(cb_can_decode::<C>),
79 Some(cb_decode_with_context::<C>),
80 )
81}
82
83fn register_transform_with_callbacks<C: CustomTransform>(
84 custom: C,
85 capabilities: TransformCapabilities,
86 can_decode: Option<unsafe extern "C" fn(*mut c_void, *mut BNBinaryView) -> bool>,
87 decode_with_context: Option<
88 unsafe extern "C" fn(
89 *mut c_void,
90 *mut BNTransformContext,
91 *mut BNTransformParameter,
92 usize,
93 ) -> bool,
94 >,
95) -> (&'static mut C, Transform) {
96 let name = C::NAME.to_cstr();
97 let long_name = C::LONG_NAME.to_cstr();
98 let group = C::GROUP.to_cstr();
99 let transform = Box::leak(Box::new(custom));
100 let mut callbacks = BNCustomTransform {
101 context: transform as *mut _ as *mut c_void,
102 getParameters: Some(cb_get_params::<C>),
103 freeParameters: Some(cb_free_params),
104 decode: Some(cb_decode::<C>),
105 encode: Some(cb_encode::<C>),
106 decodeWithContext: decode_with_context,
107 canDecode: can_decode,
108 };
109 let result = unsafe {
110 BNRegisterTransformTypeWithCapabilities(
111 C::TYPE,
112 capabilities.bits(),
113 name.as_ptr(),
114 long_name.as_ptr(),
115 group.as_ptr(),
116 &mut callbacks,
117 )
118 };
119 assert!(
120 !result.is_null(),
121 "Should always be a valid pointer returned"
122 );
123 let core = unsafe { Transform::from_raw(result) };
124 (transform, core)
125}
126
127pub trait CustomTransform {
128 const TYPE: TransformType;
129 const NAME: &'static str;
130 const LONG_NAME: &'static str = Self::NAME;
131 const GROUP: &'static str;
132 const PARAMETERS: &'static [TransformParameterInfo] = &[];
133
134 fn decode(&self, input: &[u8], params: &TransformInputParameters) -> Option<DataBuffer>;
135
136 fn encode(&self, input: &[u8], params: &TransformInputParameters) -> Option<DataBuffer>;
137}
138
139pub trait DetectionTransform: CustomTransform {
141 fn can_decode(&self, reader: &mut BinaryReader) -> bool;
142}
143
144pub trait ContextTransform: CustomTransform {
146 fn decode_within_context(
147 &self,
148 context: &TransformContext,
149 params: &TransformInputParameters,
150 ) -> bool;
151}
152
153pub struct Transform {
160 handle: *mut BNTransform,
161}
162
163impl Transform {
164 pub(crate) unsafe fn from_raw(handle: *mut BNTransform) -> Self {
165 assert!(!handle.is_null());
166 Self { handle }
167 }
168
169 pub fn by_name(name: &str) -> Option<Self> {
170 let name = name.to_cstr();
171 let handle = unsafe { BNGetTransformByName(name.as_ptr()) };
172 if handle.is_null() {
173 None
174 } else {
175 Some(unsafe { Self::from_raw(handle) })
176 }
177 }
178
179 pub fn transform_type(&self) -> TransformType {
180 unsafe { BNGetTransformType(self.handle) }
181 }
182
183 pub fn name(&self) -> String {
184 unsafe { BnString::into_string(BNGetTransformName(self.handle)) }
185 }
186
187 pub fn long_name(&self) -> String {
188 unsafe { BnString::into_string(BNGetTransformLongName(self.handle)) }
189 }
190
191 pub fn group(&self) -> String {
192 unsafe { BnString::into_string(BNGetTransformGroup(self.handle)) }
193 }
194
195 pub fn capabilities(&self) -> TransformCapabilities {
196 TransformCapabilities::from_bits_retain(unsafe { BNGetTransformCapabilities(self.handle) })
197 }
198
199 pub fn supports_detection(&self) -> bool {
200 unsafe { BNTransformSupportsDetection(self.handle) }
201 }
202
203 pub fn supports_context(&self) -> bool {
204 unsafe { BNTransformSupportsContext(self.handle) }
205 }
206
207 pub fn params(&self) -> Array<TransformParameterInfo> {
208 let mut count = 0;
209 let list = unsafe { BNGetTransformParameterList(self.handle, &mut count) };
210 unsafe { Array::new(list, count, ()) }
211 }
212
213 pub fn can_decode(&self, input: &BinaryView) -> bool {
214 unsafe { BNCanDecode(self.handle, input.handle) }
215 }
216
217 pub fn decode(&self, input: &[u8], params: &TransformInputParameters) -> Option<DataBuffer> {
218 let buffer = DataBuffer::new(input);
219 let output = DataBuffer::new(&[]);
220 let mut param_list: Vec<BNTransformParameter> = params
221 .iter()
222 .map(|(name, value)| BNTransformParameter {
223 name: BnString::into_raw(BnString::new(name)),
224 value: value.as_raw(),
225 })
226 .collect();
227 let result = unsafe {
228 BNDecode(
229 self.handle,
230 buffer.as_raw(),
231 output.as_raw(),
232 param_list.as_mut_ptr(),
233 param_list.len(),
234 )
235 };
236 for param in param_list {
237 unsafe { BnString::free_raw(param.name as *mut c_char) };
238 }
239 match result {
240 true => Some(output),
241 false => None,
242 }
243 }
244
245 pub fn encode(&self, input: &[u8], params: &TransformInputParameters) -> Option<DataBuffer> {
246 let buffer = DataBuffer::new(input);
247 let output = DataBuffer::new(&[]);
248 let mut param_list: Vec<BNTransformParameter> = params
249 .iter()
250 .map(|(name, value)| BNTransformParameter {
251 name: BnString::into_raw(BnString::new(name)),
252 value: value.as_raw(),
253 })
254 .collect();
255 let result = unsafe {
256 BNEncode(
257 self.handle,
258 buffer.as_raw(),
259 output.as_raw(),
260 param_list.as_mut_ptr(),
261 param_list.len(),
262 )
263 };
264 for param in param_list {
265 unsafe { BnString::free_raw(param.name as *mut c_char) };
266 }
267 match result {
268 true => Some(output),
269 false => None,
270 }
271 }
272
273 pub fn decode_within_context(
274 &self,
275 context: &TransformContext,
276 params: &TransformInputParameters,
277 ) -> bool {
278 let mut param_list: Vec<BNTransformParameter> = params
279 .iter()
280 .map(|(name, value)| BNTransformParameter {
281 name: BnString::into_raw(BnString::new(name)),
282 value: value.as_raw(),
283 })
284 .collect();
285 let result = unsafe {
286 BNDecodeWithContext(
287 self.handle,
288 context.handle,
289 param_list.as_mut_ptr(),
290 param_list.len(),
291 )
292 };
293 match result {
294 true => true,
295 false => false,
296 }
297 }
298}
299
300impl Debug for Transform {
301 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
302 f.debug_struct("Transform")
303 .field("name", &self.name())
304 .field("long_name", &self.long_name())
305 .field("group", &self.group())
306 .field("params", &self.params().to_vec())
307 .finish()
308 }
309}
310
311pub struct TransformContext {
313 handle: *mut BNTransformContext,
314}
315
316impl TransformContext {
317 pub(crate) unsafe fn from_raw(handle: *mut BNTransformContext) -> Self {
318 assert!(!handle.is_null());
319 Self { handle }
320 }
321
322 pub(crate) unsafe fn ref_from_raw(handle: *mut BNTransformContext) -> Ref<Self> {
323 Ref::new(Self::from_raw(handle))
324 }
325
326 pub fn input(&self) -> Ref<BinaryView> {
330 unsafe { BinaryView::ref_from_raw(BNTransformContextGetInput(self.handle)) }
331 }
332
333 pub fn name(&self) -> String {
335 unsafe { BnString::into_string(BNTransformContextGetFileName(self.handle)) }
336 }
337
338 pub fn available_transforms(&self) -> Array<BnString> {
343 let mut count = 0;
344 let transforms_raw =
345 unsafe { BNTransformContextGetAvailableTransforms(self.handle, &mut count) };
346 unsafe { Array::new(transforms_raw, count, ()) }
347 }
348
349 pub fn transform_name(&self) -> String {
351 unsafe { BnString::into_string(BNTransformContextGetTransformName(self.handle)) }
352 }
353
354 pub fn set_transform_name(&self, transform_name: &str) {
361 let raw_transform_name = transform_name.to_cstr();
362 unsafe { BNTransformContextSetTransformName(self.handle, raw_transform_name.as_ptr()) }
363 }
364
365 pub fn set_transform_params(&self, params: &TransformInputParameters) {
366 let mut param_list: Vec<BNTransformParameter> = params
367 .iter()
368 .map(|(name, value)| BNTransformParameter {
369 name: BnString::into_raw(BnString::new(name)),
370 value: value.as_raw(),
371 })
372 .collect();
373 unsafe {
374 BNTransformContextSetTransformParameters(
375 self.handle,
376 param_list.as_mut_ptr(),
377 param_list.len(),
378 )
379 };
380 for param in param_list {
381 unsafe { BnString::from_raw(param.name as *mut c_char) };
382 }
383 }
384
385 pub fn set_transform_param(&self, name: &str, value: &DataBuffer) {
386 let raw_name = name.to_cstr();
387 unsafe {
388 BNTransformContextSetTransformParameter(self.handle, raw_name.as_ptr(), value.as_raw())
389 }
390 }
391
392 pub fn has_transform_param(&self, name: &str) -> bool {
393 let raw_name = name.to_cstr();
394 unsafe { BNTransformContextHasTransformParameter(self.handle, raw_name.as_ptr()) }
395 }
396
397 pub fn clear_transform_params(&self, name: &str) {
398 let raw_name = name.to_cstr();
399 unsafe { BNTransformContextClearTransformParameter(self.handle, raw_name.as_ptr()) }
400 }
401
402 pub fn extraction_message(&self) -> String {
406 unsafe { BnString::into_string(BNTransformContextGetExtractionMessage(self.handle)) }
407 }
408
409 pub fn extraction_result(&self) -> TransformResult {
413 unsafe { BNTransformContextGetExtractionResult(self.handle) }
414 }
415
416 pub fn transform_result(&self) -> TransformResult {
420 unsafe { BNTransformContextGetTransformResult(self.handle) }
421 }
422
423 pub fn set_transform_result(&self, result: TransformResult) {
425 unsafe { BNTransformContextSetTransformResult(self.handle, result) }
426 }
427
428 pub fn metadata(&self) -> Ref<Metadata> {
432 unsafe { Metadata::ref_from_raw(BNTransformContextGetMetadata(self.handle)) }
434 }
435
436 pub fn parent(&self) -> Option<Ref<TransformContext>> {
438 let parent_handle = unsafe { BNTransformContextGetParent(self.handle) };
439 if parent_handle.is_null() {
440 None
441 } else {
442 Some(unsafe { TransformContext::ref_from_raw(parent_handle) })
443 }
444 }
445
446 pub fn children(&self) -> Array<TransformContext> {
447 let mut count = 0;
448 let raw = unsafe { BNTransformContextGetChildren(self.handle, &mut count) };
449 unsafe { Array::new(raw, count, ()) }
450 }
451
452 pub fn child_by_name(&self, name: &str) -> Option<Ref<TransformContext>> {
453 let name = name.to_cstr();
454 let child_handle = unsafe { BNTransformContextGetChild(self.handle, name.as_ptr()) };
455 if child_handle.is_null() {
456 None
457 } else {
458 Some(unsafe { TransformContext::ref_from_raw(child_handle) })
459 }
460 }
461
462 pub fn create_child(
472 &self,
473 name: &str,
474 data: &DataBuffer,
475 extraction_result: TransformResult,
476 extraction_message: &str,
477 is_descriptor: bool,
478 ) -> Ref<TransformContext> {
479 let name = name.to_cstr();
480 let message = extraction_message.to_cstr();
481 let child_handle = unsafe {
482 BNTransformContextSetChild(
483 self.handle,
484 data.as_raw(),
485 name.as_ptr(),
486 extraction_result,
487 message.as_ptr(),
488 is_descriptor,
489 )
490 };
491 assert!(
492 !child_handle.is_null(),
493 "Core always constructs a valid child context handle"
494 );
495 unsafe { TransformContext::ref_from_raw(child_handle) }
496 }
497
498 pub fn is_leaf(&self) -> bool {
500 unsafe { BNTransformContextIsLeaf(self.handle) }
501 }
502
503 pub fn is_root(&self) -> bool {
505 unsafe { BNTransformContextIsRoot(self.handle) }
506 }
507
508 pub fn available_files(&self) -> Array<BnString> {
510 let mut count = 0;
511 let file_list = unsafe { BNTransformContextGetAvailableFiles(self.handle, &mut count) };
512 assert!(
513 !file_list.is_null(),
514 "Core always returns a valid file list"
515 );
516 unsafe { Array::new(file_list, count, ()) }
517 }
518
519 pub fn set_available_files(&self, files: &[&str]) {
525 let file_list = strings_to_string_list(files);
526 unsafe { BNTransformContextSetAvailableFiles(self.handle, file_list as _, files.len()) };
527 unsafe { BNFreeStringList(file_list as _, files.len()) };
528 }
529
530 pub fn requested_files(&self) -> Array<BnString> {
535 let mut count = 0;
536 let file_list = unsafe { BNTransformContextGetRequestedFiles(self.handle, &mut count) };
537 assert!(
538 !file_list.is_null(),
539 "Core always returns a valid file list"
540 );
541 unsafe { Array::new(file_list, count, ()) }
542 }
543
544 pub fn set_requested_files(&self, files: &[&str]) {
549 let file_list = strings_to_string_list(files);
550 unsafe { BNTransformContextSetRequestedFiles(self.handle, file_list as _, files.len()) };
551 unsafe { BNFreeStringList(file_list as _, files.len()) };
552 }
553
554 pub fn is_database(&self) -> bool {
556 unsafe { BNTransformContextIsDatabase(self.handle) }
557 }
558
559 pub fn is_interactive(&self) -> bool {
564 unsafe { BNTransformContextIsInteractive(self.handle) }
565 }
566
567 pub fn settings(&self) -> Ref<Settings> {
568 unsafe { Settings::ref_from_raw(BNTransformContextGetSettings(self.handle)) }
569 }
570}
571
572impl ToOwned for TransformContext {
573 type Owned = Ref<Self>;
574
575 fn to_owned(&self) -> Self::Owned {
576 unsafe { RefCountable::inc_ref(self) }
577 }
578}
579
580unsafe impl RefCountable for TransformContext {
581 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
582 Ref::new(Self {
583 handle: BNNewTransformContextReference(handle.handle),
584 })
585 }
586
587 unsafe fn dec_ref(handle: &Self) {
588 BNFreeTransformContext(handle.handle);
589 }
590}
591
592impl CoreArrayProvider for TransformContext {
593 type Raw = *mut BNTransformContext;
594 type Context = ();
595 type Wrapped<'a> = Self;
596}
597
598unsafe impl CoreArrayProviderInner for TransformContext {
599 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
600 unsafe { BNFreeTransformContextList(raw, count) };
601 }
602
603 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
604 Self::from_raw(*raw)
605 }
606}
607
608pub struct TransformSession {
624 handle: *mut BNTransformSession,
625}
626
627impl TransformSession {
628 pub(crate) unsafe fn from_raw(handle: *mut BNTransformSession) -> Self {
629 Self { handle }
630 }
631
632 pub(crate) unsafe fn ref_from_raw(handle: *mut BNTransformSession) -> Ref<Self> {
633 unsafe { Ref::new(Self::from_raw(handle)) }
634 }
635
636 pub fn new(file_path: &Path, settings: &Settings) -> Ref<TransformSession> {
642 let file_path = file_path.to_cstr();
643 let settings = settings.serialize_schema().to_cstr();
644 let session = unsafe { BNCreateTransformSession(file_path.as_ptr(), settings.as_ptr()) };
645 assert!(
646 !session.is_null(),
647 "Transform session should always be valid"
648 );
649 unsafe { Self::ref_from_raw(session) }
650 }
651
652 pub fn new_with_mode(
654 file_path: &Path,
655 settings: &Settings,
656 mode: TransformSessionMode,
657 ) -> Ref<TransformSession> {
658 let file_path = file_path.to_cstr();
659 let settings = settings.serialize_schema().to_cstr();
660 let session = unsafe {
661 BNCreateTransformSessionWithMode(file_path.as_ptr(), mode, settings.as_ptr())
662 };
663 assert!(
664 !session.is_null(),
665 "Transform session should always be valid"
666 );
667 unsafe { Self::ref_from_raw(session) }
668 }
669
670 pub fn from_view(view: &BinaryView, settings: &Settings) -> Ref<TransformSession> {
672 let settings = settings.serialize_schema().to_cstr();
673 let session =
674 unsafe { BNCreateTransformSessionFromBinaryView(view.handle, settings.as_ptr()) };
675 assert!(
676 !session.is_null(),
677 "Transform session should always be valid"
678 );
679 unsafe { Self::ref_from_raw(session) }
680 }
681
682 pub fn from_view_with_mode(
684 view: &BinaryView,
685 settings: &Settings,
686 mode: TransformSessionMode,
687 ) -> Ref<TransformSession> {
688 let settings = settings.serialize_schema().to_cstr();
689 let session = unsafe {
690 BNCreateTransformSessionFromBinaryViewWithMode(view.handle, mode, settings.as_ptr())
691 };
692 assert!(
693 !session.is_null(),
694 "Transform session should always be valid"
695 );
696 unsafe { Self::ref_from_raw(session) }
697 }
698
699 pub fn from_context(
701 context: &TransformContext,
702 settings: &Settings,
703 mode: TransformSessionMode,
704 ) -> Ref<TransformSession> {
705 let settings = settings.serialize_schema().to_cstr();
706 let session = unsafe {
707 BNCreateTransformSessionFromTransformContextWithMode(
708 context.handle,
709 mode,
710 settings.as_ptr(),
711 )
712 };
713 assert!(
714 !session.is_null(),
715 "Transform session should always be valid"
716 );
717 unsafe { Self::ref_from_raw(session) }
718 }
719
720 pub fn root_context(&self) -> Option<Ref<TransformContext>> {
721 let handle = unsafe { BNTransformSessionGetRootContext(self.handle) };
722 if handle.is_null() {
723 None
724 } else {
725 Some(unsafe { TransformContext::ref_from_raw(handle) })
726 }
727 }
728
729 pub fn current_context(&self) -> Option<Ref<TransformContext>> {
730 let handle = unsafe { BNTransformSessionGetCurrentContext(self.handle) };
731 if handle.is_null() {
732 None
733 } else {
734 Some(unsafe { TransformContext::ref_from_raw(handle) })
735 }
736 }
737
738 pub fn process(&self) -> ProcessResult {
742 match unsafe { BNTransformSessionProcess(self.handle) } {
743 false => ProcessResult::Incomplete,
744 true => ProcessResult::Complete,
745 }
746 }
747
748 pub fn process_from(&self, context: &TransformContext) -> ProcessResult {
752 match unsafe { BNTransformSessionProcessFrom(self.handle, context.handle) } {
753 false => ProcessResult::Incomplete,
754 true => ProcessResult::Complete,
755 }
756 }
757
758 pub fn has_any_stages(&self) -> bool {
763 unsafe { BNTransformSessionHasAnyStages(self.handle) }
764 }
765
766 pub fn has_single_path(&self) -> bool {
768 unsafe { BNTransformSessionHasSinglePath(self.handle) }
769 }
770
771 pub fn selected_contexts(&self) -> Array<TransformContext> {
775 let mut count = 0;
776 let handle = unsafe { BNTransformSessionGetSelectedContexts(self.handle, &mut count) };
777 unsafe { Array::new(handle, count, ()) }
778 }
779
780 pub fn set_selected_contexts(&self, contexts: &[Ref<TransformContext>]) {
783 let mut contexts: Vec<*mut BNTransformContext> =
784 contexts.iter().map(|c| c.handle).collect();
785 unsafe {
786 BNTransformSessionSetSelectedContexts(
787 self.handle,
788 contexts.as_mut_ptr(),
789 contexts.len(),
790 )
791 }
792 }
793}
794
795impl ToOwned for TransformSession {
796 type Owned = Ref<Self>;
797
798 fn to_owned(&self) -> Self::Owned {
799 unsafe { RefCountable::inc_ref(self) }
800 }
801}
802
803unsafe impl RefCountable for TransformSession {
804 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
805 Ref::new(Self {
806 handle: BNNewTransformSessionReference(handle.handle),
807 })
808 }
809
810 unsafe fn dec_ref(handle: &Self) {
811 BNFreeTransformSession(handle.handle);
812 }
813}
814
815#[derive(Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
816pub struct TransformParameterInfo {
817 pub name: Cow<'static, str>,
818 pub long_name: Cow<'static, str>,
819 pub length: Option<usize>,
820}
821
822impl TransformParameterInfo {
823 pub fn new(name: &'static str, length: Option<usize>) -> Self {
824 Self {
825 name: Cow::Borrowed(name),
826 long_name: Cow::Borrowed(name),
827 length,
828 }
829 }
830
831 pub fn new_with_long(
832 name: &'static str,
833 long_name: &'static str,
834 length: Option<usize>,
835 ) -> Self {
836 Self {
837 name: Cow::Borrowed(name),
838 long_name: Cow::Borrowed(long_name),
839 length,
840 }
841 }
842
843 pub fn from_raw(value: BNTransformParameterInfo) -> Self {
844 Self {
845 name: Cow::Owned(raw_to_string(value.name).unwrap_or_default()),
846 long_name: Cow::Owned(raw_to_string(value.longName).unwrap_or_default()),
847 length: Some(value.fixedLength),
848 }
849 }
850
851 pub fn into_raw(self) -> BNTransformParameterInfo {
852 BNTransformParameterInfo {
853 name: BnString::into_raw(BnString::new(self.name)),
854 longName: BnString::into_raw(BnString::new(self.long_name)),
855 fixedLength: self.length.unwrap_or(0),
856 }
857 }
858
859 pub fn free_raw(value: BNTransformParameterInfo) {
860 unsafe {
861 BnString::free_raw(value.name);
862 BnString::free_raw(value.longName);
863 }
864 }
865}
866
867impl CoreArrayProvider for TransformParameterInfo {
868 type Raw = BNTransformParameterInfo;
869 type Context = ();
870 type Wrapped<'a> = Self;
871}
872
873unsafe impl CoreArrayProviderInner for TransformParameterInfo {
874 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
875 unsafe { BNFreeTransformParameterList(raw, count) };
876 }
877
878 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
879 Self::from_raw(*raw)
880 }
881}
882
883unsafe extern "C" fn cb_get_params<C: CustomTransform>(
884 _ctxt: *mut c_void,
885 count: *mut usize,
886) -> *mut BNTransformParameterInfo {
887 let boxed_params: Box<[_]> = C::PARAMETERS
888 .iter()
889 .cloned()
890 .map(TransformParameterInfo::into_raw)
891 .collect();
892 let leaked_params = Box::leak(boxed_params);
893 *count = leaked_params.len();
894 leaked_params as *mut _ as *mut BNTransformParameterInfo
895}
896
897unsafe extern "C" fn cb_free_params(params: *mut BNTransformParameterInfo, count: usize) {
898 let params = Box::from_raw(std::ptr::slice_from_raw_parts_mut(params, count));
899 for param in params {
900 TransformParameterInfo::free_raw(param);
901 }
902}
903
904unsafe extern "C" fn cb_decode<C: CustomTransform>(
905 ctxt: *mut c_void,
906 input: *mut BNDataBuffer,
907 output: *mut BNDataBuffer,
908 params: *mut BNTransformParameter,
909 param_count: usize,
910) -> bool {
911 let ctxt = ctxt as *mut C;
912 let raw_params = core::slice::from_raw_parts(params, param_count);
913 let params: TransformInputParameters = raw_params
914 .iter()
915 .map(|p| {
916 let name = CStr::from_ptr(p.name).to_string_lossy();
917 let buffer = DataBuffer::from_raw(p.value);
919 let owned_buffer = buffer.clone();
920 std::mem::forget(buffer);
921 (name.to_string(), owned_buffer)
922 })
923 .collect();
924 let input = ManuallyDrop::new(DataBuffer::from_raw(input));
925 let mut output = ManuallyDrop::new(DataBuffer::from_raw(output));
926 match (*ctxt).decode(input.as_ref(), ¶ms) {
927 Some(buffer) => {
928 output.set_data(buffer.as_ref());
929 true
930 }
931 None => false,
932 }
933}
934
935unsafe extern "C" fn cb_encode<C: CustomTransform>(
936 ctxt: *mut c_void,
937 input: *mut BNDataBuffer,
938 output: *mut BNDataBuffer,
939 params: *mut BNTransformParameter,
940 param_count: usize,
941) -> bool {
942 let ctxt = ctxt as *mut C;
943 let raw_params = core::slice::from_raw_parts(params, param_count);
944 let params: TransformInputParameters = raw_params
945 .iter()
946 .map(|p| {
947 let name = CStr::from_ptr(p.name).to_string_lossy();
948 let buffer = DataBuffer::from_raw(p.value);
950 let owned_buffer = buffer.clone();
951 std::mem::forget(buffer);
952 (name.to_string(), owned_buffer)
953 })
954 .collect();
955 let input = ManuallyDrop::new(DataBuffer::from_raw(input));
956 let mut output = ManuallyDrop::new(DataBuffer::from_raw(output));
957 match (*ctxt).encode(input.as_ref(), ¶ms) {
958 Some(buffer) => {
959 output.set_data(buffer.as_ref());
960 true
961 }
962 None => false,
963 }
964}
965
966unsafe extern "C" fn cb_decode_with_context<C: CustomTransform + ContextTransform>(
967 ctxt: *mut c_void,
968 input: *mut BNTransformContext,
969 params: *mut BNTransformParameter,
970 param_count: usize,
971) -> bool {
972 let ctxt = ctxt as *mut C;
973 let raw_params = core::slice::from_raw_parts(params, param_count);
974 let params: TransformInputParameters = raw_params
975 .iter()
976 .map(|p| {
977 let name = CStr::from_ptr(p.name).to_string_lossy();
978 let buffer = DataBuffer::from_raw(p.value);
980 let owned_buffer = buffer.clone();
981 std::mem::forget(buffer);
982 (name.to_string(), owned_buffer)
983 })
984 .collect();
985 let input = TransformContext::from_raw(input);
986 (*ctxt).decode_within_context(&input, ¶ms)
987}
988
989unsafe extern "C" fn cb_can_decode<C: CustomTransform + DetectionTransform>(
990 ctxt: *mut c_void,
991 input: *mut BNBinaryView,
992) -> bool {
993 let ctxt = ctxt as *mut C;
994 let input = BinaryView::from_raw(input);
995 let mut reader = BinaryReader::new(input.as_ref());
996 (*ctxt).can_decode(&mut reader)
997}