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::type_container::TypeContainer;
9use crate::types::{NamedTypeReference, QualifiedName, QualifiedNameAndType, Type};
10use binaryninjacore_sys::*;
11use std::ffi::{c_char, c_int, c_void};
12use std::ptr::NonNull;
13
14pub type TokenEscapingType = BNTokenEscapingType;
15pub type TypeDefinitionLineType = BNTypeDefinitionLineType;
16
17pub fn register_type_printer<T: TypePrinter>(
19 name: &str,
20 parser: T,
21) -> (&'static mut T, CoreTypePrinter) {
22 let parser = Box::leak(Box::new(parser));
23 let mut callback = BNTypePrinterCallbacks {
24 context: parser as *mut _ as *mut c_void,
25 getTypeTokens: Some(cb_get_type_tokens::<T>),
26 getTypeTokensBeforeName: Some(cb_get_type_tokens_before_name::<T>),
27 getTypeTokensAfterName: Some(cb_get_type_tokens_after_name::<T>),
28 getTypeString: Some(cb_get_type_string::<T>),
29 getTypeStringBeforeName: Some(cb_get_type_string_before_name::<T>),
30 getTypeStringAfterName: Some(cb_get_type_string_after_name::<T>),
31 getTypeLines: Some(cb_get_type_lines::<T>),
32 printAllTypes: Some(cb_print_all_types::<T>),
33 freeTokens: Some(cb_free_tokens),
34 freeString: Some(cb_free_string),
35 freeLines: Some(cb_free_lines),
36 };
37 let raw_name = name.to_cstr();
38 let result = unsafe { BNRegisterTypePrinter(raw_name.as_ptr(), &mut callback) };
39 let core = unsafe { CoreTypePrinter::from_raw(NonNull::new(result).unwrap()) };
40 (parser, core)
41}
42
43#[repr(transparent)]
44pub struct CoreTypePrinter {
45 pub(crate) handle: NonNull<BNTypePrinter>,
46}
47
48impl CoreTypePrinter {
49 pub(crate) unsafe fn from_raw(handle: NonNull<BNTypePrinter>) -> CoreTypePrinter {
50 Self { handle }
51 }
52
53 pub fn printers() -> Array<CoreTypePrinter> {
54 let mut count = 0;
55 let result = unsafe { BNGetTypePrinterList(&mut count) };
56 assert!(!result.is_null());
57 unsafe { Array::new(result, count, ()) }
58 }
59
60 pub fn printer_by_name(name: &str) -> Option<CoreTypePrinter> {
61 let name_raw = name.to_cstr();
62 let result = unsafe { BNGetTypePrinterByName(name_raw.as_ptr()) };
63 NonNull::new(result).map(|x| unsafe { Self::from_raw(x) })
64 }
65
66 pub fn name(&self) -> String {
67 let result = unsafe { BNGetTypePrinterName(self.handle.as_ptr()) };
68 assert!(!result.is_null());
69 unsafe { BnString::into_string(result) }
70 }
71
72 pub fn get_type_tokens<T: Into<QualifiedName>>(
73 &self,
74 type_: &Type,
75 platform: &Platform,
76 name: T,
77 base_confidence: u8,
78 escaping: TokenEscapingType,
79 ) -> Option<Array<InstructionTextToken>> {
80 let mut result_count = 0;
81 let mut result = std::ptr::null_mut();
82 let mut raw_name = QualifiedName::into_raw(name.into());
83 let success = unsafe {
84 BNGetTypePrinterTypeTokens(
85 self.handle.as_ptr(),
86 type_.handle,
87 platform.handle,
88 &mut raw_name,
89 base_confidence,
90 escaping,
91 &mut result,
92 &mut result_count,
93 )
94 };
95 QualifiedName::free_raw(raw_name);
96 success.then(|| {
97 assert!(!result.is_null());
98 unsafe { Array::new(result, result_count, ()) }
99 })
100 }
101
102 pub fn get_type_tokens_before_name(
103 &self,
104 type_: &Type,
105 platform: &Platform,
106 base_confidence: u8,
107 parent_type: &Type,
108 escaping: TokenEscapingType,
109 ) -> Option<Array<InstructionTextToken>> {
110 let mut result_count = 0;
111 let mut result = std::ptr::null_mut();
112 let success = unsafe {
113 BNGetTypePrinterTypeTokensBeforeName(
114 self.handle.as_ptr(),
115 type_.handle,
116 platform.handle,
117 base_confidence,
118 parent_type.handle,
119 escaping,
120 &mut result,
121 &mut result_count,
122 )
123 };
124 success.then(|| {
125 assert!(!result.is_null());
126 unsafe { Array::new(result, result_count, ()) }
127 })
128 }
129
130 pub fn get_type_tokens_after_name(
131 &self,
132 type_: &Type,
133 platform: &Platform,
134 base_confidence: u8,
135 parent_type: &Type,
136 escaping: TokenEscapingType,
137 ) -> Option<Array<InstructionTextToken>> {
138 let mut result_count = 0;
139 let mut result = std::ptr::null_mut();
140 let success = unsafe {
141 BNGetTypePrinterTypeTokensAfterName(
142 self.handle.as_ptr(),
143 type_.handle,
144 platform.handle,
145 base_confidence,
146 parent_type.handle,
147 escaping,
148 &mut result,
149 &mut result_count,
150 )
151 };
152 success.then(|| {
153 assert!(!result.is_null());
154 unsafe { Array::new(result, result_count, ()) }
155 })
156 }
157
158 pub fn get_type_string<T: Into<QualifiedName>>(
159 &self,
160 type_: &Type,
161 platform: &Platform,
162 name: T,
163 escaping: TokenEscapingType,
164 ) -> Option<BnString> {
165 let mut result = std::ptr::null_mut();
166 let mut raw_name = QualifiedName::into_raw(name.into());
167 let success = unsafe {
168 BNGetTypePrinterTypeString(
169 self.handle.as_ptr(),
170 type_.handle,
171 platform.handle,
172 &mut raw_name,
173 escaping,
174 &mut result,
175 )
176 };
177 QualifiedName::free_raw(raw_name);
178 success.then(|| unsafe {
179 assert!(!result.is_null());
180 BnString::from_raw(result)
181 })
182 }
183
184 pub fn get_type_string_before_name(
185 &self,
186 type_: &Type,
187 platform: &Platform,
188 escaping: BNTokenEscapingType,
189 ) -> Option<BnString> {
190 let mut result = std::ptr::null_mut();
191 let success = unsafe {
192 BNGetTypePrinterTypeStringAfterName(
193 self.handle.as_ptr(),
194 type_.handle,
195 platform.handle,
196 escaping,
197 &mut result,
198 )
199 };
200 success.then(|| unsafe {
201 assert!(!result.is_null());
202 BnString::from_raw(result)
203 })
204 }
205
206 pub fn get_type_string_after_name(
207 &self,
208 type_: &Type,
209 platform: &Platform,
210 escaping: TokenEscapingType,
211 ) -> Option<BnString> {
212 let mut result = std::ptr::null_mut();
213 let success = unsafe {
214 BNGetTypePrinterTypeStringBeforeName(
215 self.handle.as_ptr(),
216 type_.handle,
217 platform.handle,
218 escaping,
219 &mut result,
220 )
221 };
222 success.then(|| unsafe {
223 assert!(!result.is_null());
224 BnString::from_raw(result)
225 })
226 }
227
228 pub fn get_type_lines<T: Into<QualifiedName>>(
229 &self,
230 type_: &Type,
231 types: &TypeContainer,
232 name: T,
233 padding_cols: isize,
234 collapsed: bool,
235 escaping: TokenEscapingType,
236 ) -> Option<Array<TypeDefinitionLine>> {
237 let mut result_count = 0;
238 let mut result = std::ptr::null_mut();
239 let mut raw_name = QualifiedName::into_raw(name.into());
240 let success = unsafe {
241 BNGetTypePrinterTypeLines(
242 self.handle.as_ptr(),
243 type_.handle,
244 types.handle.as_ptr(),
245 &mut raw_name,
246 padding_cols as c_int,
247 collapsed,
248 escaping,
249 &mut result,
250 &mut result_count,
251 )
252 };
253 QualifiedName::free_raw(raw_name);
254 success.then(|| {
255 assert!(!result.is_null());
256 unsafe { Array::<TypeDefinitionLine>::new(result, result_count, ()) }
257 })
258 }
259
260 pub fn default_print_all_types<T, I>(
267 &self,
268 types: T,
269 data: &BinaryView,
270 padding_cols: isize,
271 escaping: TokenEscapingType,
272 ) -> Option<BnString>
273 where
274 T: Iterator<Item = I>,
275 I: Into<QualifiedNameAndType>,
276 {
277 let mut result = std::ptr::null_mut();
278 let (mut raw_names, mut raw_types): (Vec<BNQualifiedName>, Vec<_>) = types
279 .map(|t| {
280 let t = t.into();
281 (
283 QualifiedName::into_raw(t.name),
284 unsafe { Ref::into_raw(t.ty) }.handle,
285 )
286 })
287 .unzip();
288 let success = unsafe {
289 BNTypePrinterDefaultPrintAllTypes(
290 self.handle.as_ptr(),
291 raw_names.as_mut_ptr(),
292 raw_types.as_mut_ptr(),
293 raw_types.len(),
294 data.handle,
295 padding_cols as c_int,
296 escaping,
297 &mut result,
298 )
299 };
300 for raw_name in raw_names {
301 QualifiedName::free_raw(raw_name);
302 }
303 for raw_type in raw_types {
304 let _ = unsafe { Type::ref_from_raw(raw_type) };
305 }
306 success.then(|| unsafe {
307 assert!(!result.is_null());
308 BnString::from_raw(result)
309 })
310 }
311
312 pub fn print_all_types<T, I>(
313 &self,
314 types: T,
315 data: &BinaryView,
316 padding_cols: isize,
317 escaping: TokenEscapingType,
318 ) -> Option<BnString>
319 where
320 T: IntoIterator<Item = I>,
321 I: Into<QualifiedNameAndType>,
322 {
323 let mut result = std::ptr::null_mut();
324 let (mut raw_names, mut raw_types): (Vec<BNQualifiedName>, Vec<_>) = types
326 .into_iter()
327 .map(|t| {
328 let t = t.into();
329 (
331 QualifiedName::into_raw(t.name),
332 unsafe { Ref::into_raw(t.ty) }.handle,
333 )
334 })
335 .unzip();
336 let success = unsafe {
337 BNTypePrinterPrintAllTypes(
338 self.handle.as_ptr(),
339 raw_names.as_mut_ptr(),
340 raw_types.as_mut_ptr(),
341 raw_types.len(),
342 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}