binaryninja/types/
parser.rs

1#![allow(unused)]
2use binaryninjacore_sys::*;
3use std::ffi::{c_char, c_void};
4use std::fmt::Debug;
5use std::path::PathBuf;
6use std::ptr::NonNull;
7
8use crate::platform::Platform;
9use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref};
10use crate::string::{raw_to_string, BnString, IntoCStr};
11use crate::types::{QualifiedName, QualifiedNameAndType, Type, TypeContainer};
12
13pub type TypeParserErrorSeverity = BNTypeParserErrorSeverity;
14pub type TypeParserOption = BNTypeParserOption;
15
16/// Register a custom parser with the API
17pub fn register_type_parser<T: TypeParser>(
18    name: &str,
19    parser: T,
20) -> (&'static mut T, CoreTypeParser) {
21    let parser = Box::leak(Box::new(parser));
22    let mut callback = BNTypeParserCallbacks {
23        context: parser as *mut _ as *mut c_void,
24        getOptionText: Some(cb_get_option_text::<T>),
25        preprocessSource: Some(cb_preprocess_source::<T>),
26        parseTypesFromSource: Some(cb_parse_types_from_source::<T>),
27        parseTypeString: Some(cb_parse_type_string::<T>),
28        freeString: Some(cb_free_string),
29        freeResult: Some(cb_free_result),
30        freeErrorList: Some(cb_free_error_list),
31    };
32    let name = name.to_cstr();
33    let result = unsafe { BNRegisterTypeParser(name.as_ptr(), &mut callback) };
34    let core = unsafe { CoreTypeParser::from_raw(NonNull::new(result).unwrap()) };
35    (parser, core)
36}
37
38#[repr(transparent)]
39pub struct CoreTypeParser {
40    pub(crate) handle: NonNull<BNTypeParser>,
41}
42
43impl CoreTypeParser {
44    pub(crate) unsafe fn from_raw(handle: NonNull<BNTypeParser>) -> Self {
45        Self { handle }
46    }
47
48    pub fn parsers() -> Array<CoreTypeParser> {
49        let mut count = 0;
50        let result = unsafe { BNGetTypeParserList(&mut count) };
51        unsafe { Array::new(result, count, ()) }
52    }
53
54    pub fn parser_by_name(name: &str) -> Option<CoreTypeParser> {
55        let name_raw = name.to_cstr();
56        let result = unsafe { BNGetTypeParserByName(name_raw.as_ptr()) };
57        NonNull::new(result).map(|x| unsafe { Self::from_raw(x) })
58    }
59
60    pub fn name(&self) -> String {
61        let result = unsafe { BNGetTypeParserName(self.handle.as_ptr()) };
62        assert!(!result.is_null());
63        unsafe { BnString::into_string(result) }
64    }
65}
66
67impl TypeParser for CoreTypeParser {
68    fn get_option_text(&self, option: TypeParserOption, value: &str) -> Option<String> {
69        let mut output = std::ptr::null_mut();
70        let value_ptr = std::ptr::null_mut();
71        let result = unsafe {
72            BNGetTypeParserOptionText(self.handle.as_ptr(), option, value_ptr, &mut output)
73        };
74        result.then(|| {
75            assert!(!output.is_null());
76            unsafe { BnString::into_string(value_ptr) }
77        })
78    }
79
80    fn preprocess_source(
81        &self,
82        source: &str,
83        file_name: &str,
84        platform: &Platform,
85        existing_types: &TypeContainer,
86        options: &[String],
87        include_directories: &[PathBuf],
88    ) -> Result<String, Vec<TypeParserError>> {
89        let source_cstr = BnString::new(source);
90        let file_name_cstr = BnString::new(file_name);
91        let options: Vec<_> = options.iter().map(|o| o.to_cstr()).collect();
92        let options_raw: Vec<*const c_char> = options.iter().map(|o| o.as_ptr()).collect();
93        let include_directories: Vec<_> = include_directories
94            .iter()
95            .map(|d| d.clone().to_cstr())
96            .collect();
97        let include_directories_raw: Vec<*const c_char> =
98            include_directories.iter().map(|d| d.as_ptr()).collect();
99        let mut result = std::ptr::null_mut();
100        let mut errors = std::ptr::null_mut();
101        let mut error_count = 0;
102        let success = unsafe {
103            BNTypeParserPreprocessSource(
104                self.handle.as_ptr(),
105                source_cstr.as_ptr(),
106                file_name_cstr.as_ptr(),
107                platform.handle,
108                existing_types.handle.as_ptr(),
109                options_raw.as_ptr(),
110                options_raw.len(),
111                include_directories_raw.as_ptr(),
112                include_directories_raw.len(),
113                &mut result,
114                &mut errors,
115                &mut error_count,
116            )
117        };
118        if success {
119            assert!(!result.is_null());
120            let bn_result = unsafe { BnString::into_string(result) };
121            Ok(bn_result)
122        } else {
123            let errors: Array<TypeParserError> = unsafe { Array::new(errors, error_count, ()) };
124            Err(errors.to_vec())
125        }
126    }
127
128    fn parse_types_from_source(
129        &self,
130        source: &str,
131        file_name: &str,
132        platform: &Platform,
133        existing_types: &TypeContainer,
134        options: &[String],
135        include_directories: &[PathBuf],
136        auto_type_source: &str,
137    ) -> Result<TypeParserResult, Vec<TypeParserError>> {
138        let source_cstr = BnString::new(source);
139        let file_name_cstr = BnString::new(file_name);
140        let options: Vec<_> = options.iter().map(|o| o.to_cstr()).collect();
141        let options_raw: Vec<*const c_char> = options.iter().map(|o| o.as_ptr()).collect();
142        let include_directories: Vec<_> = include_directories
143            .iter()
144            .map(|d| d.clone().to_cstr())
145            .collect();
146        let include_directories_raw: Vec<*const c_char> =
147            include_directories.iter().map(|d| d.as_ptr()).collect();
148        let auto_type_source = BnString::new(auto_type_source);
149        let mut raw_result = BNTypeParserResult::default();
150        let mut errors = std::ptr::null_mut();
151        let mut error_count = 0;
152        let success = unsafe {
153            BNTypeParserParseTypesFromSource(
154                self.handle.as_ptr(),
155                source_cstr.as_ptr(),
156                file_name_cstr.as_ptr(),
157                platform.handle,
158                existing_types.handle.as_ptr(),
159                options_raw.as_ptr(),
160                options_raw.len(),
161                include_directories_raw.as_ptr(),
162                include_directories_raw.len(),
163                auto_type_source.as_ptr(),
164                &mut raw_result,
165                &mut errors,
166                &mut error_count,
167            )
168        };
169        if success {
170            let result = TypeParserResult::from_raw(&raw_result);
171            // NOTE: This is safe because the core allocated the TypeParserResult
172            TypeParserResult::free_raw(raw_result);
173            Ok(result)
174        } else {
175            let errors: Array<TypeParserError> = unsafe { Array::new(errors, error_count, ()) };
176            Err(errors.to_vec())
177        }
178    }
179
180    fn parse_type_string(
181        &self,
182        source: &str,
183        platform: &Platform,
184        existing_types: &TypeContainer,
185    ) -> Result<QualifiedNameAndType, Vec<TypeParserError>> {
186        let source_cstr = BnString::new(source);
187        let mut output = BNQualifiedNameAndType::default();
188        let mut errors = std::ptr::null_mut();
189        let mut error_count = 0;
190        let result = unsafe {
191            BNTypeParserParseTypeString(
192                self.handle.as_ptr(),
193                source_cstr.as_ptr(),
194                platform.handle,
195                existing_types.handle.as_ptr(),
196                &mut output,
197                &mut errors,
198                &mut error_count,
199            )
200        };
201        if result {
202            Ok(QualifiedNameAndType::from_owned_raw(output))
203        } else {
204            let errors: Array<TypeParserError> = unsafe { Array::new(errors, error_count, ()) };
205            Err(errors.to_vec())
206        }
207    }
208}
209
210impl Default for CoreTypeParser {
211    fn default() -> Self {
212        // TODO: This should return a ref
213        unsafe { Self::from_raw(NonNull::new(BNGetDefaultTypeParser()).unwrap()) }
214    }
215}
216
217// TODO: Impl this on platform.
218pub trait TypeParser {
219    /// Get the string representation of an option for passing to parse_type_*.
220    /// Returns a string representing the option if the parser supports it,
221    /// otherwise None
222    ///
223    /// * `option` - Option type
224    /// * `value` - Option value
225    fn get_option_text(&self, option: TypeParserOption, value: &str) -> Option<String>;
226
227    /// Preprocess a block of source, returning the source that would be parsed
228    ///
229    /// * `source` - Source code to process
230    /// * `file_name` - Name of the file containing the source (does not need to exist on disk)
231    /// * `platform` - Platform to assume the source is relevant to
232    /// * `existing_types` - Optional collection of all existing types to use for parsing context
233    /// * `options` - Optional string arguments to pass as options, e.g. command line arguments
234    /// * `include_dirs` - Optional list of directories to include in the header search path
235    fn preprocess_source(
236        &self,
237        source: &str,
238        file_name: &str,
239        platform: &Platform,
240        existing_types: &TypeContainer,
241        options: &[String],
242        include_dirs: &[PathBuf],
243    ) -> Result<String, Vec<TypeParserError>>;
244
245    /// Parse an entire block of source into types, variables, and functions
246    ///
247    /// * `source` - Source code to parse
248    /// * `file_name` - Name of the file containing the source (optional: exists on disk)
249    /// * `platform` - Platform to assume the types are relevant to
250    /// * `existing_types` - Optional container of all existing types to use for parsing context
251    /// * `options` - Optional string arguments to pass as options, e.g. command line arguments
252    /// * `include_dirs` - Optional list of directories to include in the header search path
253    /// * `auto_type_source` - Optional source of types if used for automatically generated types
254    fn parse_types_from_source(
255        &self,
256        source: &str,
257        file_name: &str,
258        platform: &Platform,
259        existing_types: &TypeContainer,
260        options: &[String],
261        include_dirs: &[PathBuf],
262        auto_type_source: &str,
263    ) -> Result<TypeParserResult, Vec<TypeParserError>>;
264
265    /// Parse a single type and name from a string containing their definition.
266    ///
267    /// * `source` - Source code to parse
268    /// * `platform` - Platform to assume the types are relevant to
269    /// * `existing_types` - Optional container of all existing types to use for parsing context
270    fn parse_type_string(
271        &self,
272        source: &str,
273        platform: &Platform,
274        existing_types: &TypeContainer,
275    ) -> Result<QualifiedNameAndType, Vec<TypeParserError>>;
276}
277
278impl CoreArrayProvider for CoreTypeParser {
279    type Raw = *mut BNTypeParser;
280    type Context = ();
281    type Wrapped<'a> = Self;
282}
283
284unsafe impl CoreArrayProviderInner for CoreTypeParser {
285    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
286        BNFreeTypeParserList(raw)
287    }
288
289    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
290        // TODO: Because handle is a NonNull we should prob make Self::Raw that as well...
291        let handle = NonNull::new(*raw).unwrap();
292        CoreTypeParser::from_raw(handle)
293    }
294}
295
296#[derive(Clone, Debug, Eq, PartialEq)]
297pub struct TypeParserError {
298    pub severity: TypeParserErrorSeverity,
299    pub message: String,
300    pub file_name: String,
301    pub line: u64,
302    pub column: u64,
303}
304
305impl TypeParserError {
306    pub(crate) fn from_raw(value: &BNTypeParserError) -> Self {
307        Self {
308            severity: value.severity,
309            message: raw_to_string(value.message).unwrap(),
310            file_name: raw_to_string(value.fileName).unwrap(),
311            line: value.line,
312            column: value.column,
313        }
314    }
315
316    pub(crate) fn from_owned_raw(value: BNTypeParserError) -> Self {
317        let owned = Self::from_raw(&value);
318        Self::free_raw(value);
319        owned
320    }
321
322    pub(crate) fn into_raw(value: Self) -> BNTypeParserError {
323        BNTypeParserError {
324            severity: value.severity,
325            message: BnString::into_raw(BnString::new(value.message)),
326            fileName: BnString::into_raw(BnString::new(value.file_name)),
327            line: value.line,
328            column: value.column,
329        }
330    }
331
332    pub(crate) fn free_raw(value: BNTypeParserError) {
333        unsafe { BnString::free_raw(value.message) };
334        unsafe { BnString::free_raw(value.fileName) };
335    }
336
337    pub fn new(
338        severity: TypeParserErrorSeverity,
339        message: String,
340        file_name: String,
341        line: u64,
342        column: u64,
343    ) -> Self {
344        Self {
345            severity,
346            message,
347            file_name,
348            line,
349            column,
350        }
351    }
352}
353
354impl CoreArrayProvider for TypeParserError {
355    type Raw = BNTypeParserError;
356    type Context = ();
357    type Wrapped<'a> = Self;
358}
359
360unsafe impl CoreArrayProviderInner for TypeParserError {
361    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
362        unsafe { BNFreeTypeParserErrors(raw, count) }
363    }
364
365    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
366        Self::from_raw(raw)
367    }
368}
369
370#[derive(Debug, Eq, PartialEq, Default)]
371pub struct TypeParserResult {
372    pub types: Vec<ParsedType>,
373    pub variables: Vec<ParsedType>,
374    pub functions: Vec<ParsedType>,
375}
376
377impl TypeParserResult {
378    pub(crate) fn from_raw(value: &BNTypeParserResult) -> Self {
379        let raw_types = unsafe { std::slice::from_raw_parts(value.types, value.typeCount) };
380        let types = raw_types.iter().map(ParsedType::from_raw).collect();
381        let raw_variables =
382            unsafe { std::slice::from_raw_parts(value.variables, value.variableCount) };
383        let variables = raw_variables.iter().map(ParsedType::from_raw).collect();
384        let raw_functions =
385            unsafe { std::slice::from_raw_parts(value.functions, value.functionCount) };
386        let functions = raw_functions.iter().map(ParsedType::from_raw).collect();
387        TypeParserResult {
388            types,
389            variables,
390            functions,
391        }
392    }
393
394    /// Return a rust allocated type parser result, free using [`Self::free_owned_raw`].
395    ///
396    /// Under no circumstance should you call [`Self::free_raw`] on the returned result.
397    pub(crate) fn into_raw(value: Self) -> BNTypeParserResult {
398        let boxed_raw_types: Box<[BNParsedType]> = value
399            .types
400            .into_iter()
401            // NOTE: Freed with [`Self::free_owned_raw`].
402            .map(ParsedType::into_raw)
403            .collect();
404        let boxed_raw_variables: Box<[BNParsedType]> = value
405            .variables
406            .into_iter()
407            // NOTE: Freed with [`Self::free_owned_raw`].
408            .map(ParsedType::into_raw)
409            .collect();
410        let boxed_raw_functions: Box<[BNParsedType]> = value
411            .functions
412            .into_iter()
413            // NOTE: Freed with [`Self::free_owned_raw`].
414            .map(ParsedType::into_raw)
415            .collect();
416        BNTypeParserResult {
417            typeCount: boxed_raw_types.len(),
418            // NOTE: Freed with [`Self::free_owned_raw`].
419            types: Box::leak(boxed_raw_types).as_mut_ptr(),
420            variableCount: boxed_raw_variables.len(),
421            // NOTE: Freed with [`Self::free_owned_raw`].
422            variables: Box::leak(boxed_raw_variables).as_mut_ptr(),
423            functionCount: boxed_raw_functions.len(),
424            // NOTE: Freed with [`Self::free_owned_raw`].
425            functions: Box::leak(boxed_raw_functions).as_mut_ptr(),
426        }
427    }
428
429    pub(crate) fn free_raw(mut value: BNTypeParserResult) {
430        // SAFETY: `value` must be a properly initialized BNTypeParserResult.
431        // SAFETY: `value` must be core allocated.
432        unsafe { BNFreeTypeParserResult(&mut value) };
433    }
434
435    pub(crate) fn free_owned_raw(value: BNTypeParserResult) {
436        let raw_types = std::ptr::slice_from_raw_parts_mut(value.types, value.typeCount);
437        // Free the rust allocated types list
438        let boxed_types = unsafe { Box::from_raw(raw_types) };
439        for parsed_type in boxed_types {
440            ParsedType::free_raw(parsed_type);
441        }
442        let raw_variables =
443            std::ptr::slice_from_raw_parts_mut(value.variables, value.variableCount);
444        // Free the rust allocated variables list
445        let boxed_variables = unsafe { Box::from_raw(raw_variables) };
446        for parsed_type in boxed_variables {
447            ParsedType::free_raw(parsed_type);
448        }
449        let raw_functions =
450            std::ptr::slice_from_raw_parts_mut(value.functions, value.functionCount);
451        // Free the rust allocated functions list
452        let boxed_functions = unsafe { Box::from_raw(raw_functions) };
453        for parsed_type in boxed_functions {
454            ParsedType::free_raw(parsed_type);
455        }
456    }
457}
458
459#[derive(Debug, Clone, Eq, PartialEq)]
460pub struct ParsedType {
461    pub name: QualifiedName,
462    pub ty: Ref<Type>,
463    pub user: bool,
464}
465
466impl ParsedType {
467    pub(crate) fn from_raw(value: &BNParsedType) -> Self {
468        Self {
469            name: QualifiedName::from_raw(&value.name),
470            ty: unsafe { Type::from_raw(value.type_).to_owned() },
471            user: value.isUser,
472        }
473    }
474
475    pub(crate) fn from_owned_raw(value: BNParsedType) -> Self {
476        let owned = Self::from_raw(&value);
477        Self::free_raw(value);
478        owned
479    }
480
481    pub(crate) fn into_raw(value: Self) -> BNParsedType {
482        BNParsedType {
483            name: QualifiedName::into_raw(value.name),
484            type_: unsafe { Ref::into_raw(value.ty) }.handle,
485            isUser: value.user,
486        }
487    }
488
489    pub(crate) fn free_raw(value: BNParsedType) {
490        QualifiedName::free_raw(value.name);
491        let _ = unsafe { Type::ref_from_raw(value.type_) };
492    }
493
494    pub fn new(name: QualifiedName, ty: Ref<Type>, user: bool) -> Self {
495        Self { name, ty, user }
496    }
497}
498
499impl CoreArrayProvider for ParsedType {
500    type Raw = BNParsedType;
501    type Context = ();
502    type Wrapped<'b> = Self;
503}
504
505unsafe impl CoreArrayProviderInner for ParsedType {
506    unsafe fn free(_raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
507        // Expected to be freed with BNFreeTypeParserResult
508        // TODO ^ because of the above, we should not provide an array provider for this
509    }
510
511    unsafe fn wrap_raw<'b>(raw: &'b Self::Raw, _context: &'b Self::Context) -> Self::Wrapped<'b> {
512        ParsedType::from_raw(raw)
513    }
514}
515
516unsafe extern "C" fn cb_get_option_text<T: TypeParser>(
517    ctxt: *mut ::std::os::raw::c_void,
518    option: BNTypeParserOption,
519    value: *const c_char,
520    result: *mut *mut c_char,
521) -> bool {
522    let ctxt: &mut T = &mut *(ctxt as *mut T);
523    if let Some(inner_result) = ctxt.get_option_text(option, &raw_to_string(value).unwrap()) {
524        let bn_inner_result = BnString::new(inner_result);
525        // NOTE: Dropped by `cb_free_string`
526        *result = BnString::into_raw(bn_inner_result);
527        true
528    } else {
529        *result = std::ptr::null_mut();
530        false
531    }
532}
533
534unsafe extern "C" fn cb_preprocess_source<T: TypeParser>(
535    ctxt: *mut c_void,
536    source: *const c_char,
537    file_name: *const c_char,
538    platform: *mut BNPlatform,
539    existing_types: *mut BNTypeContainer,
540    options: *const *const c_char,
541    option_count: usize,
542    include_dirs: *const *const c_char,
543    include_dir_count: usize,
544    result: *mut *mut c_char,
545    errors: *mut *mut BNTypeParserError,
546    error_count: *mut usize,
547) -> bool {
548    let ctxt: &mut T = &mut *(ctxt as *mut T);
549    let platform = Platform { handle: platform };
550    let existing_types_ptr = NonNull::new(existing_types).unwrap();
551    let existing_types = TypeContainer::from_raw(existing_types_ptr);
552    let options_raw = unsafe { std::slice::from_raw_parts(options, option_count) };
553    let options: Vec<_> = options_raw
554        .iter()
555        .filter_map(|&r| raw_to_string(r))
556        .collect();
557    let includes_raw = unsafe { std::slice::from_raw_parts(include_dirs, include_dir_count) };
558    let includes: Vec<_> = includes_raw
559        .iter()
560        .filter_map(|&r| Some(PathBuf::from(raw_to_string(r)?)))
561        .collect();
562    match ctxt.preprocess_source(
563        &raw_to_string(source).unwrap(),
564        &raw_to_string(file_name).unwrap(),
565        &platform,
566        &existing_types,
567        &options,
568        &includes,
569    ) {
570        Ok(inner_result) => {
571            let bn_inner_result = BnString::new(inner_result);
572            // NOTE: Dropped by `cb_free_string`
573            *result = BnString::into_raw(bn_inner_result);
574            *errors = std::ptr::null_mut();
575            *error_count = 0;
576            true
577        }
578        Err(inner_errors) => {
579            *result = std::ptr::null_mut();
580            *error_count = inner_errors.len();
581            // NOTE: Leaking errors here, dropped by `cb_free_error_list`.
582            let inner_errors: Box<[_]> = inner_errors
583                .into_iter()
584                .map(TypeParserError::into_raw)
585                .collect();
586            // NOTE: Dropped by `cb_free_error_list`
587            *errors = Box::leak(inner_errors).as_mut_ptr();
588            false
589        }
590    }
591}
592
593unsafe extern "C" fn cb_parse_types_from_source<T: TypeParser>(
594    ctxt: *mut c_void,
595    source: *const c_char,
596    file_name: *const c_char,
597    platform: *mut BNPlatform,
598    existing_types: *mut BNTypeContainer,
599    options: *const *const c_char,
600    option_count: usize,
601    include_dirs: *const *const c_char,
602    include_dir_count: usize,
603    auto_type_source: *const c_char,
604    result: *mut BNTypeParserResult,
605    errors: *mut *mut BNTypeParserError,
606    error_count: *mut usize,
607) -> bool {
608    let ctxt: &mut T = &mut *(ctxt as *mut T);
609    let platform = Platform { handle: platform };
610    let existing_types_ptr = NonNull::new(existing_types).unwrap();
611    let existing_types = TypeContainer::from_raw(existing_types_ptr);
612    let options_raw = unsafe { std::slice::from_raw_parts(options, option_count) };
613    let options: Vec<_> = options_raw
614        .iter()
615        .filter_map(|&r| raw_to_string(r))
616        .collect();
617    let includes_raw = unsafe { std::slice::from_raw_parts(include_dirs, include_dir_count) };
618    let includes: Vec<_> = includes_raw
619        .iter()
620        .filter_map(|&r| Some(PathBuf::from(raw_to_string(r)?)))
621        .collect();
622    match ctxt.parse_types_from_source(
623        &raw_to_string(source).unwrap(),
624        &raw_to_string(file_name).unwrap(),
625        &platform,
626        &existing_types,
627        &options,
628        &includes,
629        &raw_to_string(auto_type_source).unwrap(),
630    ) {
631        Ok(type_parser_result) => {
632            *result = TypeParserResult::into_raw(type_parser_result);
633            *errors = std::ptr::null_mut();
634            *error_count = 0;
635            true
636        }
637        Err(inner_errors) => {
638            *error_count = inner_errors.len();
639            let inner_errors: Box<[_]> = inner_errors
640                .into_iter()
641                .map(TypeParserError::into_raw)
642                .collect();
643            *result = Default::default();
644            // NOTE: Dropped by cb_free_error_list
645            *errors = Box::leak(inner_errors).as_mut_ptr();
646            false
647        }
648    }
649}
650
651unsafe extern "C" fn cb_parse_type_string<T: TypeParser>(
652    ctxt: *mut c_void,
653    source: *const c_char,
654    platform: *mut BNPlatform,
655    existing_types: *mut BNTypeContainer,
656    result: *mut BNQualifiedNameAndType,
657    errors: *mut *mut BNTypeParserError,
658    error_count: *mut usize,
659) -> bool {
660    let ctxt: &mut T = &mut *(ctxt as *mut T);
661    let platform = Platform { handle: platform };
662    let existing_types_ptr = NonNull::new(existing_types).unwrap();
663    let existing_types = TypeContainer::from_raw(existing_types_ptr);
664    match ctxt.parse_type_string(&raw_to_string(source).unwrap(), &platform, &existing_types) {
665        Ok(inner_result) => {
666            *result = QualifiedNameAndType::into_raw(inner_result);
667            *errors = std::ptr::null_mut();
668            *error_count = 0;
669            true
670        }
671        Err(inner_errors) => {
672            *error_count = inner_errors.len();
673            let inner_errors: Box<[_]> = inner_errors
674                .into_iter()
675                .map(TypeParserError::into_raw)
676                .collect();
677            *result = Default::default();
678            // NOTE: Dropped by cb_free_error_list
679            *errors = Box::leak(inner_errors).as_mut_ptr();
680            false
681        }
682    }
683}
684
685unsafe extern "C" fn cb_free_string(_ctxt: *mut c_void, string: *mut c_char) {
686    // SAFETY: The returned string is just BnString
687    BnString::free_raw(string);
688}
689
690unsafe extern "C" fn cb_free_result(_ctxt: *mut c_void, result: *mut BNTypeParserResult) {
691    TypeParserResult::free_owned_raw(*result);
692}
693
694unsafe extern "C" fn cb_free_error_list(
695    _ctxt: *mut c_void,
696    errors: *mut BNTypeParserError,
697    error_count: usize,
698) {
699    let errors = std::ptr::slice_from_raw_parts_mut(errors, error_count);
700    let boxed_errors = Box::from_raw(errors);
701    for error in boxed_errors {
702        TypeParserError::free_raw(error);
703    }
704}