1#![allow(unused)]
2
3use crate::binary_view::BinaryView;
4use crate::disassembly::InstructionTextToken;
5use crate::platform::Platform;
6use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref};
7use crate::string::{raw_to_string, BnString, IntoCStr};
8use crate::types::{NamedTypeReference, QualifiedName, QualifiedNameAndType, Type, TypeContainer};
9use binaryninjacore_sys::*;
10use std::ffi::{c_char, c_int, c_void};
11use std::ptr::NonNull;
12
13pub type TokenEscapingType = BNTokenEscapingType;
14pub type TypeDefinitionLineType = BNTypeDefinitionLineType;
15
16pub fn register_type_printer<T: TypePrinter>(
18 name: &str,
19 parser: T,
20) -> (&'static mut T, CoreTypePrinter) {
21 let parser = Box::leak(Box::new(parser));
22 let mut callback = BNTypePrinterCallbacks {
23 context: parser as *mut _ as *mut c_void,
24 getTypeTokens: Some(cb_get_type_tokens::<T>),
25 getTypeTokensBeforeName: Some(cb_get_type_tokens_before_name::<T>),
26 getTypeTokensAfterName: Some(cb_get_type_tokens_after_name::<T>),
27 getTypeString: Some(cb_get_type_string::<T>),
28 getTypeStringBeforeName: Some(cb_get_type_string_before_name::<T>),
29 getTypeStringAfterName: Some(cb_get_type_string_after_name::<T>),
30 getTypeLines: Some(cb_get_type_lines::<T>),
31 printAllTypes: Some(cb_print_all_types::<T>),
32 freeTokens: Some(cb_free_tokens),
33 freeString: Some(cb_free_string),
34 freeLines: Some(cb_free_lines),
35 };
36 let raw_name = name.to_cstr();
37 let result = unsafe { BNRegisterTypePrinter(raw_name.as_ptr(), &mut callback) };
38 let core = unsafe { CoreTypePrinter::from_raw(NonNull::new(result).unwrap()) };
39 (parser, core)
40}
41
42#[repr(transparent)]
43pub struct CoreTypePrinter {
44 pub(crate) handle: NonNull<BNTypePrinter>,
45}
46
47impl CoreTypePrinter {
48 pub(crate) unsafe fn from_raw(handle: NonNull<BNTypePrinter>) -> CoreTypePrinter {
49 Self { handle }
50 }
51
52 pub fn printers() -> Array<CoreTypePrinter> {
53 let mut count = 0;
54 let result = unsafe { BNGetTypePrinterList(&mut count) };
55 assert!(!result.is_null());
56 unsafe { Array::new(result, count, ()) }
57 }
58
59 pub fn printer_by_name(name: &str) -> Option<CoreTypePrinter> {
60 let name_raw = name.to_cstr();
61 let result = unsafe { BNGetTypePrinterByName(name_raw.as_ptr()) };
62 NonNull::new(result).map(|x| unsafe { Self::from_raw(x) })
63 }
64
65 pub fn name(&self) -> String {
66 let result = unsafe { BNGetTypePrinterName(self.handle.as_ptr()) };
67 assert!(!result.is_null());
68 unsafe { BnString::into_string(result) }
69 }
70
71 pub fn get_type_tokens<T: Into<QualifiedName>>(
72 &self,
73 type_: &Type,
74 platform: &Platform,
75 name: T,
76 base_confidence: u8,
77 escaping: TokenEscapingType,
78 ) -> Option<Array<InstructionTextToken>> {
79 let mut result_count = 0;
80 let mut result = std::ptr::null_mut();
81 let mut raw_name = QualifiedName::into_raw(name.into());
82 let success = unsafe {
83 BNGetTypePrinterTypeTokens(
84 self.handle.as_ptr(),
85 type_.handle,
86 platform.handle,
87 &mut raw_name,
88 base_confidence,
89 escaping,
90 &mut result,
91 &mut result_count,
92 )
93 };
94 QualifiedName::free_raw(raw_name);
95 success.then(|| {
96 assert!(!result.is_null());
97 unsafe { Array::new(result, result_count, ()) }
98 })
99 }
100
101 pub fn get_type_tokens_before_name(
102 &self,
103 type_: &Type,
104 platform: &Platform,
105 base_confidence: u8,
106 parent_type: &Type,
107 escaping: TokenEscapingType,
108 ) -> Option<Array<InstructionTextToken>> {
109 let mut result_count = 0;
110 let mut result = std::ptr::null_mut();
111 let success = unsafe {
112 BNGetTypePrinterTypeTokensBeforeName(
113 self.handle.as_ptr(),
114 type_.handle,
115 platform.handle,
116 base_confidence,
117 parent_type.handle,
118 escaping,
119 &mut result,
120 &mut result_count,
121 )
122 };
123 success.then(|| {
124 assert!(!result.is_null());
125 unsafe { Array::new(result, result_count, ()) }
126 })
127 }
128
129 pub fn get_type_tokens_after_name(
130 &self,
131 type_: &Type,
132 platform: &Platform,
133 base_confidence: u8,
134 parent_type: &Type,
135 escaping: TokenEscapingType,
136 ) -> Option<Array<InstructionTextToken>> {
137 let mut result_count = 0;
138 let mut result = std::ptr::null_mut();
139 let success = unsafe {
140 BNGetTypePrinterTypeTokensAfterName(
141 self.handle.as_ptr(),
142 type_.handle,
143 platform.handle,
144 base_confidence,
145 parent_type.handle,
146 escaping,
147 &mut result,
148 &mut result_count,
149 )
150 };
151 success.then(|| {
152 assert!(!result.is_null());
153 unsafe { Array::new(result, result_count, ()) }
154 })
155 }
156
157 pub fn get_type_string<T: Into<QualifiedName>>(
158 &self,
159 type_: &Type,
160 platform: &Platform,
161 name: T,
162 escaping: TokenEscapingType,
163 ) -> Option<BnString> {
164 let mut result = std::ptr::null_mut();
165 let mut raw_name = QualifiedName::into_raw(name.into());
166 let success = unsafe {
167 BNGetTypePrinterTypeString(
168 self.handle.as_ptr(),
169 type_.handle,
170 platform.handle,
171 &mut raw_name,
172 escaping,
173 &mut result,
174 )
175 };
176 QualifiedName::free_raw(raw_name);
177 success.then(|| unsafe {
178 assert!(!result.is_null());
179 BnString::from_raw(result)
180 })
181 }
182
183 pub fn get_type_string_before_name(
184 &self,
185 type_: &Type,
186 platform: &Platform,
187 escaping: BNTokenEscapingType,
188 ) -> Option<BnString> {
189 let mut result = std::ptr::null_mut();
190 let success = unsafe {
191 BNGetTypePrinterTypeStringAfterName(
192 self.handle.as_ptr(),
193 type_.handle,
194 platform.handle,
195 escaping,
196 &mut result,
197 )
198 };
199 success.then(|| unsafe {
200 assert!(!result.is_null());
201 BnString::from_raw(result)
202 })
203 }
204
205 pub fn get_type_string_after_name(
206 &self,
207 type_: &Type,
208 platform: &Platform,
209 escaping: TokenEscapingType,
210 ) -> Option<BnString> {
211 let mut result = std::ptr::null_mut();
212 let success = unsafe {
213 BNGetTypePrinterTypeStringBeforeName(
214 self.handle.as_ptr(),
215 type_.handle,
216 platform.handle,
217 escaping,
218 &mut result,
219 )
220 };
221 success.then(|| unsafe {
222 assert!(!result.is_null());
223 BnString::from_raw(result)
224 })
225 }
226
227 pub fn get_type_lines<T: Into<QualifiedName>>(
228 &self,
229 type_: &Type,
230 types: &TypeContainer,
231 name: T,
232 padding_cols: isize,
233 collapsed: bool,
234 escaping: TokenEscapingType,
235 ) -> Option<Array<TypeDefinitionLine>> {
236 let mut result_count = 0;
237 let mut result = std::ptr::null_mut();
238 let mut raw_name = QualifiedName::into_raw(name.into());
239 let success = unsafe {
240 BNGetTypePrinterTypeLines(
241 self.handle.as_ptr(),
242 type_.handle,
243 types.handle.as_ptr(),
244 &mut raw_name,
245 padding_cols as c_int,
246 collapsed,
247 escaping,
248 &mut result,
249 &mut result_count,
250 )
251 };
252 QualifiedName::free_raw(raw_name);
253 success.then(|| {
254 assert!(!result.is_null());
255 unsafe { Array::<TypeDefinitionLine>::new(result, result_count, ()) }
256 })
257 }
258
259 pub fn default_print_all_types<T, I>(
266 &self,
267 types: T,
268 data: &BinaryView,
269 padding_cols: isize,
270 escaping: TokenEscapingType,
271 ) -> Option<BnString>
272 where
273 T: Iterator<Item = I>,
274 I: Into<QualifiedNameAndType>,
275 {
276 let mut result = std::ptr::null_mut();
277 let (mut raw_names, mut raw_types): (Vec<BNQualifiedName>, Vec<_>) = types
278 .map(|t| {
279 let t = t.into();
280 (
282 QualifiedName::into_raw(t.name),
283 unsafe { Ref::into_raw(t.ty) }.handle,
284 )
285 })
286 .unzip();
287 let success = unsafe {
288 BNTypePrinterDefaultPrintAllTypes(
289 self.handle.as_ptr(),
290 raw_names.as_mut_ptr(),
291 raw_types.as_mut_ptr(),
292 raw_types.len(),
293 data.handle,
294 padding_cols as c_int,
295 escaping,
296 &mut result,
297 )
298 };
299 for raw_name in raw_names {
300 QualifiedName::free_raw(raw_name);
301 }
302 for raw_type in raw_types {
303 let _ = unsafe { Type::ref_from_raw(raw_type) };
304 }
305 success.then(|| unsafe {
306 assert!(!result.is_null());
307 BnString::from_raw(result)
308 })
309 }
310
311 pub fn print_all_types<T, I>(
312 &self,
313 types: T,
314 data: &BinaryView,
315 padding_cols: isize,
316 escaping: TokenEscapingType,
317 ) -> Option<BnString>
318 where
319 T: IntoIterator<Item = I>,
320 I: Into<QualifiedNameAndType>,
321 {
322 let mut result = std::ptr::null_mut();
323 let (mut raw_names, mut raw_types): (Vec<BNQualifiedName>, Vec<_>) = types
325 .into_iter()
326 .map(|t| {
327 let t = t.into();
328 (
330 QualifiedName::into_raw(t.name),
331 unsafe { Ref::into_raw(t.ty) }.handle,
332 )
333 })
334 .unzip();
335 let success = unsafe {
336 BNTypePrinterPrintAllTypes(
337 self.handle.as_ptr(),
338 raw_names.as_mut_ptr(),
339 raw_types.as_mut_ptr(),
340 raw_types.len(),
341 data.handle,
343 padding_cols as c_int,
344 escaping,
345 &mut result,
346 )
347 };
348 for raw_name in raw_names {
349 QualifiedName::free_raw(raw_name);
350 }
351 for raw_type in raw_types {
352 let _ = unsafe { Type::ref_from_raw(raw_type) };
353 }
354 success.then(|| unsafe {
355 assert!(!result.is_null());
356 BnString::from_raw(result)
357 })
358 }
359}
360
361impl Default for CoreTypePrinter {
362 fn default() -> Self {
363 let default_settings = crate::settings::Settings::new();
365 let name = default_settings.get_string("analysis.types.printerName");
366 Self::printer_by_name(&name).unwrap()
367 }
368}
369
370impl CoreArrayProvider for CoreTypePrinter {
371 type Raw = *mut BNTypePrinter;
372 type Context = ();
373 type Wrapped<'a> = Self;
374}
375
376unsafe impl CoreArrayProviderInner for CoreTypePrinter {
377 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
378 BNFreeTypePrinterList(raw)
379 }
380
381 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
382 let handle = NonNull::new(*raw).unwrap();
384 CoreTypePrinter::from_raw(handle)
385 }
386}
387
388pub trait TypePrinter {
389 fn get_type_tokens<T: Into<QualifiedName>>(
398 &self,
399 type_: Ref<Type>,
400 platform: Option<Ref<Platform>>,
401 name: T,
402 base_confidence: u8,
403 escaping: TokenEscapingType,
404 ) -> Option<Vec<InstructionTextToken>>;
405
406 fn get_type_tokens_before_name(
416 &self,
417 type_: Ref<Type>,
418 platform: Option<Ref<Platform>>,
419 base_confidence: u8,
420 parent_type: Option<Ref<Type>>,
421 escaping: TokenEscapingType,
422 ) -> Option<Vec<InstructionTextToken>>;
423
424 fn get_type_tokens_after_name(
434 &self,
435 type_: Ref<Type>,
436 platform: Option<Ref<Platform>>,
437 base_confidence: u8,
438 parent_type: Option<Ref<Type>>,
439 escaping: TokenEscapingType,
440 ) -> Option<Vec<InstructionTextToken>>;
441
442 fn get_type_string<T: Into<QualifiedName>>(
450 &self,
451 type_: Ref<Type>,
452 platform: Option<Ref<Platform>>,
453 name: T,
454 escaping: TokenEscapingType,
455 ) -> Option<String>;
456
457 fn get_type_string_before_name(
465 &self,
466 type_: Ref<Type>,
467 platform: Option<Ref<Platform>>,
468 escaping: TokenEscapingType,
469 ) -> Option<String>;
470
471 fn get_type_string_after_name(
479 &self,
480 type_: Ref<Type>,
481 platform: Option<Ref<Platform>>,
482 escaping: TokenEscapingType,
483 ) -> Option<String>;
484
485 fn get_type_lines<T: Into<QualifiedName>>(
495 &self,
496 type_: Ref<Type>,
497 types: &TypeContainer,
498 name: T,
499 padding_cols: isize,
500 collapsed: bool,
501 escaping: TokenEscapingType,
502 ) -> Option<Vec<TypeDefinitionLine>>;
503
504 fn print_all_types(
512 &self,
513 names: Vec<QualifiedName>,
514 types: Vec<Ref<Type>>,
515 data: Ref<BinaryView>,
516 padding_cols: isize,
517 escaping: TokenEscapingType,
518 ) -> Option<String>;
519}
520
521#[derive(Clone)]
523pub struct TypeDefinitionLine {
524 pub line_type: TypeDefinitionLineType,
525 pub tokens: Vec<InstructionTextToken>,
526 pub ty: Ref<Type>,
527 pub parent_type: Option<Ref<Type>>,
528 pub root_type: Option<Ref<Type>>,
530 pub root_type_name: Option<String>,
531 pub base_type: Option<Ref<NamedTypeReference>>,
533 pub base_offset: u64,
535 pub offset: u64,
536 pub field_index: usize,
537}
538
539impl TypeDefinitionLine {
540 pub(crate) fn from_raw(value: &BNTypeDefinitionLine) -> Self {
541 Self {
542 line_type: value.lineType,
543 tokens: {
544 let raw_tokens = unsafe { std::slice::from_raw_parts(value.tokens, value.count) };
545 raw_tokens
546 .iter()
547 .map(InstructionTextToken::from_raw)
548 .collect()
549 },
550 ty: unsafe { Type::from_raw(value.type_).to_owned() },
551 parent_type: match value.parentType.is_null() {
552 false => Some(unsafe { Type::from_raw(value.parentType).to_owned() }),
553 true => None,
554 },
555 root_type: match value.rootType.is_null() {
556 false => Some(unsafe { Type::from_raw(value.rootType).to_owned() }),
557 true => None,
558 },
559 root_type_name: match value.rootTypeName.is_null() {
560 false => Some(raw_to_string(value.rootTypeName).unwrap()),
561 true => None,
562 },
563 base_type: match value.baseType.is_null() {
564 false => Some(unsafe { NamedTypeReference::from_raw(value.baseType).to_owned() }),
565 true => None,
566 },
567 base_offset: value.baseOffset,
568 offset: value.offset,
569 field_index: value.fieldIndex,
570 }
571 }
572
573 pub(crate) fn from_owned_raw(value: BNTypeDefinitionLine) -> Self {
575 let owned = Self::from_raw(&value);
576 Self::free_owned_raw(value);
577 owned
578 }
579
580 pub(crate) fn into_raw(value: Self) -> BNTypeDefinitionLine {
581 let tokens: Box<[BNInstructionTextToken]> = value
583 .tokens
584 .into_iter()
585 .map(InstructionTextToken::into_raw)
586 .collect();
587 BNTypeDefinitionLine {
588 lineType: value.line_type,
589 count: tokens.len(),
590 tokens: Box::leak(tokens).as_mut_ptr(),
592 type_: unsafe { Ref::into_raw(value.ty) }.handle,
594 parentType: value
596 .parent_type
597 .map(|t| unsafe { Ref::into_raw(t) }.handle)
598 .unwrap_or(std::ptr::null_mut()),
599 rootType: value
601 .root_type
602 .map(|t| unsafe { Ref::into_raw(t) }.handle)
603 .unwrap_or(std::ptr::null_mut()),
604 rootTypeName: value
606 .root_type_name
607 .map(|s| BnString::into_raw(BnString::new(s)))
608 .unwrap_or(std::ptr::null_mut()),
609 baseType: value
611 .base_type
612 .map(|t| unsafe { Ref::into_raw(t) }.handle)
613 .unwrap_or(std::ptr::null_mut()),
614 baseOffset: value.base_offset,
615 offset: value.offset,
616 fieldIndex: value.field_index,
617 }
618 }
619
620 pub(crate) fn free_owned_raw(raw: BNTypeDefinitionLine) {
622 if !raw.tokens.is_null() {
623 let tokens = std::ptr::slice_from_raw_parts_mut(raw.tokens, raw.count);
624 let boxed_tokens = unsafe { Box::from_raw(tokens) };
626 for token in boxed_tokens {
627 InstructionTextToken::free_raw(token);
628 }
629 }
630 if !raw.type_.is_null() {
631 let _ = unsafe { Type::ref_from_raw(raw.type_) };
633 }
634 if !raw.parentType.is_null() {
635 let _ = unsafe { Type::ref_from_raw(raw.parentType) };
637 }
638 if !raw.rootType.is_null() {
639 let _ = unsafe { Type::ref_from_raw(raw.rootType) };
641 }
642 if !raw.rootTypeName.is_null() {
643 let _ = unsafe { BnString::from_raw(raw.rootTypeName) };
645 }
646 if !raw.baseType.is_null() {
647 let _ = unsafe { NamedTypeReference::ref_from_raw(raw.baseType) };
649 }
650 }
651}
652
653impl CoreArrayProvider for TypeDefinitionLine {
654 type Raw = BNTypeDefinitionLine;
655 type Context = ();
656 type Wrapped<'a> = Self;
657}
658
659unsafe impl CoreArrayProviderInner for TypeDefinitionLine {
660 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
661 unsafe { BNFreeTypeDefinitionLineList(raw, count) };
662 }
663
664 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
665 Self::from_raw(raw)
666 }
667}
668
669unsafe extern "C" fn cb_get_type_tokens<T: TypePrinter>(
670 ctxt: *mut ::std::os::raw::c_void,
671 type_: *mut BNType,
672 platform: *mut BNPlatform,
673 name: *mut BNQualifiedName,
674 base_confidence: u8,
675 escaping: BNTokenEscapingType,
676 result: *mut *mut BNInstructionTextToken,
677 result_count: *mut usize,
678) -> bool {
679 let ctxt: &mut T = &mut *(ctxt as *mut T);
680 let qualified_name = QualifiedName::from_raw(&*name);
682 let inner_result = ctxt.get_type_tokens(
683 unsafe { Type::ref_from_raw(type_) },
684 match platform.is_null() {
685 false => Some(Platform::ref_from_raw(platform)),
686 true => None,
687 },
688 qualified_name,
689 base_confidence,
690 escaping,
691 );
692 if let Some(inner_result) = inner_result {
693 let raw_text_tokens: Box<[BNInstructionTextToken]> = inner_result
694 .into_iter()
695 .map(InstructionTextToken::into_raw)
696 .collect();
697 *result_count = raw_text_tokens.len();
698 *result = Box::leak(raw_text_tokens).as_mut_ptr();
700 true
701 } else {
702 *result = std::ptr::null_mut();
703 *result_count = 0;
704 false
705 }
706}
707
708unsafe extern "C" fn cb_get_type_tokens_before_name<T: TypePrinter>(
709 ctxt: *mut ::std::os::raw::c_void,
710 type_: *mut BNType,
711 platform: *mut BNPlatform,
712 base_confidence: u8,
713 parent_type: *mut BNType,
714 escaping: BNTokenEscapingType,
715 result: *mut *mut BNInstructionTextToken,
716 result_count: *mut usize,
717) -> bool {
718 let ctxt: &mut T = &mut *(ctxt as *mut T);
719 let inner_result = ctxt.get_type_tokens_before_name(
720 Type::ref_from_raw(type_),
721 match platform.is_null() {
722 false => Some(Platform::ref_from_raw(platform)),
723 true => None,
724 },
725 base_confidence,
726 match parent_type.is_null() {
727 false => Some(Type::ref_from_raw(parent_type)),
728 true => None,
729 },
730 escaping,
731 );
732 if let Some(inner_result) = inner_result {
733 let raw_text_tokens: Box<[BNInstructionTextToken]> = inner_result
734 .into_iter()
735 .map(InstructionTextToken::into_raw)
736 .collect();
737 *result_count = raw_text_tokens.len();
738 *result = Box::leak(raw_text_tokens).as_mut_ptr();
740 true
741 } else {
742 *result = std::ptr::null_mut();
743 *result_count = 0;
744 false
745 }
746}
747
748unsafe extern "C" fn cb_get_type_tokens_after_name<T: TypePrinter>(
749 ctxt: *mut ::std::os::raw::c_void,
750 type_: *mut BNType,
751 platform: *mut BNPlatform,
752 base_confidence: u8,
753 parent_type: *mut BNType,
754 escaping: BNTokenEscapingType,
755 result: *mut *mut BNInstructionTextToken,
756 result_count: *mut usize,
757) -> bool {
758 let ctxt: &mut T = &mut *(ctxt as *mut T);
759 let inner_result = ctxt.get_type_tokens_after_name(
760 Type::ref_from_raw(type_),
761 match platform.is_null() {
762 false => Some(Platform::ref_from_raw(platform)),
763 true => None,
764 },
765 base_confidence,
766 match parent_type.is_null() {
767 false => Some(Type::ref_from_raw(parent_type)),
768 true => None,
769 },
770 escaping,
771 );
772 if let Some(inner_result) = inner_result {
773 let raw_text_tokens: Box<[BNInstructionTextToken]> = inner_result
774 .into_iter()
775 .map(InstructionTextToken::into_raw)
776 .collect();
777 *result_count = raw_text_tokens.len();
778 *result = Box::leak(raw_text_tokens).as_mut_ptr();
780 true
781 } else {
782 *result = std::ptr::null_mut();
783 *result_count = 0;
784 false
785 }
786}
787
788unsafe extern "C" fn cb_get_type_string<T: TypePrinter>(
789 ctxt: *mut ::std::os::raw::c_void,
790 type_: *mut BNType,
791 platform: *mut BNPlatform,
792 name: *mut BNQualifiedName,
793 escaping: BNTokenEscapingType,
794 result: *mut *mut ::std::os::raw::c_char,
795) -> bool {
796 let ctxt: &mut T = &mut *(ctxt as *mut T);
797 let qualified_name = QualifiedName::from_raw(&*name);
799 let inner_result = ctxt.get_type_string(
800 Type::ref_from_raw(type_),
801 match platform.is_null() {
802 false => Some(Platform::ref_from_raw(platform)),
803 true => None,
804 },
805 qualified_name,
806 escaping,
807 );
808 if let Some(inner_result) = inner_result {
809 let raw_string = BnString::new(inner_result);
810 *result = BnString::into_raw(raw_string);
812 true
813 } else {
814 *result = std::ptr::null_mut();
815 false
816 }
817}
818
819unsafe extern "C" fn cb_get_type_string_before_name<T: TypePrinter>(
820 ctxt: *mut ::std::os::raw::c_void,
821 type_: *mut BNType,
822 platform: *mut BNPlatform,
823 escaping: BNTokenEscapingType,
824 result: *mut *mut ::std::os::raw::c_char,
825) -> bool {
826 let ctxt: &mut T = &mut *(ctxt as *mut T);
827 let inner_result = ctxt.get_type_string_before_name(
828 Type::ref_from_raw(type_),
829 match platform.is_null() {
830 false => Some(Platform::ref_from_raw(platform)),
831 true => None,
832 },
833 escaping,
834 );
835 if let Some(inner_result) = inner_result {
836 let raw_string = BnString::new(inner_result);
838 *result = BnString::into_raw(raw_string);
839 true
840 } else {
841 *result = std::ptr::null_mut();
842 false
843 }
844}
845
846unsafe extern "C" fn cb_get_type_string_after_name<T: TypePrinter>(
847 ctxt: *mut ::std::os::raw::c_void,
848 type_: *mut BNType,
849 platform: *mut BNPlatform,
850 escaping: BNTokenEscapingType,
851 result: *mut *mut ::std::os::raw::c_char,
852) -> bool {
853 let ctxt: &mut T = &mut *(ctxt as *mut T);
854 let inner_result = ctxt.get_type_string_after_name(
855 Type::ref_from_raw(type_),
856 match platform.is_null() {
857 false => Some(Platform::ref_from_raw(platform)),
858 true => None,
859 },
860 escaping,
861 );
862 if let Some(inner_result) = inner_result {
863 let raw_string = BnString::new(inner_result);
864 *result = BnString::into_raw(raw_string);
866 true
867 } else {
868 *result = std::ptr::null_mut();
869 false
870 }
871}
872
873unsafe extern "C" fn cb_get_type_lines<T: TypePrinter>(
874 ctxt: *mut ::std::os::raw::c_void,
875 type_: *mut BNType,
876 types: *mut BNTypeContainer,
877 name: *mut BNQualifiedName,
878 padding_cols: ::std::os::raw::c_int,
879 collapsed: bool,
880 escaping: BNTokenEscapingType,
881 result: *mut *mut BNTypeDefinitionLine,
882 result_count: *mut usize,
883) -> bool {
884 let ctxt: &mut T = &mut *(ctxt as *mut T);
885 let qualified_name = QualifiedName::from_raw(&*name);
887 let types_ptr = NonNull::new(types).unwrap();
888 let types = TypeContainer::from_raw(types_ptr);
889 let inner_result = ctxt.get_type_lines(
890 Type::ref_from_raw(type_),
891 &types,
892 qualified_name,
893 padding_cols as isize,
894 collapsed,
895 escaping,
896 );
897 if let Some(inner_result) = inner_result {
898 let boxed_raw_lines: Box<[_]> = inner_result
899 .into_iter()
900 .map(TypeDefinitionLine::into_raw)
901 .collect();
902 *result_count = boxed_raw_lines.len();
903 *result = Box::leak(boxed_raw_lines).as_mut_ptr();
905 true
906 } else {
907 *result = std::ptr::null_mut();
908 *result_count = 0;
909 false
910 }
911}
912
913unsafe extern "C" fn cb_print_all_types<T: TypePrinter>(
914 ctxt: *mut ::std::os::raw::c_void,
915 names: *mut BNQualifiedName,
916 types: *mut *mut BNType,
917 type_count: usize,
918 data: *mut BNBinaryView,
919 padding_cols: ::std::os::raw::c_int,
920 escaping: BNTokenEscapingType,
921 result: *mut *mut ::std::os::raw::c_char,
922) -> bool {
923 let ctxt: &mut T = &mut *(ctxt as *mut T);
924 let raw_names = std::slice::from_raw_parts(names, type_count);
925 let names: Vec<_> = raw_names.iter().map(QualifiedName::from_raw).collect();
927 let raw_types = std::slice::from_raw_parts(types, type_count);
928 let types: Vec<_> = raw_types.iter().map(|&t| Type::ref_from_raw(t)).collect();
930 let inner_result = ctxt.print_all_types(
931 names,
932 types,
933 BinaryView::ref_from_raw(data),
934 padding_cols as isize,
935 escaping,
936 );
937 if let Some(inner_result) = inner_result {
938 let raw_string = BnString::new(inner_result);
939 *result = BnString::into_raw(raw_string);
941 true
942 } else {
943 *result = std::ptr::null_mut();
944 false
945 }
946}
947
948unsafe extern "C" fn cb_free_string(_ctxt: *mut c_void, string: *mut c_char) {
949 BnString::free_raw(string);
951}
952
953unsafe extern "C" fn cb_free_tokens(
954 _ctxt: *mut ::std::os::raw::c_void,
955 tokens: *mut BNInstructionTextToken,
956 count: usize,
957) {
958 let tokens = std::ptr::slice_from_raw_parts_mut(tokens, count);
959 let boxed_tokens = Box::from_raw(tokens);
961 for token in boxed_tokens {
962 InstructionTextToken::free_raw(token);
963 }
964}
965
966unsafe extern "C" fn cb_free_lines(
967 _ctxt: *mut ::std::os::raw::c_void,
968 lines: *mut BNTypeDefinitionLine,
969 count: usize,
970) {
971 let lines = std::ptr::slice_from_raw_parts_mut(lines, count);
972 let boxes_lines = Box::from_raw(lines);
974 for line in boxes_lines {
975 TypeDefinitionLine::free_owned_raw(line);
976 }
977}