diff options
| author | Glenn Smith <glenn@vector35.com> | 2023-11-01 17:03:17 -0400 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2024-02-07 17:23:49 -0500 |
| commit | 8037455723546000448135499957273623776581 (patch) | |
| tree | 268322ef34d16e067210df592dd782d50f294e3c /python/typearchive.py | |
| parent | e1542ed05f3f8c273206bb9ead8d39fea87430bb (diff) | |
Type Archives
Diffstat (limited to 'python/typearchive.py')
| -rw-r--r-- | python/typearchive.py | 758 |
1 files changed, 758 insertions, 0 deletions
diff --git a/python/typearchive.py b/python/typearchive.py new file mode 100644 index 00000000..c4e94a5e --- /dev/null +++ b/python/typearchive.py @@ -0,0 +1,758 @@ +# Copyright (c) 2015-2023 Vector 35 Inc +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import ctypes +import traceback +from typing import Optional, List, Dict, Union, Tuple + +# Binary Ninja components +import binaryninja +from . import _binaryninjacore as core +from . import types as ty_ +from . import log +from . import metadata +from . import databuffer +from . import platform +from . import architecture +from . import binaryview + + +class TypeArchive: + def __init__(self, handle: core.BNTypeArchiveHandle): + binaryninja._init_plugins() + self.handle: core.BNTypeArchiveHandle = core.handle_of_type(handle, core.BNTypeArchive) + self._notifications = {} + + def __hash__(self): + return hash(ctypes.addressof(self.handle.contents)) + + def __del__(self): + if core is not None: + core.BNFreeTypeArchiveReference(self.handle) + + def __repr__(self): + return f"<type archive '{self.path}'>" + + def __eq__(self, other): + if not isinstance(other, TypeArchive): + return False + return self.id == other.id + + @staticmethod + def open(path: str) -> Optional['TypeArchive']: + """ + Open the Type Archive at the given path, if it exists. + :param path: Path to Type Archive file + :return: Type Archive, or None if it could not be loaded. + """ + handle = core.BNOpenTypeArchive(path) + if handle is None: + return None + return TypeArchive(handle=handle) + + @staticmethod + def create(path: str, platform: 'platform.Platform') -> Optional['TypeArchive']: + """ + Create a Type Archive at the given path. + :param path: Path to Type Archive file + :param platform: Relevant platform for types in the archive + :return: Type Archive, or None if it could not be created. + """ + handle = core.BNCreateTypeArchive(path, platform.handle) + if handle is None: + return None + return TypeArchive(handle=handle) + + @staticmethod + def lookup_by_id(id: str) -> Optional['TypeArchive']: + """ + Get a reference to the Type Archive with the known id, if one exists. + :param id: Type Archive id + :return: Type archive, or None if it could not be found. + """ + handle = core.BNLookupTypeArchiveById(id) + if handle is None: + return None + return TypeArchive(handle=handle) + + @property + def path(self) -> Optional[str]: + """ + Get the path to the Type Archive's file + :return: File path + """ + return core.BNGetTypeArchivePath(self.handle) + + @property + def id(self) -> Optional[str]: + """ + Get the guid for a Type Archive + :return: Guid string + """ + return core.BNGetTypeArchiveId(self.handle) + + @property + def platform(self) -> 'platform.Platform': + """ + Get the associated Platform for a Type Archive + :return: Platform object + """ + handle = core.BNGetTypeArchivePlatform(self.handle) + assert handle is not None + return platform.Platform(handle=handle) + + @property + def current_snapshot_id(self) -> str: + """ + Get the id of the current snapshot in the type archive + :return: Snapshot id + """ + result = core.BNGetTypeArchiveCurrentSnapshotId(self.handle) + if result is None: + raise RuntimeError("BNGetTypeArchiveCurrentSnapshotId") + return result + + @current_snapshot_id.setter + def current_snapshot_id(self, value: str): + """ + Revert the type archive's current snapshot to the given snapshot + :param value: Snapshot id + """ + core.BNSetTypeArchiveCurrentSnapshot(self.handle, value) + + @property + def all_snapshot_ids(self) -> List[str]: + """ + Get a list of every snapshot's id + :return: All ids (including the empty first snapshot) + """ + count = ctypes.c_ulonglong(0) + ids = core.BNGetTypeArchiveAllSnapshotIds(self.handle, count) + if ids is None: + raise RuntimeError("BNGetTypeArchiveAllSnapshotIds") + result = [] + try: + for i in range(0, count.value): + result.append(core.pyNativeStr(ids[i])) + return result + finally: + core.BNFreeStringList(ids, count.value) + + def get_snapshot_parent_ids(self, snapshot: str) -> Optional[List[str]]: + """ + Get the ids of the parents to the given snapshot + :param snapshot: Child snapshot id + :return: Parent snapshot ids, or empty list if the snapshot is a root + """ + count = ctypes.c_size_t(0) + ids = core.BNGetTypeArchiveSnapshotParentIds(self.handle, snapshot, count) + if ids is None: + raise RuntimeError("BNGetTypeArchiveSnapshotParentIds") + result = [] + try: + for i in range(0, count.value): + result.append(core.pyNativeStr(ids[i])) + return result + finally: + core.BNFreeStringList(ids, count.value) + + def get_snapshot_child_ids(self, snapshot: str) -> Optional[List[str]]: + """ + Get the ids of the children to the given snapshot + :param snapshot: Parent snapshot id + :return: Child snapshot ids, or empty list if the snapshot is a root + """ + count = ctypes.c_size_t(0) + ids = core.BNGetTypeArchiveSnapshotChildIds(self.handle, snapshot, count) + if ids is None: + raise RuntimeError("BNGetTypeArchiveSnapshotChildIds") + result = [] + try: + for i in range(0, count.value): + result.append(core.pyNativeStr(ids[i])) + return result + finally: + core.BNFreeStringList(ids, count.value) + + def add_type(self, name: 'ty_.QualifiedNameType', type: 'ty_.Type') -> None: + """ + Add named types to the type archive. Type must have all dependant named types added + prior to being added, or this function will fail. + If the type already exists, it will be overwritten. + :param name: Name of new type + :param type: Definition of new type + """ + self.add_types([(name, type)]) + + def add_types(self, new_types: List[Tuple['ty_.QualifiedNameType', 'ty_.Type']]) -> None: + """ + Add named types to the type archive. Types must have all dependant named + types prior to being added, or this function will fail. + Types already existing with any added names will be overwritten. + :param new_types: Names and definitions of new types + """ + api_types = (core.BNQualifiedNameAndType * len(new_types))() + i = 0 + for (name, type) in new_types: + if not isinstance(name, ty_.QualifiedName): + name = ty_.QualifiedName(name) + type = type.immutable_copy() + if not isinstance(type, ty_.Type): + raise ValueError("parameter type must be a Type") + api_types[i].name = name._to_core_struct() + api_types[i].type = type.handle + i += 1 + + if not core.BNAddTypeArchiveTypes(self.handle, api_types, len(new_types)): + raise RuntimeError("BNAddTypeArchiveTypes") + + def rename_type(self, old_name: 'ty_.QualifiedNameType', new_name: 'ty_.QualifiedNameType') -> None: + """ + Change the name of an existing type in the type archive. + :param old_name: Old type name in archive + :param new_name: New type name + """ + id = self.get_type_id(old_name) + return self.rename_type_by_id(id, new_name) + + def rename_type_by_id(self, id: str, new_name: 'ty_.QualifiedNameType') -> None: + """ + Change the name of an existing type in the type archive. + :param id: Old id of type in archive + :param new_name: New type name + """ + if not isinstance(new_name, ty_.QualifiedName): + new_name = ty_.QualifiedName(new_name) + if not core.BNRenameTypeArchiveType(self.handle, id, new_name._to_core_struct()): + raise RuntimeError("BNRenameTypeArchiveType") + + def delete_type(self, name: 'ty_.QualifiedNameType') -> None: + """ + Delete an existing type in the type archive. + :param name: Type name + """ + id = self.get_type_id(name) + if id is None: + raise RuntimeError(f"Unknown type {name}") + self.delete_type_by_id(id) + + def delete_type_by_id(self, id: str) -> None: + """ + Delete an existing type in the type archive. + :param id: Type id + """ + if not core.BNDeleteTypeArchiveType(self.handle, id): + raise RuntimeError("BNDeleteTypeArchiveType") + + def get_type_by_name(self, name: 'ty_.QualifiedNameType', snapshot: Optional[str] = None) -> Optional[ty_.Type]: + """ + Retrieve a stored type in the archive + :param name: Type name + :param snapshot: Snapshot id to search for types, or None to search the latest snapshot + :return: Type, if it exists. Otherwise None + """ + if snapshot is None: + snapshot = self.current_snapshot_id + if not isinstance(name, ty_.QualifiedName): + name = ty_.QualifiedName(name) + t = core.BNGetTypeArchiveTypeByName(self.handle, name._to_core_struct(), snapshot) + if t is None: + return None + return ty_.Type.create(t) + + def get_type_by_id(self, id: str, snapshot: Optional[str] = None) -> Optional[ty_.Type]: + """ + Retrieve a stored type in the archive by id + :param id: Type id + :param snapshot: Snapshot id to search for types, or None to search the latest snapshot + :return: Type, if it exists. Otherwise None + """ + if snapshot is None: + snapshot = self.current_snapshot_id + assert id is not None + t = core.BNGetTypeArchiveTypeById(self.handle, id, snapshot) + if t is None: + return None + return ty_.Type.create(t) + + def get_type_name_by_id(self, id: str, snapshot: Optional[str] = None) -> Optional['ty_.QualifiedName']: + """ + Retrieve a type's name by its id + :param id: Type id + :param snapshot: Snapshot id to search for types, or None to search the latest snapshot + :return: Type name, if it exists. Otherwise None + """ + if snapshot is None: + snapshot = self.current_snapshot_id + assert id is not None + name = core.BNGetTypeArchiveTypeName(self.handle, id, snapshot) + if name is None: + return None + qname = ty_.QualifiedName._from_core_struct(name) + if len(qname.name) == 0: + return None + return qname + + def get_type_id(self, name: 'ty_.QualifiedNameType', snapshot: Optional[str] = None) -> Optional[str]: + """ + Retrieve a type's id by its name + :param name: Type name + :param snapshot: Snapshot id to search for types, or None to search the latest snapshot + :return: Type id, if it exists. Otherwise None + """ + if snapshot is None: + snapshot = self.current_snapshot_id + if not isinstance(name, ty_.QualifiedName): + name = ty_.QualifiedName(name) + t = core.BNGetTypeArchiveTypeId(self.handle, name._to_core_struct(), snapshot) + if t is None: + return None + if t == "": + return None + return t + + @property + def types(self) -> Dict[ty_.QualifiedName, ty_.Type]: + """ + Retrieve all stored types in the archive at the current snapshot + :return: Map of all types, by name + """ + return self.get_types() + + @property + def types_and_ids(self) -> Dict[str, Tuple[ty_.QualifiedName, ty_.Type]]: + """ + Retrieve all stored types in the archive at the current snapshot + :return: Map of type id to type name and definition + """ + return self.get_types_and_ids() + + def get_types(self, snapshot: Optional[str] = None) -> Dict[ty_.QualifiedName, ty_.Type]: + """ + Retrieve all stored types in the archive at a snapshot + :param snapshot: Snapshot id to search for types, or None to search the latest snapshot + :return: Map of all types, by name + """ + result = {} + for id, (name, type) in self.get_types_and_ids(snapshot).items(): + result[name] = type + return result + + def get_types_and_ids(self, snapshot: Optional[str] = None) -> Dict[str, Tuple[ty_.QualifiedName, ty_.Type]]: + """ + Retrieve all stored types in the archive at a snapshot + :param snapshot: Snapshot id to search for types, or None to search the latest snapshot + :return: Map of type id to type name and definition + """ + if snapshot is None: + snapshot = self.current_snapshot_id + count = ctypes.c_ulonglong(0) + result = {} + named_types = core.BNGetTypeArchiveTypes(self.handle, snapshot, count) + assert named_types is not None, "core.BNGetTypeArchiveTypes returned None" + try: + for i in range(0, count.value): + name = ty_.QualifiedName._from_core_struct(named_types[i].name) + id = core.pyNativeStr(named_types[i].id) + result[id] = (name, ty_.Type.create(core.BNNewTypeReference(named_types[i].type))) + return result + finally: + core.BNFreeTypeIdList(named_types, count.value) + + @property + def type_ids(self) -> List[str]: + """ + Get a list of all types' ids in the archive at the current snapshot + :return: All type ids + """ + return self.get_type_ids() + + def get_type_ids(self, snapshot: Optional[str] = None) -> List[str]: + """ + Get a list of all types' ids in the archive at a snapshot + :param snapshot: Snapshot id to search for types, or None to search the latest snapshot + :return: All type ids + """ + if snapshot is None: + snapshot = self.current_snapshot_id + count = ctypes.c_ulonglong(0) + result = [] + ids = core.BNGetTypeArchiveTypeIds(self.handle, snapshot, count) + assert ids is not None, "core.BNGetTypeArchiveTypeIds returned None" + try: + for i in range(count.value): + result.append(core.pyNativeStr(ids[i])) + return result + finally: + core.BNFreeStringList(ids, count.value) + + @property + def type_names(self) -> List['ty_.QualifiedName']: + """ + Get a list of all types' names in the archive at the current snapshot + :return: All type names + """ + return self.get_type_names() + + def get_type_names(self, snapshot: Optional[str] = None) -> List['ty_.QualifiedName']: + """ + Get a list of all types' names in the archive at a snapshot + :param snapshot: Snapshot id to search for types, or None to search the latest snapshot + :return: All type names + """ + if snapshot is None: + snapshot = self.current_snapshot_id + count = ctypes.c_ulonglong(0) + result = [] + names = core.BNGetTypeArchiveTypeNames(self.handle, snapshot, count) + assert names is not None, "core.BNGetTypeArchiveTypeNames returned None" + try: + for i in range(count.value): + result.append(ty_.QualifiedName._from_core_struct(names[i])) + return result + finally: + core.BNFreeQualifiedNameArray(names, count.value) + + @property + def type_names_and_ids(self) -> Dict[str, 'ty_.QualifiedName']: + """ + Get a list of all types' names and ids in the archive at the current snapshot + :return: Mapping of all type ids to names + """ + return self.get_type_names_and_ids() + + def get_type_names_and_ids(self, snapshot: Optional[str] = None) -> Dict[str, 'ty_.QualifiedName']: + """ + Get a list of all types' names and ids in the archive at a current snapshot + :param snapshot: Snapshot id to search for types, or None to search the latest snapshot + :return: Mapping of all type ids to names + """ + if snapshot is None: + snapshot = self.current_snapshot_id + names = ctypes.POINTER(core.BNQualifiedName)() + ids = ctypes.POINTER(ctypes.c_char_p)() + count = ctypes.c_ulonglong(0) + result = {} + if not core.BNGetTypeArchiveTypeNamesAndIds(self.handle, snapshot, names, ids, count): + raise RuntimeError("core.BNGetTypeArchiveTypeNamesAndIds returned False") + try: + for i in range(count.value): + id = core.pyNativeStr(ids[i]) + name = ty_.QualifiedName._from_core_struct(names[i]) + result[id] = name + return result + finally: + core.BNFreeQualifiedNameArray(names, count.value) + + def get_outgoing_direct_references(self, id: str, snapshot: Optional[str] = None) -> List[str]: + """ + Get all types a given type references directly + :param id: Source type id + :param snapshot: Snapshot id to search for types, or empty string to search the latest snapshot + :return: Target type ids + """ + if snapshot is None: + snapshot = self.current_snapshot_id + assert id is not None + count = ctypes.c_size_t(0) + ids = core.BNGetTypeArchiveOutgoingDirectTypeReferences(self.handle, id, snapshot, count) + if ids is None: + raise RuntimeError("BNGetTypeArchiveOutgoingDirectTypeReferences") + result = [] + try: + for i in range(0, count.value): + result.append(core.pyNativeStr(ids[i])) + return result + finally: + core.BNFreeStringList(ids, count.value) + + def get_outgoing_recursive_references(self, id: str, snapshot: Optional[str] = None) -> List[str]: + """ + Get all types a given type references, and any types that the referenced types reference + :param id: Source type id + :param snapshot: Snapshot id to search for types, or empty string to search the latest snapshot + :return: Target type ids + """ + if snapshot is None: + snapshot = self.current_snapshot_id + assert id is not None + count = ctypes.c_size_t(0) + ids = core.BNGetTypeArchiveOutgoingRecursiveTypeReferences(self.handle, id, snapshot, count) + if ids is None: + raise RuntimeError("BNGetTypeArchiveOutgoingRecursiveTypeReferences") + result = [] + try: + for i in range(0, count.value): + result.append(core.pyNativeStr(ids[i])) + return result + finally: + core.BNFreeStringList(ids, count.value) + + def get_incoming_direct_references(self, id: str, snapshot: Optional[str] = None) -> List[str]: + """ + Get all types that reference a given type + :param id: Target type id + :param snapshot: Snapshot id to search for types, or empty string to search the latest snapshot + :return: Source type ids + """ + if snapshot is None: + snapshot = self.current_snapshot_id + assert id is not None + count = ctypes.c_size_t(0) + ids = core.BNGetTypeArchiveIncomingDirectTypeReferences(self.handle, id, snapshot, count) + if ids is None: + raise RuntimeError("BNGetTypeArchiveIncomingDirectTypeReferences") + result = [] + try: + for i in range(0, count.value): + result.append(core.pyNativeStr(ids[i])) + return result + finally: + core.BNFreeStringList(ids, count.value) + + def get_incoming_recursive_references(self, id: str, snapshot: Optional[str] = None) -> List[str]: + """ + Get all types that reference a given type, and all types that reference them, recursively + :param id: Target type id + :param snapshot: Snapshot id to search for types, or empty string to search the latest snapshot + :return: Source type ids + """ + if snapshot is None: + snapshot = self.current_snapshot_id + assert id is not None + count = ctypes.c_size_t(0) + ids = core.BNGetTypeArchiveIncomingRecursiveTypeReferences(self.handle, id, snapshot, count) + if ids is None: + raise RuntimeError("BNGetTypeArchiveIncomingRecursiveTypeReferences") + result = [] + try: + for i in range(0, count.value): + result.append(core.pyNativeStr(ids[i])) + return result + finally: + core.BNFreeStringList(ids, count.value) + + def query_metadata(self, key: str) -> Optional['metadata.MetadataValueType']: + """ + Look up a metadata entry in the archive + :param string key: key to query + :rtype: Metadata associated with the key, if it exists. Otherwise, None + :Example: + + >>> ta: TypeArchive + >>> ta.store_metadata("ordinals", {"9": "htons"}) + >>> ta.query_metadata("ordinals")["9"] + "htons" + """ + md_handle = core.BNTypeArchiveQueryMetadata(self.handle, key) + if md_handle is None: + return None + return metadata.Metadata(handle=md_handle).value + + def store_metadata(self, key: str, md: 'metadata.MetadataValueType') -> None: + """ + Store a key/value pair in the archive's metadata storage + :param string key: key value to associate the Metadata object with + :param Varies md: object to store. + :Example: + + >>> ta: TypeArchive + >>> ta.store_metadata("ordinals", {"9": "htons"}) + >>> ta.query_metadata("ordinals")["9"] + "htons" + """ + if not isinstance(md, metadata.Metadata): + md = metadata.Metadata(md) + if not core.BNTypeArchiveStoreMetadata(self.handle, key, md.handle): + raise RuntimeError("BNTypeArchiveStoreMetadata") + + def remove_metadata(self, key: str) -> None: + """ + Delete a given metadata entry in the archive + :param string key: key associated with metadata + :Example: + + >>> ta: TypeArchive + >>> ta.store_metadata("integer", 1337) + >>> ta.remove_metadata("integer") + """ + core.BNTypeArchiveRemoveMetadata(self.handle, key) + + def serialize_snapshot(self, snapshot: str) -> 'databuffer.DataBuffer': + """ + Turn a given snapshot into a data stream + :param snapshot: Snapshot id + :return: Buffer containing serialized snapshot data + """ + result = core.BNTypeArchiveSerializeSnapshot(self.handle, snapshot) + if not result: + raise RuntimeError("BNTypeArchiveDeserializeSnapshot") + return databuffer.DataBuffer(handle=result) + + def deserialize_snapshot(self, data: 'databuffer.DataBufferInputType') -> str: + """ + Take a serialized snapshot data stream and create a new snapshot from it + :param data: Snapshot data + :return: String of created snapshot id + """ + buffer = databuffer.DataBuffer(data) + result = core.BNTypeArchiveDeserializeSnapshot(self.handle, buffer.handle) + if not result: + raise RuntimeError("BNTypeArchiveDeserializeSnapshot") + return result + + def register_notification(self, notify: 'TypeArchiveNotification') -> None: + """ + Register a notification listener + :param notify: Object to receive notifications + """ + cb = TypeArchiveNotificationCallbacks(self, notify) + cb._register() + self._notifications[notify] = cb + + def unregister_notification(self, notify: 'TypeArchiveNotification') -> None: + """ + Unregister a notification listener + :param notify: Object to no longer receive notifications + """ + if notify in self._notifications: + self._notifications[notify]._unregister() + del self._notifications[notify] + + +class TypeArchiveNotification: + def __init__(self): + pass + + def view_attached(self, archive: 'TypeArchive', view: 'binaryview.BinaryView') -> None: + """ + Called when a new view attaches to the type archive. + :param archive: Source Type archive + :param view: View attaching the archive + """ + pass + + def view_detached(self, archive: 'TypeArchive', view: 'binaryview.BinaryView') -> None: + """ + Called when a view that has previously attached the archive detaches it + :param archive: Source Type archive + :param view: View detaching the archive + """ + pass + + def type_added(self, archive: 'TypeArchive', id: str, definition: 'ty_.Type') -> None: + """ + Called when a type is added to the archive + :param archive: Source Type archive + :param id: Id of type added + :param definition: Definition of type + """ + pass + + def type_updated(self, archive: 'TypeArchive', id: str, old_definition: 'ty_.Type', new_definition: 'ty_.Type') -> None: + """ + Called when a type in the archive is updated to a new definition + :param archive: Source Type archive + :param id: Id of type + :param old_definition: Previous definition + :param new_definition: Current definition + """ + pass + + def type_renamed(self, archive: 'TypeArchive', id: str, old_name: 'ty_.QualifiedName', new_name: 'ty_.QualifiedName') -> None: + """ + Called when a type in the archive is renamed + :param archive: Source Type archive + :param id: Type id + :param old_name: Previous name + :param new_name: Current name + """ + pass + + def type_deleted(self, archive: 'TypeArchive', id: str, definition: 'ty_.Type') -> None: + """ + Called when a type in the archive is deleted from the archive + :param archive: Source Type archive + :param id: Id of type deleted + :param definition: Definition of type deleted + """ + pass + + +class TypeArchiveNotificationCallbacks: + def __init__(self, archive: 'TypeArchive', notify: 'TypeArchiveNotification'): + self._archive = archive + self._notify = notify + self._cb = core.BNTypeArchiveNotification() + self._cb.context = 0 + self._cb.typeAdded = self._cb.typeAdded.__class__(self._type_added) + self._cb.typeUpdated = self._cb.typeUpdated.__class__(self._type_updated) + self._cb.typeRenamed = self._cb.typeRenamed.__class__(self._type_renamed) + self._cb.typeDeleted = self._cb.typeDeleted.__class__(self._type_deleted) + + def _register(self) -> None: + core.BNRegisterTypeArchiveNotification(self._archive.handle, self._cb) + + def _unregister(self) -> None: + core.BNUnregisterTypeArchiveNotification(self._archive.handle, self._cb) + + def _view_attached(self, ctxt, archive: ctypes.POINTER(core.BNTypeArchive), view: ctypes.POINTER(core.BNBinaryView)) -> None: + try: + self._notify.view_attached(self._archive, binaryview.BinaryView(handle=core.BNNewViewReference(view))) + except: + log.log_error(traceback.format_exc()) + + def _view_detached(self, ctxt, archive: ctypes.POINTER(core.BNTypeArchive), view: ctypes.POINTER(core.BNBinaryView)) -> None: + try: + self._notify.view_detached(self._archive, binaryview.BinaryView(handle=core.BNNewViewReference(view))) + except: + log.log_error(traceback.format_exc()) + + def _type_added(self, ctxt, archive: ctypes.POINTER(core.BNTypeArchive), id: ctypes.c_char_p, definition: ctypes.POINTER(core.BNType)) -> None: + try: + self._notify.type_added(self._archive, core.pyNativeStr(id), ty_.Type.create(handle=core.BNNewTypeReference(definition))) + except: + log.log_error(traceback.format_exc()) + + def _type_updated(self, ctxt, archive: ctypes.POINTER(core.BNTypeArchive), id: ctypes.c_char_p, old_definition: ctypes.POINTER(core.BNType), new_definition: ctypes.POINTER(core.BNType)) -> None: + try: + self._notify.type_updated(self._archive, core.pyNativeStr(id), ty_.Type.create(handle=core.BNNewTypeReference(old_definition)), ty_.Type.create(handle=core.BNNewTypeReference(new_definition))) + except: + log.log_error(traceback.format_exc()) + + def _type_renamed(self, ctxt, archive: ctypes.POINTER(core.BNTypeArchive), id: ctypes.c_char_p, old_name: ctypes.POINTER(core.BNQualifiedName), new_name: ctypes.POINTER(core.BNQualifiedName)) -> None: + try: + self._notify.type_renamed(self._archive, core.pyNativeStr(id), ty_.QualifiedName._from_core_struct(old_name.contents), ty_.QualifiedName._from_core_struct(new_name.contents)) + except: + log.log_error(traceback.format_exc()) + + def _type_deleted(self, ctxt, archive: ctypes.POINTER(core.BNTypeArchive), id: ctypes.c_char_p, definition: ctypes.POINTER(core.BNType)) -> None: + try: + self._notify.type_deleted(self._archive, core.pyNativeStr(id), ty_.Type.create(handle=core.BNNewTypeReference(definition))) + except: + log.log_error(traceback.format_exc()) + + @property + def archive(self) -> 'TypeArchive': + return self._archive + + @property + def notify(self) -> 'TypeArchiveNotification': + return self._notify
\ No newline at end of file |
