diff options
| author | Peter LaFosse <peter@vector35.com> | 2021-06-07 09:59:54 -0400 |
|---|---|---|
| committer | Peter LaFosse <peter@vector35.com> | 2021-09-05 10:08:09 -0400 |
| commit | 61b4bb24e06aa955484293d35fa926c07887544b (patch) | |
| tree | 29c6b7fecdac6270681260637439926ec07a259e /python/filemetadata.py | |
| parent | 75f2463a46cc666e87120f3a30332fa80020b62e (diff) | |
Add type hints to basicblock.py, lowlevelil.py, architecture.py
Diffstat (limited to 'python/filemetadata.py')
| -rw-r--r-- | python/filemetadata.py | 158 |
1 files changed, 91 insertions, 67 deletions
diff --git a/python/filemetadata.py b/python/filemetadata.py index 903a36f6..ee8e8271 100644 --- a/python/filemetadata.py +++ b/python/filemetadata.py @@ -18,20 +18,23 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -from __future__ import absolute_import import traceback import ctypes +from typing import Any, Callable, Optional, List # Binary Ninja Components import binaryninja -from binaryninja import _binaryninjacore as core -from binaryninja import associateddatastore #required for _FileMetadataAssociatedDataStore -from binaryninja import log -from binaryninja.enums import SaveOption -from binaryninja import pyNativeStr +from . import _binaryninjacore as core +from .enums import SaveOption +from . import associateddatastore #required for _FileMetadataAssociatedDataStore +from . import log +from . import binaryview + +ProgressFuncType = Callable[[int, int], bool] +ViewName = str class NavigationHandler(object): - def _register(self, handle): + def _register(self, handle) -> None: self._cb = core.BNNavigationHandler() self._cb.context = 0 self._cb.getCurrentView = self._cb.getCurrentView.__class__(self._get_current_view) @@ -39,7 +42,7 @@ class NavigationHandler(object): self._cb.navigate = self._cb.navigate.__class__(self._navigate) core.BNSetFileMetadataNavigationHandler(handle, self._cb) - def _get_current_view(self, ctxt): + def _get_current_view(self, ctxt:Any): try: view = self.get_current_view() except: @@ -47,27 +50,36 @@ class NavigationHandler(object): view = "" return core.BNAllocString(view) - def _get_current_offset(self, ctxt): + def _get_current_offset(self, ctxt:Any) -> int: try: return self.get_current_offset() except: log.log_error(traceback.format_exc()) return 0 - def _navigate(self, ctxt, view, offset): + def _navigate(self, ctxt:Any, view:ViewName, offset:int) -> bool: try: return self.navigate(view, offset) except: log.log_error(traceback.format_exc()) return False + def get_current_view(self) -> str: + return NotImplemented + + def get_current_offset(self) -> int: + return NotImplemented + + def navigate(self, view:ViewName, offset:int) -> bool: + return NotImplemented + class SaveSettings(object): """ ``class SaveSettings`` is used to specify actions and options that apply to saving a database (.bndb). """ - def __init__(self, handle = None): + def __init__(self, handle=None): if handle is None: self.handle = core.BNCreateSaveSettings() else: @@ -76,12 +88,12 @@ class SaveSettings(object): def __del__(self): core.BNFreeSaveSettings(self.handle) - def is_option_set(self, option): + def is_option_set(self, option:SaveOption) -> bool: if isinstance(option, str): option = SaveOption[option] return core.BNIsSaveSettingsOptionSet(self.handle, option) - def set_option(self, option, state = True): + def set_option(self, option:SaveOption, state:bool=True): """ Set a SaveOption in this instance. @@ -122,7 +134,7 @@ class FileMetadata(object): self.handle = core.BNCreateFileMetadata() if filename is not None: core.BNSetFilename(self.handle, str(filename)) - self._nav = None + self._nav:Optional[NavigationHandler] = None def __repr__(self): return "<FileMetadata: %s>" % self.filename @@ -135,6 +147,8 @@ class FileMetadata(object): def __eq__(self, other): if not isinstance(other, self.__class__): return NotImplemented + assert self.handle is not None + assert other.handle is not None return ctypes.addressof(self.handle.contents) == ctypes.addressof(other.handle.contents) def __ne__(self, other): @@ -143,16 +157,15 @@ class FileMetadata(object): return not (self == other) def __hash__(self): + assert self.handle is not None return hash(ctypes.addressof(self.handle.contents)) @property - def nav(self): - """ - """ + def nav(self) -> Optional[NavigationHandler]: return self._nav @nav.setter - def nav(self, value): + def nav(self, value:NavigationHandler) -> None: self._nav = value @classmethod @@ -161,100 +174,102 @@ class FileMetadata(object): if handle.value in cls._associated_data: del cls._associated_data[handle.value] - @classmethod - def set_default_session_data(cls, name, value): + @staticmethod + def set_default_session_data(name:str, value:Any) -> None: _FileMetadataAssociatedDataStore.set_default(name, value) @property - def original_filename(self): + def original_filename(self) -> str: """The original name of the binary opened if a bndb, otherwise reads or sets the current filename (read/write)""" return core.BNGetOriginalFilename(self.handle) @original_filename.setter - def original_filename(self, value): + def original_filename(self, value:str) -> None: core.BNSetOriginalFilename(self.handle, str(value)) @property - def filename(self): + def filename(self) -> str: """The name of the open bndb or binary filename (read/write)""" return core.BNGetFilename(self.handle) @filename.setter - def filename(self, value): + def filename(self, value:str) -> None: core.BNSetFilename(self.handle, str(value)) @property - def modified(self): + def modified(self) -> bool: """Boolean result of whether the file is modified (Inverse of 'saved' property) (read/write)""" return core.BNIsFileModified(self.handle) @modified.setter - def modified(self, value): + def modified(self, value:bool) -> None: if value: core.BNMarkFileModified(self.handle) else: core.BNMarkFileSaved(self.handle) @property - def analysis_changed(self): + def analysis_changed(self) -> bool: """Boolean result of whether the auto-analysis results have changed (read-only)""" return core.BNIsAnalysisChanged(self.handle) @property - def has_database(self, binary_view_type = ""): + def has_database(self, binary_view_type:ViewName="") -> bool: """Whether the FileMetadata is backed by a database, or if specified, a specific BinaryViewType (read-only)""" return core.BNIsBackedByDatabase(self.handle, binary_view_type) @property - def view(self): + def view(self) -> ViewName: return core.BNGetCurrentView(self.handle) @view.setter - def view(self, value): + def view(self, value:ViewName) -> None: core.BNNavigate(self.handle, str(value), core.BNGetCurrentOffset(self.handle)) @property - def offset(self): + def offset(self) -> int: """The current offset into the file (read/write)""" return core.BNGetCurrentOffset(self.handle) @offset.setter - def offset(self, value): + def offset(self, value:int) -> None: core.BNNavigate(self.handle, core.BNGetCurrentView(self.handle), value) @property - def raw(self): + def raw(self) -> Optional['binaryview.BinaryView']: """Gets the "Raw" BinaryView of the file""" view = core.BNGetFileViewOfType(self.handle, "Raw") if view is None: return None - return binaryninja.binaryview.BinaryView(file_metadata = self, handle = view) + return binaryview.BinaryView(file_metadata = self, handle = view) @property - def saved(self): + def saved(self) -> bool: """Boolean result of whether the file has been saved (Inverse of 'modified' property) (read/write)""" return not core.BNIsFileModified(self.handle) @saved.setter - def saved(self, value): + def saved(self, value:bool) -> None: if value: core.BNMarkFileSaved(self.handle) else: core.BNMarkFileModified(self.handle) @property - def navigation(self): + def navigation(self) -> Optional[NavigationHandler]: """Alias for nav""" return self._nav @navigation.setter - def navigation(self, value): + def navigation(self, value:NavigationHandler) -> None: + assert self.handle is not None value._register(self.handle) self._nav = value @property - def session_data(self): + def session_data(self) -> Any: """Dictionary object where plugins can store arbitrary data associated with the file""" + assert self.handle is not None, "Attempting to set session_data when handle is None" handle = ctypes.cast(self.handle, ctypes.c_void_p) if handle.value not in FileMetadata._associated_data: obj = _FileMetadataAssociatedDataStore() @@ -264,17 +279,17 @@ class FileMetadata(object): return FileMetadata._associated_data[handle.value] @property - def snapshot_data_applied_without_error(self): + def snapshot_data_applied_without_error(self) -> bool: return core.BNIsSnapshotDataAppliedWithoutError(self.handle) - def close(self): + def close(self) -> None: """ Closes the underlying file handle. It is recommended that this is done in a `finally` clause to avoid handle leaks. """ core.BNCloseFile(self.handle) - def begin_undo_actions(self): + def begin_undo_actions(self) -> None: """ ``begin_undo_actions`` start recording actions taken so the can be undone at some point. @@ -296,7 +311,7 @@ class FileMetadata(object): """ core.BNBeginUndoActions(self.handle) - def commit_undo_actions(self): + def commit_undo_actions(self) -> None: """ ``commit_undo_actions`` commit the actions taken since the last commit to the undo database. @@ -318,7 +333,7 @@ class FileMetadata(object): """ core.BNCommitUndoActions(self.handle) - def undo(self): + def undo(self) -> None: """ ``undo`` undo the last committed action in the undo database. @@ -343,7 +358,7 @@ class FileMetadata(object): """ core.BNUndo(self.handle) - def redo(self): + def redo(self) -> None: """ ``redo`` redo the last committed action in the undo database. @@ -368,7 +383,7 @@ class FileMetadata(object): """ core.BNRedo(self.handle) - def navigate(self, view, offset): + def navigate(self, view:ViewName, offset:int) -> bool: """ ``navigate`` navigates the UI to the specified virtual address @@ -381,12 +396,12 @@ class FileMetadata(object): :Example: >>> import random - >>> bv.navigate(bv.view, random.choice(bv.functions).start) + >>> bv.navigate(bv.view, random.choice(list(bv.functions)).start) True """ return core.BNNavigate(self.handle, str(view), offset) - def create_database(self, filename, progress_func = None, settings = None): + def create_database(self, filename:str, progress_func:Optional[ProgressFuncType]= None, settings:SaveSettings=None): """ ``create_database`` writes the current database (.bndb) out to the specified file. @@ -400,17 +415,20 @@ class FileMetadata(object): >>> bv.file.create_database(f"{bv.file.filename}.bndb", None, settings) True """ + _settings = None if settings is not None: - settings = settings.handle + _settings = settings.handle + assert self.raw is not None, "BinaryView.create_database called when raw view is None" if progress_func is None: - return core.BNCreateDatabase(self.raw.handle, str(filename), settings) + return core.BNCreateDatabase(self.raw.handle, str(filename), _settings) else: + _progress_func = progress_func return core.BNCreateDatabaseWithProgress(self.raw.handle, str(filename), None, ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( - lambda ctxt, cur, total: progress_func(cur, total)), settings) + lambda ctxt, cur, total: _progress_func(cur, total)), settings) - def open_existing_database(self, filename, progress_func = None): + def open_existing_database(self, filename:str, progress_func:Callable[[int, int], bool]=None): if progress_func is None: view = core.BNOpenExistingDatabase(self.handle, str(filename)) else: @@ -419,56 +437,62 @@ class FileMetadata(object): lambda ctxt, cur, total: progress_func(cur, total))) if view is None: return None - return binaryninja.binaryview.BinaryView(file_metadata = self, handle = view) + return binaryview.BinaryView(file_metadata = self, handle = view) - def open_database_for_configuration(self, filename): + def open_database_for_configuration(self, filename:str) -> Optional['binaryview.BinaryView']: view = core.BNOpenDatabaseForConfiguration(self.handle, str(filename)) if view is None: return None - return binaryninja.binaryview.BinaryView(file_metadata = self, handle = view) + return binaryview.BinaryView(file_metadata = self, handle = view) - def save_auto_snapshot(self, progress_func = None, settings = None): + def save_auto_snapshot(self, progress_func:Optional[ProgressFuncType]=None, settings:SaveSettings=None): + _settings = None if settings is not None: - settings = settings.handle + _settings = settings.handle + assert self.raw is not None, "BinaryView.save_auto_snapshot called when raw view is None" if progress_func is None: - return core.BNSaveAutoSnapshot(self.raw.handle, settings) + return core.BNSaveAutoSnapshot(self.raw.handle, _settings) else: + _progress_func = progress_func return core.BNSaveAutoSnapshotWithProgress(self.raw.handle, None, ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( - lambda ctxt, cur, total: progress_func(cur, total)), settings) + lambda ctxt, cur, total: _progress_func(cur, total)), _settings) - def merge_user_analysis(self, path, progress_func = None): + def merge_user_analysis(self, path:str, progress_func:ProgressFuncType): return core.BNMergeUserAnalysis(self.handle, str(path), None, ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( lambda ctxt, cur, total: progress_func(cur, total))) - def get_view_of_type(self, name): + def get_view_of_type(self, name:str) -> Optional['binaryview.BinaryView']: view = core.BNGetFileViewOfType(self.handle, str(name)) if view is None: view_type = core.BNGetBinaryViewTypeByName(str(name)) if view_type is None: return None + + assert self.raw is not None, "BinaryView.save_auto_snapshot called when raw view is None" view = core.BNCreateBinaryViewOfType(view_type, self.raw.handle) if view is None: return None - return binaryninja.binaryview.BinaryView(file_metadata = self, handle = view) + return binaryview.BinaryView(file_metadata = self, handle = view) - def open_project(self): + def open_project(self) -> bool: return core.BNOpenProject(self.handle) - def close_project(self): + def close_project(self) -> None: core.BNCloseProject(self.handle) - def is_project_open(self): + def is_project_open(self) -> bool: return core.BNIsProjectOpen(self.handle) @property - def existing_views(self): + def existing_views(self) -> List[ViewName]: length = ctypes.c_ulonglong() result = core.BNGetExistingViews(self.handle, ctypes.byref(length)) + assert result is not None, "core.BNGetExistingViews returned None" views = [] for i in range(length.value): - views.append(pyNativeStr(result[i])) + views.append(result[i].decode("utf-8")) core.BNFreeStringList(result, length) return views
\ No newline at end of file |
