@@ -13,6 +13,7 @@ pub type TypeParserErrorSeverity = BNTypeParserErrorSeverity;
1313pub type TypeParserOption = BNTypeParserOption ;
1414pub type TokenEscapingType = BNTokenEscapingType ;
1515pub type TypeDefinitionLineType = BNTypeDefinitionLineType ;
16+ pub type TypeContainerType = BNTypeContainerType ;
1617
1718#[ repr( transparent) ]
1819pub struct CoreTypeParser {
@@ -279,6 +280,17 @@ unsafe impl CoreArrayProviderInner for CoreTypeParser {
279280 }
280281}
281282
283+ /// A `TypeContainer` is a generic interface to access various Binary Ninja models
284+ /// that contain types. Types are stored with both a unique id and a unique name.
285+ // ///
286+ // /// The `TypeContainer` class should not generally be instantiated directly. Instances
287+ // /// can be retrieved from the following properties and methods in the API:
288+ // /// * [BinaryView::type_container]
289+ // /// * [BinaryView::auto_type_container]
290+ // /// * [BinaryView::user_type_container]
291+ // /// * [Platform::type_container]
292+ // /// * [TypeLibrary::type_container]
293+ // /// * [DebugInfo::get_type_container]
282294#[ repr( transparent) ]
283295pub struct TypeContainer {
284296 handle : ptr:: NonNull < BNTypeContainer > ,
@@ -298,6 +310,340 @@ impl TypeContainer {
298310 pub ( crate ) unsafe fn as_raw ( & self ) -> & mut BNTypeContainer {
299311 & mut * self . handle . as_ptr ( )
300312 }
313+
314+ /// Get an id string for the Type Container. This will be unique within a given
315+ /// analysis session, but may not be globally unique.
316+ pub fn id ( & self ) -> BnString {
317+ let result = unsafe { BNTypeContainerGetId ( self . as_raw ( ) ) } ;
318+ assert ! ( !result. is_null( ) ) ;
319+ unsafe { BnString :: from_raw ( result) }
320+ }
321+
322+ /// Get a user-friendly name for the Type Container.
323+ pub fn name ( & self ) -> BnString {
324+ let result = unsafe { BNTypeContainerGetName ( self . as_raw ( ) ) } ;
325+ assert ! ( !result. is_null( ) ) ;
326+ unsafe { BnString :: from_raw ( result) }
327+ }
328+
329+ /// Get the type of underlying model the Type Container is accessing.
330+ pub fn container_type ( & self ) -> TypeContainerType {
331+ unsafe { BNTypeContainerGetType ( self . as_raw ( ) ) }
332+ }
333+
334+ /// Test if the Type Container supports mutable operations (add, rename, delete)
335+ pub fn is_mutable ( & self ) -> bool {
336+ unsafe { BNTypeContainerIsMutable ( self . as_raw ( ) ) }
337+ }
338+
339+ /// Get the Platform object associated with this Type Container. All Type Containers
340+ /// have exactly one associated Platform (as opposed to, e.g. Type Libraries).
341+ pub fn platform ( & self ) -> Ref < Platform > {
342+ let result = unsafe { BNTypeContainerGetPlatform ( self . as_raw ( ) ) } ;
343+ assert ! ( !result. is_null( ) ) ;
344+ unsafe { Platform :: ref_from_raw ( result) }
345+ }
346+
347+ /// Add or update types to a Type Container. If the Type Container already contains
348+ /// a type with the same name as a type being added, the existing type will be
349+ /// replaced with the definition given to this function, and references will be
350+ /// updated in the source model.
351+ pub fn add_types < I > ( & self , types : I ) -> bool
352+ where
353+ I : IntoIterator < Item = ( QualifiedName , Ref < Type > ) > ,
354+ {
355+ let ( names, types) : ( Vec < QualifiedName > , Vec < Ref < Type > > ) = types. into_iter ( ) . unzip ( ) ;
356+
357+ // SAFETY QualifiedName is transparent with BNQualifiedName
358+ let names_raw: & [ BNQualifiedName ] = unsafe { mem:: transmute ( names. as_slice ( ) ) } ;
359+
360+ let mut types_raw: Vec < * mut BNType > = types. iter ( ) . map ( |t| t. handle ) . collect ( ) ;
361+
362+ let mut result_names = ptr:: null_mut ( ) ;
363+ let mut result_ids = ptr:: null_mut ( ) ;
364+ let mut result_count = 0 ;
365+ unsafe {
366+ BNTypeContainerAddTypes (
367+ self . as_raw ( ) ,
368+ names_raw. as_ptr ( ) ,
369+ types_raw. as_mut_ptr ( ) ,
370+ types. len ( ) ,
371+ Some ( cb_progress_nop) ,
372+ ptr:: null_mut ( ) ,
373+ & mut result_names,
374+ & mut result_ids,
375+ & mut result_count,
376+ )
377+ }
378+ }
379+
380+ pub fn add_types_with_progress < I , F > ( & self , types : I , mut progress : F ) -> bool
381+ where
382+ I : IntoIterator < Item = ( QualifiedName , Ref < Type > ) > ,
383+ F : FnMut ( usize , usize ) -> bool ,
384+ {
385+ let ( names, types) : ( Vec < QualifiedName > , Vec < Ref < Type > > ) = types. into_iter ( ) . unzip ( ) ;
386+
387+ // SAFETY QualifiedName is transparent with BNQualifiedName
388+ let names_raw: & [ BNQualifiedName ] = unsafe { mem:: transmute ( names. as_slice ( ) ) } ;
389+
390+ let mut types_raw: Vec < * mut BNType > = types. iter ( ) . map ( |t| t. handle ) . collect ( ) ;
391+
392+ let mut result_names = ptr:: null_mut ( ) ;
393+ let mut result_ids = ptr:: null_mut ( ) ;
394+ let mut result_count = 0 ;
395+ unsafe {
396+ BNTypeContainerAddTypes (
397+ self . as_raw ( ) ,
398+ names_raw. as_ptr ( ) ,
399+ types_raw. as_mut_ptr ( ) ,
400+ types. len ( ) ,
401+ Some ( cb_progress :: < F > ) ,
402+ & mut progress as * mut F as * mut ffi:: c_void ,
403+ & mut result_names,
404+ & mut result_ids,
405+ & mut result_count,
406+ )
407+ }
408+ }
409+
410+ /// Rename a type in the Type Container. All references to this type will be updated
411+ /// (by id) to use the new name.
412+ pub fn rename_type < S : BnStrCompatible > ( & self , name : & QualifiedName , type_id : S ) -> bool {
413+ let type_id = type_id. into_bytes_with_nul ( ) ;
414+ unsafe {
415+ BNTypeContainerRenameType (
416+ self . as_raw ( ) ,
417+ type_id. as_ref ( ) . as_ptr ( ) as * const ffi:: c_char ,
418+ & name. 0 ,
419+ )
420+ }
421+ }
422+
423+ /// Delete a type in the Type Container. Behavior of references to this type is
424+ /// not specified and you may end up with broken references if any still exist.
425+ pub fn delete_type < S : BnStrCompatible > ( & self , type_id : S ) -> bool {
426+ let type_id = type_id. into_bytes_with_nul ( ) ;
427+ unsafe {
428+ BNTypeContainerDeleteType (
429+ self . as_raw ( ) ,
430+ type_id. as_ref ( ) . as_ptr ( ) as * const ffi:: c_char ,
431+ )
432+ }
433+ }
434+
435+ /// Get the unique id of the type in the Type Container with the given name.
436+ /// If no type with that name exists, returns None.
437+ pub fn type_id ( & self , type_name : & QualifiedName ) -> Option < BnString > {
438+ let mut result = ptr:: null_mut ( ) ;
439+ let success = unsafe { BNTypeContainerGetTypeId ( self . as_raw ( ) , & type_name. 0 , & mut result) } ;
440+ success. then ( || unsafe { BnString :: from_raw ( result) } )
441+ }
442+
443+ /// Get the unique name of the type in the Type Container with the given id.
444+ /// If no type with that id exists, returns None.
445+ pub fn type_name < S : BnStrCompatible > ( & self , type_id : S ) -> Option < QualifiedName > {
446+ let type_id = type_id. into_bytes_with_nul ( ) ;
447+ let mut result = BNQualifiedName :: default ( ) ;
448+ let success = unsafe {
449+ BNTypeContainerGetTypeName (
450+ self . as_raw ( ) ,
451+ type_id. as_ref ( ) . as_ptr ( ) as * const ffi:: c_char ,
452+ & mut result,
453+ )
454+ } ;
455+ success. then ( || QualifiedName ( result) )
456+ }
457+
458+ /// Get the definition of the type in the Type Container with the given id.
459+ /// If no type with that id exists, returns None.
460+ pub fn type_by_id < S : BnStrCompatible > ( & self , type_id : S ) -> Option < Ref < Type > > {
461+ let type_id = type_id. into_bytes_with_nul ( ) ;
462+ let mut result = ptr:: null_mut ( ) ;
463+ let success = unsafe {
464+ BNTypeContainerGetTypeById (
465+ self . as_raw ( ) ,
466+ type_id. as_ref ( ) . as_ptr ( ) as * const ffi:: c_char ,
467+ & mut result,
468+ )
469+ } ;
470+ success. then ( || unsafe { Type :: ref_from_raw ( result) } )
471+ }
472+
473+ /// Get the definition of the type in the Type Container with the given name.
474+ /// If no type with that name exists, returns None.
475+ pub fn type_by_name ( & self , type_name : & QualifiedName ) -> Option < Ref < Type > > {
476+ let mut result = ptr:: null_mut ( ) ;
477+ let success =
478+ unsafe { BNTypeContainerGetTypeByName ( self . as_raw ( ) , & type_name. 0 , & mut result) } ;
479+ success. then ( || unsafe { Type :: ref_from_raw ( result) } )
480+ }
481+
482+ /// Get a mapping of all types in a Type Container.
483+ pub fn types ( & self ) -> Option < ( Array < Type > , Array < QualifiedName > , Array < BnString > ) > {
484+ let mut type_ids = ptr:: null_mut ( ) ;
485+ let mut type_names = ptr:: null_mut ( ) ;
486+ let mut type_types = ptr:: null_mut ( ) ;
487+ let mut type_count = 0 ;
488+ let success = unsafe {
489+ BNTypeContainerGetTypes (
490+ self . as_raw ( ) ,
491+ & mut type_ids,
492+ & mut type_names,
493+ & mut type_types,
494+ & mut type_count,
495+ )
496+ } ;
497+ success. then ( || unsafe {
498+ let ids = Array :: new ( type_ids, type_count, ( ) ) ;
499+ let names = Array :: new ( type_names, type_count, ( ) ) ;
500+ let types = Array :: new ( type_types, type_count, ( ) ) ;
501+ ( types, names, ids)
502+ } )
503+ }
504+
505+ /// Get all type ids in a Type Container.
506+ pub fn type_ids ( & self ) -> Option < Array < BnString > > {
507+ let mut type_ids = ptr:: null_mut ( ) ;
508+ let mut type_count = 0 ;
509+ let success =
510+ unsafe { BNTypeContainerGetTypeIds ( self . as_raw ( ) , & mut type_ids, & mut type_count) } ;
511+ success. then ( || unsafe { Array :: new ( type_ids, type_count, ( ) ) } )
512+ }
513+
514+ /// Get all type names in a Type Container.
515+ pub fn type_names ( & self ) -> Option < Array < QualifiedName > > {
516+ let mut type_ids = ptr:: null_mut ( ) ;
517+ let mut type_count = 0 ;
518+ let success =
519+ unsafe { BNTypeContainerGetTypeNames ( self . as_raw ( ) , & mut type_ids, & mut type_count) } ;
520+ success. then ( || unsafe { Array :: new ( type_ids, type_count, ( ) ) } )
521+ }
522+
523+ /// Get a mapping of all type ids and type names in a Type Container.
524+ pub fn type_names_and_ids ( & self ) -> Option < ( Array < BnString > , Array < QualifiedName > ) > {
525+ let mut type_ids = ptr:: null_mut ( ) ;
526+ let mut type_names = ptr:: null_mut ( ) ;
527+ let mut type_count = 0 ;
528+ let success = unsafe {
529+ BNTypeContainerGetTypeNamesAndIds (
530+ self . as_raw ( ) ,
531+ & mut type_ids,
532+ & mut type_names,
533+ & mut type_count,
534+ )
535+ } ;
536+ success. then ( || unsafe {
537+ let ids = Array :: new ( type_ids, type_count, ( ) ) ;
538+ let names = Array :: new ( type_names, type_count, ( ) ) ;
539+ ( ids, names)
540+ } )
541+ }
542+
543+ /// Parse a single type and name from a string containing their definition, with
544+ /// knowledge of the types in the Type Container.
545+ ///
546+ /// * `source` - Source code to parse
547+ /// * `import_dependencies` - If Type Library / Type Archive types should be imported during parsing
548+ pub fn parse_type_string < S : BnStrCompatible > (
549+ & self ,
550+ source : S ,
551+ import_dependencies : bool ,
552+ ) -> Result < QualifiedNameAndType , Array < TypeParserError > > {
553+ let source = source. into_bytes_with_nul ( ) ;
554+ let mut result = BNQualifiedNameAndType :: default ( ) ;
555+ let mut errors = ptr:: null_mut ( ) ;
556+ let mut error_count = 0 ;
557+ let success = unsafe {
558+ BNTypeContainerParseTypeString (
559+ self . as_raw ( ) ,
560+ source. as_ref ( ) . as_ptr ( ) as * const ffi:: c_char ,
561+ import_dependencies,
562+ & mut result,
563+ & mut errors,
564+ & mut error_count,
565+ )
566+ } ;
567+ if success {
568+ Ok ( QualifiedNameAndType ( result) )
569+ } else {
570+ assert ! ( !errors. is_null( ) ) ;
571+ Err ( unsafe { Array :: new ( errors, error_count, ( ) ) } )
572+ }
573+ }
574+
575+ /// Parse an entire block of source into types, variables, and functions, with
576+ /// knowledge of the types in the Type Container.
577+
578+ /// * `source` - Source code to parse
579+ /// * `file_name` - Name of the file containing the source (optional: exists on disk)
580+ /// * `options` - String arguments to pass as options, e.g. command line arguments
581+ /// * `include_dirs` - List of directories to include in the header search path
582+ /// * `auto_type_source` - Source of types if used for automatically generated types
583+ /// * `import_dependencies` - If Type Library / Type Archive types should be imported during parsing
584+ pub fn parse_types_from_source < S , F , O , D , A > (
585+ & self ,
586+ source : S ,
587+ filename : F ,
588+ options : O ,
589+ include_directories : D ,
590+ auto_type_source : A ,
591+ import_dependencies : bool ,
592+ ) -> Result < TypeParserResult , Array < TypeParserError > >
593+ where
594+ S : BnStrCompatible ,
595+ F : BnStrCompatible ,
596+ O : IntoIterator ,
597+ O :: Item : BnStrCompatible ,
598+ D : IntoIterator ,
599+ D :: Item : BnStrCompatible ,
600+ A : BnStrCompatible ,
601+ {
602+ let source = source. into_bytes_with_nul ( ) ;
603+ let filename = filename. into_bytes_with_nul ( ) ;
604+ let options: Vec < _ > = options
605+ . into_iter ( )
606+ . map ( |o| o. into_bytes_with_nul ( ) )
607+ . collect ( ) ;
608+ let options_raw: Vec < * const ffi:: c_char > = options
609+ . iter ( )
610+ . map ( |o| o. as_ref ( ) . as_ptr ( ) as * const ffi:: c_char )
611+ . collect ( ) ;
612+ let include_directories: Vec < _ > = include_directories
613+ . into_iter ( )
614+ . map ( |d| d. into_bytes_with_nul ( ) )
615+ . collect ( ) ;
616+ let include_directories_raw: Vec < * const ffi:: c_char > = include_directories
617+ . iter ( )
618+ . map ( |d| d. as_ref ( ) . as_ptr ( ) as * const ffi:: c_char )
619+ . collect ( ) ;
620+ let auto_type_source = auto_type_source. into_bytes_with_nul ( ) ;
621+ let mut result = BNTypeParserResult :: default ( ) ;
622+ let mut errors = ptr:: null_mut ( ) ;
623+ let mut error_count = 0 ;
624+ let success = unsafe {
625+ BNTypeContainerParseTypesFromSource (
626+ self . as_raw ( ) ,
627+ source. as_ref ( ) . as_ptr ( ) as * const ffi:: c_char ,
628+ filename. as_ref ( ) . as_ptr ( ) as * const ffi:: c_char ,
629+ options_raw. as_ptr ( ) ,
630+ options_raw. len ( ) ,
631+ include_directories_raw. as_ptr ( ) ,
632+ include_directories_raw. len ( ) ,
633+ auto_type_source. as_ref ( ) . as_ptr ( ) as * const ffi:: c_char ,
634+ import_dependencies,
635+ & mut result,
636+ & mut errors,
637+ & mut error_count,
638+ )
639+ } ;
640+ if success {
641+ Ok ( unsafe { TypeParserResult :: from_raw ( result) } )
642+ } else {
643+ assert ! ( !errors. is_null( ) ) ;
644+ Err ( unsafe { Array :: new ( errors, error_count, ( ) ) } )
645+ }
646+ }
301647}
302648
303649impl Drop for TypeContainer {
@@ -1583,6 +1929,23 @@ unsafe extern "C" fn cb_print_all_types<T: TypePrinter>(
15831929 }
15841930}
15851931
1932+ unsafe extern "C" fn cb_progress_nop (
1933+ _ctxt : * mut :: std:: os:: raw:: c_void ,
1934+ _progress : usize ,
1935+ _total : usize ,
1936+ ) -> bool {
1937+ true
1938+ }
1939+
1940+ unsafe extern "C" fn cb_progress < F : FnMut ( usize , usize ) -> bool > (
1941+ ctxt : * mut :: std:: os:: raw:: c_void ,
1942+ progress : usize ,
1943+ total : usize ,
1944+ ) -> bool {
1945+ let ctxt = & mut * ( ctxt as * mut F ) ;
1946+ ctxt ( progress, total)
1947+ }
1948+
15861949unsafe extern "C" fn cb_free_tokens (
15871950 _ctxt : * mut :: std:: os:: raw:: c_void ,
15881951 tokens : * mut BNInstructionTextToken ,
0 commit comments