From 35564f31b73081fbaecc7155f82596509b1c1645 Mon Sep 17 00:00:00 2001 From: Plato Mavropoulos Date: Mon, 11 Nov 2024 01:18:34 +0200 Subject: [PATCH] BIOSUtilities v24.11.10 Re-written public attributes of Apple EFI ID Improved memory consumption for all utilities Adjusted README with consolidated requirements --- CHANGELOG | 6 + README.md | 164 ++++++++++-------------- biosutilities/__init__.py | 2 +- biosutilities/apple_efi_id.py | 118 ++++++++++------- biosutilities/apple_efi_im4p.py | 12 +- biosutilities/apple_efi_pbzx.py | 10 +- biosutilities/apple_efi_pkg.py | 36 ++++-- biosutilities/award_bios_extract.py | 5 +- biosutilities/common/compression.py | 4 +- biosutilities/common/externals.py | 6 +- biosutilities/common/paths.py | 12 ++ biosutilities/common/templates.py | 15 ++- biosutilities/dell_pfs_extract.py | 6 +- biosutilities/fujitsu_upc_extract.py | 6 +- biosutilities/insyde_ifd_extract.py | 4 +- biosutilities/panasonic_bios_extract.py | 6 +- biosutilities/phoenix_tdk_extract.py | 4 +- biosutilities/toshiba_com_extract.py | 14 +- main.py | 20 +-- 19 files changed, 252 insertions(+), 198 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8831ae0..f52833a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +24.11.10 + +Re-written public attributes of Apple EFI ID +Improved memory consumption for all utilities +Adjusted README with consolidated requirements + 24.10.30 Improved UAF module detection at AMI UCP Extract diff --git a/README.md b/README.md index 5a64775..2cb9d88 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## About -Various BIOS/UEFI-related utilities which aid in modding and/or research +Various BIOS/UEFI-related utilities which aid in research and/or modding ## Usage @@ -10,7 +10,7 @@ Various BIOS/UEFI-related utilities which aid in modding and/or research The "main" script provides a simple way to check and parse each of the user provided files against all utilities, in succession. It is ideal for quick drag & drop operations but lacks the finer control of the "Package" method. If needed, a few options can be set, by using the command line: -``` bash +``` text usage: main.py [-h] [-e] [-o OUTPUT_DIR] [paths ...] positional arguments: @@ -22,13 +22,13 @@ options: -o OUTPUT_DIR, --output-dir OUTPUT_DIR extraction directory ``` -``` bash +``` text python ./main.py "/path/to/input/file.bin" --output-dir "/path/to/file extractions" ``` If no arguments/options are provided, the "main" script requests the input and output paths from the user. If no output path is provided, the utility will use the parent directory of the first input file or fallback to the runtime execution directory. -``` python +``` text Enter input file or directory path: "C:\P5405CSA.303" Enter output directory path: "C:\P5405CSA.303_output" @@ -78,7 +78,7 @@ input_object: str | bytes | bytearray = b'' ##### extract_path (required) ``` python -extract_path: str = '' +extract_path: str = runtime_root() ``` ##### padding (optional) @@ -87,8 +87,7 @@ extract_path: str = '' padding: int = 0 ``` -If the required arguments are not provided, it is still possible to use the BIOSUtility-inherited instance to access -auxiliary public methods and class constants. However, checking and/or parsing of file formats will not yield results. +If the required arguments are not provided, placeholder values are set so that it is possible to use the BIOSUtility-inherited instance to access auxiliary public methods and class constants. However, checking and/or parsing of file formats will not yield results. #### Methods @@ -120,18 +119,38 @@ There are two main types of requirements, depending on the utility. ### Python Packages +* [pefile](https://pypi.org/project/pefile/2023.2.7/) +* [dissect.util](https://pypi.org/project/dissect.util/3.18/) + Python packages can be installed via Pypi (e.g. pip) ``` bash python -m pip install --upgrade -r requirements.txt ``` +or + ``` bash python -m pip install pefile==2023.2.7 dissect.util==3.18 ``` ### External Executables / Scripts +To run the utilities, you must have the following 3rd party tools at PATH or "external": + +* [7-Zip](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux) +* [UEFIFind](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIFind.exe for Windows or UEFIFind for Linux/macOS](https://github.com/LongSoft/UEFITool/releases)) +* [UEFIExtract](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIExtract.exe for Windows or UEFIExtract for Linux/macOS](https://github.com/LongSoft/UEFITool/releases)) +* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux/macOS) +* [ToshibaComExtractor](https://github.com/LongSoft/ToshibaComExtractor) (i.e. [comextract.exe for Windows or comextract for Linux/macOS](https://github.com/LongSoft/ToshibaComExtractor/releases)) + +Note: On Linux, you need to compile "comextract" from sources as no pre-built binary exists. +Note: On Linux and macOS, you need to compile "TianoCompress" from sources as no pre-built binary exists. + +Optionally, to decompile the Intel BIOS Guard Scripts (when applicable), you must have the following 3rd party python script at PATH or "external": + +* [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py) + External executables and/or scripts (e.g. TianoCompress.exe, big_script_tool.py, 7z.exe) need to be found via the "PATH" environment variable, which is configured differently depending on the operating system. Alternatively, if neither modifying PATH environment variable nor copying the executables in standard OS PATH directories is an option, you can create a folder "external" at the root of the "biosutilities" project. @@ -143,14 +162,14 @@ Alternatively, if neither modifying PATH environment variable nor copying the ex or ``` bash -sudo install "/path/to/downloaded/external/executable/to/install" /usr/local/bin +sudo install "/path/to/downloaded/executable" /usr/local/bin ``` #### Windows [Windows Path](https://www.computerhope.com/issues/ch000549.htm) -Note: In the "Environment Variables" window, you can modify the "Path" variable under "User variables" instead of "System variables", as many guides suggest. +Note: In the "Environment Variables" window, you can modify the "Path" variable under "User variables" instead of "System variables", contrary to what many guides suggest. #### MacOS @@ -187,11 +206,9 @@ Note that the AMI PFAT structure may not have an explicit component order. AMI's No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -Optionally, to decompile the AMI PFAT \> Intel BIOS Guard Scripts, you must have the following 3rd party python script at PATH or "external": - -* [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py) +* BIOS Guard Script Tool (optional) ### AMI UCP Update Extractor @@ -205,18 +222,11 @@ Additional optional arguments are provided for this utility: * checksum -> bool : verify AMI UCP Checksums (slow) -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party tools at PATH or "external": - -* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux/macOS) -* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux) - -Optionally, to decompile the AMI UCP \> AMI PFAT \> Intel BIOS Guard Scripts (when applicable), you must have the following 3rd party python script at PATH or "external": - -* [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py) - -Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists. +* 7-Zip (required) +* TianoCompress (required) +* BIOS Guard Script Tool (optional) ### Apple EFI IM4P Splitter @@ -228,9 +238,9 @@ Parses Apple IM4P multi-EFI files and splits all detected EFI firmware into sepa No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you do not need any prerequisites. +No additional requirements are needed for this utility. ### Apple EFI Image Identifier @@ -248,14 +258,12 @@ The utility exposes certain public class attributes, once parse_format() method * efi_file_name -> str : Suggested image filename, based on Intel "IBIOSI" information * intel_bios_info -> dict[str, str] : Information contained at Intel "IBIOSI" structure -* apple_rom_version -> defaultdict[str, set] : Information contained at "Apple ROM Version" structure +* apple_rom_version -> dict[str, str] : Information contained at "Apple ROM Version" structure -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party tools at PATH or "external": - -* [UEFIFind](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIFind.exe for Windows or UEFIFind for Linux/macOS](https://github.com/LongSoft/UEFITool/releases)) -* [UEFIExtract](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIExtract.exe for Windows or UEFIExtract for Linux/macOS](https://github.com/LongSoft/UEFITool/releases)) +* UEFIFind (required) +* UEFIExtract (required) ### Apple EFI Package Extractor @@ -267,13 +275,11 @@ Parses Apple EFI PKG firmware packages (e.g. FirmwareUpdate.pkg, BridgeOSUpdateC No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party tools at PATH or "external": - -* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux) -* [UEFIFind](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIFind.exe for Windows or UEFIFind for Linux/macOS](https://github.com/LongSoft/UEFITool/releases)) -* [UEFIExtract](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIExtract.exe for Windows or UEFIExtract for Linux/macOS](https://github.com/LongSoft/UEFITool/releases)) +* 7-Zip (required) +* UEFIFind (required) +* UEFIExtract (required) ### Apple EFI PBZX Extractor @@ -285,11 +291,9 @@ Parses Apple EFI PBZX images, re-assembles their CPIO payload and extracts its f No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party tools at PATH or "external": - -* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux) +* 7-Zip (required) ### Award BIOS Module Extractor @@ -301,11 +305,9 @@ Parses Award BIOS images and extracts their modules (e.g. RAID, MEMINIT, \_EN_CO No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party tool at PATH or "external": - -* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux) +* 7-Zip (required) ### Dell PFS Update Extractor @@ -320,11 +322,9 @@ Additional optional arguments are provided for this utility: * advanced -> bool : extract signatures and metadata * structure -> bool : show PFS structure information -#### Prerequisites +#### Requirements -Optionally, to decompile the Intel BIOS Guard (PFAT) Scripts, you must have the following 3rd party utility at PATH or "external": - -* [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py) +* BIOS Guard Script Tool (optional) ### Fujitsu SFX BIOS Extractor @@ -336,11 +336,9 @@ Parses Fujitsu SFX BIOS images and extracts their obfuscated Microsoft CAB archi No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party tool at PATH or "external": - -* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux) +* 7-Zip (required) ### Fujitsu UPC BIOS Extractor @@ -352,13 +350,9 @@ Parses Fujitsu UPC BIOS images and extracts their EFI compressed SPI/BIOS/UEFI f No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party tool at PATH or "external": - -* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux/macOS) - -Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists. +* TianoCompress (required) ### Insyde iFlash/iFdPacker Extractor @@ -370,9 +364,9 @@ Parses Insyde iFlash/iFdPacker Update images and extracts their firmware (e.g. S No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you do not need any prerequisites. +No additional requirements are needed for this utility. ### Panasonic BIOS Package Extractor @@ -384,16 +378,11 @@ Parses Panasonic BIOS Package executables and extracts their firmware (e.g. SPI, No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party Python modules installed: - -* [pefile](https://pypi.org/project/pefile/2023.2.7/) -* [dissect.util](https://pypi.org/project/dissect.util/3.18/) - -Moreover, you must have the following 3rd party tool at PATH or "external": - -* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux) +* 7-Zip (required) +* pefile (required) +* dissect.util (required) ### Phoenix TDK Packer Extractor @@ -405,11 +394,9 @@ Parses Phoenix Tools Development Kit (TDK) Packer executables and extracts their No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party Python module installed: - -* [pefile](https://pypi.org/project/pefile/2023.2.7/) +* pefile (required) ### Portwell EFI Update Extractor @@ -421,17 +408,10 @@ Parses Portwell UEFI Unpacker EFI executables (usually named "Update.efi") and e No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party Python module installed: - -* [pefile](https://pypi.org/project/pefile/2023.2.7/) - -Moreover, you must have the following 3rd party tool at PATH or "external": - -* [TianoCompress](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/TianoCompress/) (i.e. [TianoCompress.exe for Windows](https://github.com/tianocore/edk2-BaseTools-win32/) or TianoCompress for Linux/macOS) - -Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists. +* pefile (required) +* TianoCompress (required) ### Toshiba BIOS COM Extractor @@ -443,13 +423,9 @@ Parses Toshiba BIOS COM images and extracts their raw or compressed SPI/BIOS/UEF No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party tool at PATH or "external": - -* [ToshibaComExtractor](https://github.com/LongSoft/ToshibaComExtractor) (i.e. [comextract.exe for Windows or comextract for Linux/macOS](https://github.com/LongSoft/ToshibaComExtractor/releases)) - -Note: On Linux, you'll need to compile comextract from sources as no pre-built binary exists. +* ToshibaComExtractor (required) ### VAIO Packaging Manager Extractor @@ -461,8 +437,6 @@ Parses VAIO Packaging Manager executables and extracts their firmware (e.g. SPI, No additional optional arguments are provided for this utility. -#### Prerequisites +#### Requirements -To run the utility, you must have the following 3rd party tool at PATH or "external": - -* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux) +* 7-Zip (required) diff --git a/biosutilities/__init__.py b/biosutilities/__init__.py index 387a38c..0790d55 100644 --- a/biosutilities/__init__.py +++ b/biosutilities/__init__.py @@ -5,4 +5,4 @@ Copyright (C) 2018-2024 Plato Mavropoulos """ -__version__ = '24.10.30' +__version__ = '24.11.10' diff --git a/biosutilities/apple_efi_id.py b/biosutilities/apple_efi_id.py index 3b95532..09da9d3 100644 --- a/biosutilities/apple_efi_id.py +++ b/biosutilities/apple_efi_id.py @@ -13,18 +13,20 @@ import struct import subprocess import zlib -from collections import defaultdict +from datetime import datetime from re import Match from typing import Any, Final from biosutilities.common.externals import uefiextract_path, uefifind_path -from biosutilities.common.paths import delete_dirs, delete_file, is_file, make_dirs, path_suffixes, runtime_root +from biosutilities.common.paths import (delete_dirs, delete_file, is_file_read, make_dirs, path_size, + path_suffixes, runtime_root) from biosutilities.common.patterns import PAT_INTEL_IBIOSI, PAT_APPLE_ROM_VER from biosutilities.common.structs import CHAR, ctypes_struct, UINT8 from biosutilities.common.system import printer from biosutilities.common.templates import BIOSUtility EFI_EXTENSIONS: Final[list[str]] = ['.fd', '.scap', '.im4p'] +EFI_MAX_SIZE: Final[int] = 0x3000000 class IntelBiosId(ctypes.LittleEndianStructure): @@ -62,35 +64,27 @@ class IntelBiosId(ctypes.LittleEndianStructure): def get_bios_id(self) -> dict[str, str]: """ Get Apple/Intel EFI BIOS ID """ - intel_sig: str = self.Signature.decode('utf-8') - board_id: str = self._decode(field=self.BoardID) board_ext: str = self._decode(field=self.BoardExt) version_major: str = self._decode(field=self.VersionMajor) build_type: str = self._decode(field=self.BuildType) version_minor: str = self._decode(field=self.VersionMinor) - build_year: str = self._decode(field=self.Year) - build_month: str = self._decode(field=self.Month) - build_day: str = self._decode(field=self.Day) - build_hour: str = self._decode(field=self.Hour) - build_minute: str = self._decode(field=self.Minute) + build_year: int = int(f'20{self._decode(field=self.Year)}') + build_month: int = int(self._decode(field=self.Month)) + build_day: int = int(self._decode(field=self.Day)) + build_hour: int = int(self._decode(field=self.Hour)) + build_minute: int = int(self._decode(field=self.Minute)) - efi_name_id: str = (f'{board_id}_{board_ext}_{version_major}_{build_type}{version_minor}' - f'_20{build_year}-{build_month}-{build_day}_{build_hour}-{build_minute}') + efi_version: str = f'{version_major}_{build_type}{version_minor}' + efi_date: datetime = datetime(build_year, build_month, build_day, build_hour, build_minute) + efi_name: str = f'{board_id}_{board_ext}_{efi_version}_{efi_date.strftime("%Y-%m-%d_%H-%M")}' return { - 'intel_sig': intel_sig, 'board_id': board_id, - 'board_ext': board_ext, - 'version_major': version_major, - 'version_minor': version_minor, - 'build_type': build_type, - 'build_year': build_year, - 'build_month': build_month, - 'build_day': build_day, - 'build_hour': build_hour, - 'build_minute': build_minute, - 'efi_name_id': efi_name_id + 'apple_id': board_ext, + 'version': efi_version, + 'date': efi_date.isoformat(), + 'name': efi_name } def struct_print(self, padding: int = 0) -> None: @@ -98,17 +92,10 @@ class IntelBiosId(ctypes.LittleEndianStructure): ibiosi: dict[str, str] = self.get_bios_id() - ibiosi_date: str = f'20{ibiosi["build_year"]}-{ibiosi["build_month"]}-{ibiosi["build_day"]}' - ibiosi_time: str = f'{ibiosi["build_hour"]}:{ibiosi["build_minute"]}' - - printer(message=['Intel Signature:', ibiosi['intel_sig']], padding=padding, new_line=False) - printer(message=['Board Identity: ', ibiosi['board_id']], padding=padding, new_line=False) - printer(message=['Apple Identity: ', ibiosi['board_ext']], padding=padding, new_line=False) - printer(message=['Major Version: ', ibiosi['version_major']], padding=padding, new_line=False) - printer(message=['Minor Version: ', ibiosi['version_minor']], padding=padding, new_line=False) - printer(message=['Build Type: ', ibiosi['build_type']], padding=padding, new_line=False) - printer(message=['Build Date: ', ibiosi_date], padding=padding, new_line=False) - printer(message=['Build Time: ', ibiosi_time], padding=padding, new_line=False) + printer(message=['Board ID: ', ibiosi['board_id']], padding=padding, new_line=False) + printer(message=['Apple ID: ', ibiosi['apple_id']], padding=padding, new_line=False) + printer(message=['Version: ', ibiosi['version']], padding=padding, new_line=False) + printer(message=['Datetime: ', ibiosi['date']], padding=padding, new_line=False) class AppleEfiIdentify(BIOSUtility): @@ -125,26 +112,51 @@ class AppleEfiIdentify(BIOSUtility): self.silent: bool = silent self.efi_file_name: str = '' - self.intel_bios_info: dict[str, str] = {} - self.apple_rom_version: defaultdict[str, set] = defaultdict(set) + + self.intel_bios_info: dict[str, str] = { + 'board_id': '', + 'apple_id': '', + 'version': '', + 'date': '', + 'name': '' + } + + self.apple_rom_version: dict[str, str] = { + 'bios_id': '', + 'board_id': '', + 'build_type': '', + 'buildcave_id': '', + 'built_by': '', + 'compiler': '', + 'date': '', + 'efi_version': '', + 'model': '', + 'rom_version': '', + 'revision': '', + 'uuid': '' + } def check_format(self) -> bool: """ Check if input is Apple EFI image """ - if isinstance(self.input_object, str) and is_file(in_path=self.input_object): + if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object): if path_suffixes(in_path=self.input_object)[-1].lower() not in EFI_EXTENSIONS: return False + if path_size(in_path=self.input_object) > EFI_MAX_SIZE: + return False + input_path: str = self.input_object else: + if len(self.input_buffer) > EFI_MAX_SIZE: + return False + input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_CHECK.tmp') with open(input_path, 'wb') as check_out: check_out.write(self.input_buffer) - input_buffer: bytes = self.input_buffer - - if PAT_INTEL_IBIOSI.search(input_buffer): + if PAT_INTEL_IBIOSI.search(self.input_buffer): return True uefifind_cmd: list[str] = [uefifind_path(), input_path, 'body', 'list', self.PAT_UEFIFIND] @@ -163,7 +175,7 @@ class AppleEfiIdentify(BIOSUtility): def parse_format(self) -> bool: """ Parse & Identify (or Rename) Apple EFI image """ - if isinstance(self.input_object, str) and is_file(in_path=self.input_object): + if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object): input_path: str = self.input_object else: input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_PARSE.tmp') @@ -213,9 +225,9 @@ class AppleEfiIdentify(BIOSUtility): bios_id_hdr.struct_print(padding=self.padding + 4) - self.intel_bios_info = bios_id_hdr.get_bios_id() + self.intel_bios_info |= bios_id_hdr.get_bios_id() - self.efi_file_name = (f'{self.intel_bios_info["efi_name_id"]}_{zlib.adler32(self.input_buffer):08X}' + self.efi_file_name = (f'{self.intel_bios_info["name"]}_{zlib.adler32(self.input_buffer):08X}' f'{path_suffixes(in_path=input_path)[-1]}') _ = self._apple_rom_version(input_buffer=self.input_buffer, padding=self.padding) @@ -245,16 +257,28 @@ class AppleEfiIdentify(BIOSUtility): rom_version_text: str = rom_version_data.decode('utf-8').strip('\n') - for rom_version_line in [line.strip() for line in rom_version_text.split('\n')]: - rom_version_parts: list[str] = rom_version_line.split(sep=':', maxsplit=1) - - self.apple_rom_version[rom_version_parts[0].strip()].add(rom_version_parts[1].strip()) - if not self.silent: printer(message=f'Detected Apple ROM Version at 0x{rom_version_match_off:X}', padding=padding) printer(message=rom_version_text, strip=True, padding=padding + 4) + for rom_version_line in [line.strip() for line in rom_version_text.split('\n')]: + rom_version_parts: list[str] = rom_version_line.split(sep=':', maxsplit=1) + + rom_version_key: str = rom_version_parts[0].strip().lower().replace(' ', '_') + rom_version_val: str = rom_version_parts[1].strip() + + if rom_version_key == 'uuid': + if self.apple_rom_version[rom_version_key] == '': + self.apple_rom_version[rom_version_key] = rom_version_val + else: + self.apple_rom_version[rom_version_key] += f', {rom_version_val}' + elif rom_version_key == 'date': + self.apple_rom_version[rom_version_key] = datetime.strptime(rom_version_val.replace( + ' PDT', '').replace(' PST', ''), '%a %b %d %H:%M:%S %Y').isoformat() + else: + self.apple_rom_version[rom_version_key] = rom_version_val + return True return False diff --git a/biosutilities/apple_efi_im4p.py b/biosutilities/apple_efi_im4p.py index d145117..7af3a84 100644 --- a/biosutilities/apple_efi_im4p.py +++ b/biosutilities/apple_efi_im4p.py @@ -12,11 +12,13 @@ import os from re import Match from typing import Final -from biosutilities.common.paths import make_dirs, path_stem +from biosutilities.common.paths import is_file_read, make_dirs, path_size, path_stem from biosutilities.common.patterns import PAT_APPLE_IM4P, PAT_INTEL_FD from biosutilities.common.system import printer from biosutilities.common.templates import BIOSUtility +from biosutilities.apple_efi_id import EFI_MAX_SIZE + class AppleEfiIm4pSplit(BIOSUtility): """ Apple EFI IM4P Splitter """ @@ -29,8 +31,12 @@ class AppleEfiIm4pSplit(BIOSUtility): def check_format(self) -> bool: """ Check if input is Apple EFI IM4P image """ - if isinstance(self.input_object, str) and not self.input_object.lower().endswith('.im4p'): - return False + if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object): + if not self.input_object.lower().endswith('.im4p'): + return False + + if path_size(in_path=self.input_object) > EFI_MAX_SIZE: + return False if PAT_APPLE_IM4P.search(self.input_buffer) and PAT_INTEL_FD.search(self.input_buffer): return True diff --git a/biosutilities/apple_efi_pbzx.py b/biosutilities/apple_efi_pbzx.py index 82867ae..a85054b 100644 --- a/biosutilities/apple_efi_pbzx.py +++ b/biosutilities/apple_efi_pbzx.py @@ -15,7 +15,7 @@ import os from typing import Any, Final from biosutilities.common.compression import is_szip_supported, szip_decompress -from biosutilities.common.paths import delete_file, make_dirs, path_stem +from biosutilities.common.paths import delete_file, is_file_read, make_dirs, path_stem from biosutilities.common.patterns import PAT_APPLE_PBZX from biosutilities.common.structs import ctypes_struct, UINT32 from biosutilities.common.system import printer @@ -53,7 +53,13 @@ class AppleEfiPbzxExtract(BIOSUtility): def check_format(self) -> bool: """ Check if input is Apple PBZX image """ - return bool(PAT_APPLE_PBZX.search(self.input_buffer, 0, 4)) + if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object): + with open(self.input_object, 'rb') as input_object: + check_buffer: bytes = input_object.read(4) + else: + check_buffer = self.input_buffer[:4] + + return bool(PAT_APPLE_PBZX.search(check_buffer, 0, 4)) def parse_format(self) -> bool: """ Parse & Extract Apple PBZX image """ diff --git a/biosutilities/apple_efi_pkg.py b/biosutilities/apple_efi_pkg.py index 6324ee1..a76bd49 100644 --- a/biosutilities/apple_efi_pkg.py +++ b/biosutilities/apple_efi_pkg.py @@ -10,8 +10,9 @@ Copyright (C) 2019-2024 Plato Mavropoulos import os from biosutilities.common.compression import is_szip_supported, szip_decompress -from biosutilities.common.paths import (copy_file, delete_dirs, delete_file, extract_folder, is_access, is_dir, - is_file, make_dirs, path_files, path_name, path_suffixes, runtime_root) +from biosutilities.common.paths import (copy_file, delete_dirs, delete_file, extract_folder, is_dir, + is_file_read, make_dirs, path_files, path_name, path_stem, + path_suffixes, runtime_root) from biosutilities.common.system import printer from biosutilities.common.templates import BIOSUtility @@ -30,7 +31,7 @@ class AppleEfiPkgExtract(BIOSUtility): is_apple_efi_pkg: bool = False - if isinstance(self.input_object, str) and is_file(in_path=self.input_object): + if isinstance(self.input_object, str) and self._is_file_processable(input_path=self.input_object): input_path: str = self.input_object else: input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_CHECK.bin') @@ -52,7 +53,7 @@ class AppleEfiPkgExtract(BIOSUtility): def parse_format(self) -> bool: """ Parse & Extract Apple EFI PKG packages """ - if isinstance(self.input_object, str) and is_file(in_path=self.input_object): + if isinstance(self.input_object, str) and self._is_file_processable(input_path=self.input_object): input_path: str = self.input_object else: input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_PARSE.bin') @@ -76,7 +77,7 @@ class AppleEfiPkgExtract(BIOSUtility): delete_file(in_path=input_path) for work_file in path_files(in_path=working_dir): - if is_file(in_path=work_file) and is_access(in_path=work_file): + if self._is_file_processable(input_path=work_file): self._pbzx_zip(input_path=work_file, padding=self.padding + 4) self._gzip_cpio(input_path=work_file, padding=self.padding + 4) self._dmg_zip(input_path=work_file, padding=self.padding + 4) @@ -86,6 +87,10 @@ class AppleEfiPkgExtract(BIOSUtility): return True + @staticmethod + def _is_file_processable(input_path: str) -> bool: + return is_file_read(in_path=input_path) and path_stem(in_path=input_path) != '.aea' + def _xar_gzip(self, input_path: str, padding: int = 0) -> None: """ XAR/TAR > GZIP """ @@ -96,7 +101,7 @@ class AppleEfiPkgExtract(BIOSUtility): if szip_decompress(in_path=input_path, out_path=pkg_path, in_name=pkg_type, padding=padding, args=[f'-t{pkg_type}']): for pkg_file in path_files(in_path=pkg_path): - if is_file(in_path=pkg_file) and is_access(in_path=pkg_file): + if self._is_file_processable(input_path=pkg_file): self._gzip_cpio(input_path=pkg_file, padding=padding + 4) break @@ -109,14 +114,15 @@ class AppleEfiPkgExtract(BIOSUtility): if szip_decompress(in_path=input_path, out_path=dmg_path, in_name='DMG', padding=padding, args=None): for dmg_file in path_files(in_path=dmg_path): - if is_file(in_path=dmg_file) and is_access(in_path=dmg_file): + if self._is_file_processable(input_path=dmg_file): if is_szip_supported(in_path=dmg_file, args=['-tZIP']): zip_path: str = extract_folder(in_path=dmg_file) if szip_decompress(in_path=dmg_file, out_path=zip_path, in_name='ZIP', padding=padding + 4, args=['-tZIP']): for zip_file in path_files(in_path=zip_path): - self._im4p_id(input_path=zip_file, padding=padding + 8) + if self._is_file_processable(input_path=zip_file): + self._im4p_id(input_path=zip_file, padding=padding + 8) def _pbzx_zip(self, input_path: str, padding: int = 0) -> None: """ PBZX > ZIP """ @@ -133,14 +139,15 @@ class AppleEfiPkgExtract(BIOSUtility): printer(message=f'Successful PBZX extraction via {pbzx_module.TITLE}!', padding=padding) for pbzx_file in path_files(in_path=pbzx_path): - if is_file(in_path=pbzx_file) and is_access(in_path=pbzx_file): + if self._is_file_processable(input_path=pbzx_file): if is_szip_supported(in_path=pbzx_file, args=['-tZIP']): zip_path: str = extract_folder(in_path=pbzx_file) if szip_decompress(in_path=pbzx_file, out_path=zip_path, in_name='ZIP', padding=padding + 4, args=['-tZIP']): for zip_file in path_files(in_path=zip_path): - self._im4p_id(input_path=zip_file, padding=padding + 8) + if self._is_file_processable(input_path=zip_file): + self._im4p_id(input_path=zip_file, padding=padding + 8) def _gzip_cpio(self, input_path: str, padding: int = 0) -> None: """ GZIP > CPIO """ @@ -151,14 +158,15 @@ class AppleEfiPkgExtract(BIOSUtility): if szip_decompress(in_path=input_path, out_path=gzip_path, in_name='GZIP', padding=padding, args=['-tGZIP']): for gzip_file in path_files(in_path=gzip_path): - if is_file(in_path=gzip_file) and is_access(in_path=gzip_file): + if self._is_file_processable(input_path=gzip_file): if is_szip_supported(in_path=gzip_file, args=['-tCPIO']): cpio_path: str = extract_folder(in_path=gzip_file) if szip_decompress(in_path=gzip_file, out_path=cpio_path, in_name='CPIO', padding=padding + 4, args=['-tCPIO']): for cpio_file in path_files(in_path=cpio_path): - self._im4p_id(input_path=cpio_file, padding=padding + 8) + if self._is_file_processable(input_path=cpio_file): + self._im4p_id(input_path=cpio_file, padding=padding + 8) def _im4p_id(self, input_path: str, padding: int = 0) -> None: """ Split IM4P (if applicable), identify and copy EFI """ @@ -166,7 +174,7 @@ class AppleEfiPkgExtract(BIOSUtility): if path_suffixes(in_path=input_path)[-1].lower() not in EFI_EXTENSIONS: return None - if not (is_file(in_path=input_path) and is_access(in_path=input_path)): + if not self._is_file_processable(input_path=input_path): return None working_dir: str = extract_folder(in_path=input_path) @@ -185,7 +193,7 @@ class AppleEfiPkgExtract(BIOSUtility): im4p_module.parse_format() for efi_path in path_files(in_path=working_dir) if is_dir(in_path=working_dir) else [input_path]: - if is_file(in_path=efi_path) and is_access(in_path=efi_path): + if self._is_file_processable(input_path=efi_path): efi_id_module: AppleEfiIdentify = AppleEfiIdentify( input_object=efi_path, extract_path=extract_folder(in_path=efi_path), padding=padding + 8) diff --git a/biosutilities/award_bios_extract.py b/biosutilities/award_bios_extract.py index e44c131..9ebda11 100644 --- a/biosutilities/award_bios_extract.py +++ b/biosutilities/award_bios_extract.py @@ -10,7 +10,8 @@ Copyright (C) 2018-2024 Plato Mavropoulos import os from biosutilities.common.compression import szip_decompress -from biosutilities.common.paths import clear_readonly, delete_file, extract_folder, is_file, make_dirs, safe_name +from biosutilities.common.paths import (clear_readonly, delete_file, extract_folder, is_file_read, + make_dirs, safe_name) from biosutilities.common.patterns import PAT_AWARD_LZH from biosutilities.common.system import printer from biosutilities.common.templates import BIOSUtility @@ -70,7 +71,7 @@ class AwardBiosExtract(BIOSUtility): padding=self.padding + 4) # Manually check if 7-Zip extracted LZH due to its CRC check issue - if is_file(in_path=mod_path): + if is_file_read(in_path=mod_path): clear_readonly(in_path=lzh_path) delete_file(in_path=lzh_path) # Successful extraction, delete LZH archive diff --git a/biosutilities/common/compression.py b/biosutilities/common/compression.py index ae48e86..23c6775 100644 --- a/biosutilities/common/compression.py +++ b/biosutilities/common/compression.py @@ -10,7 +10,7 @@ import subprocess from typing import Final from biosutilities.common.externals import szip_path, tiano_path -from biosutilities.common.paths import is_access, is_dir, is_file, is_empty_dir, path_size +from biosutilities.common.paths import is_dir, is_file_read, is_empty_dir, path_size from biosutilities.common.system import printer from biosutilities.common.texts import file_to_bytes @@ -118,7 +118,7 @@ def efi_decompress(in_path: str, out_path: str, padding: int = 0, silent: bool = tiano_x: subprocess.CompletedProcess[bytes] = subprocess.run(tiano_c, check=False, stdout=subprocess.DEVNULL) - if tiano_x.returncode == 0 and is_file(in_path=out_path) and is_access(in_path=out_path): + if tiano_x.returncode == 0 and is_file_read(in_path=out_path): if efi_header_info(in_object=in_path)['size_decompressed'] == path_size(in_path=out_path): if not silent: printer(message='Successful EFI decompression via TianoCompress!', padding=padding) diff --git a/biosutilities/common/externals.py b/biosutilities/common/externals.py index 66a1e54..eaa61d6 100644 --- a/biosutilities/common/externals.py +++ b/biosutilities/common/externals.py @@ -16,7 +16,7 @@ from importlib.util import module_from_spec, spec_from_file_location from types import ModuleType from typing import Type -from biosutilities.common.paths import is_dir, is_file, project_root +from biosutilities.common.paths import is_dir, is_file_read, project_root from biosutilities.common.texts import to_string @@ -30,10 +30,10 @@ def get_external_path(cmd: str | list | tuple) -> str: for command in cmd if isinstance(cmd, (list, tuple)) else [to_string(in_object=cmd)]: command_path: str | None = shutil.which(command, path=external_path) - if command_path and is_file(in_path=command_path): + if command_path and is_file_read(in_path=command_path): return command_path - raise OSError(f'{to_string(in_object=cmd, sep_char=", ")} could not be found!') + raise OSError(f'{to_string(in_object=cmd, sep_char=", ")} requirement could not be found!') def big_script_tool() -> Type | None: diff --git a/biosutilities/common/paths.py b/biosutilities/common/paths.py index 21d1ca0..f33a1a0 100644 --- a/biosutilities/common/paths.py +++ b/biosutilities/common/paths.py @@ -237,6 +237,18 @@ def is_access(in_path: str, access_mode: int = os.R_OK, follow_links: bool = Fal return os.access(in_path, access_mode, follow_symlinks=follow_links) +def is_file_read(in_path: str) -> bool: + """ Check if path is a readable file """ + + return isinstance(in_path, str) and is_file(in_path=in_path) and is_access(in_path=in_path) + + +def is_dir_read(in_path: str) -> bool: + """ Check if path is a readable directory """ + + return isinstance(in_path, str) and is_dir(in_path=in_path) and is_access(in_path=in_path) + + def is_empty_dir(in_path: str, follow_links: bool = False) -> bool: """ Check if directory is empty (file-wise) """ diff --git a/biosutilities/common/templates.py b/biosutilities/common/templates.py index 178262c..37195be 100644 --- a/biosutilities/common/templates.py +++ b/biosutilities/common/templates.py @@ -5,6 +5,7 @@ Copyright (C) 2022-2024 Plato Mavropoulos """ +from biosutilities.common.paths import runtime_root from biosutilities.common.texts import file_to_bytes @@ -13,12 +14,22 @@ class BIOSUtility: TITLE: str = 'BIOS Utility' - def __init__(self, input_object: str | bytes | bytearray = b'', extract_path: str = '', padding: int = 0) -> None: + def __init__(self, input_object: str | bytes | bytearray = b'', extract_path: str = runtime_root(), + padding: int = 0) -> None: self.input_object: str | bytes | bytearray = input_object self.extract_path: str = extract_path self.padding: int = padding - self.input_buffer: bytes = file_to_bytes(in_object=self.input_object) + self.__input_buffer: bytes = b'' + + @property + def input_buffer(self) -> bytes: + """ Get input object buffer """ + + if not self.__input_buffer: + self.__input_buffer = file_to_bytes(in_object=self.input_object) + + return self.__input_buffer def check_format(self) -> bool: """ Check if input object is of specific supported format """ diff --git a/biosutilities/dell_pfs_extract.py b/biosutilities/dell_pfs_extract.py index 3877e23..2854a7b 100644 --- a/biosutilities/dell_pfs_extract.py +++ b/biosutilities/dell_pfs_extract.py @@ -19,7 +19,7 @@ from typing import Any, Final from biosutilities.common.checksums import checksum_8_xor from biosutilities.common.compression import is_szip_supported, szip_decompress -from biosutilities.common.paths import (delete_dirs, delete_file, path_files, is_access, is_file, make_dirs, +from biosutilities.common.paths import (delete_dirs, delete_file, path_files, is_file_read, make_dirs, path_name, path_parent, path_stem, safe_name) from biosutilities.common.patterns import PAT_DELL_FTR, PAT_DELL_HDR, PAT_DELL_PKG from biosutilities.common.structs import CHAR, ctypes_struct, UINT8, UINT16, UINT32, UINT64 @@ -263,7 +263,7 @@ class DellPfsExtract(BIOSUtility): pfs_results: dict[str, bytes] = self._thinos_pkg_extract( input_object=self.input_buffer, extract_path=self.extract_path) else: - pfs_results = {path_stem(in_path=self.input_object) if isinstance(self.input_object, str) and is_file( + pfs_results = {path_stem(in_path=self.input_object) if isinstance(self.input_object, str) and is_file_read( in_path=self.input_object) else 'Image': self.input_buffer} # Parse each Dell PFS image contained in the input file @@ -362,7 +362,7 @@ class DellPfsExtract(BIOSUtility): return pfs_results for pkg_file in path_files(in_path=working_path): - if is_file(in_path=pkg_file) and is_access(in_path=pkg_file): + if is_file_read(in_path=pkg_file): if self._is_pfs_hdr(input_object=pkg_file): pfs_name: str = path_name(in_path=str(path_parent(in_path=pkg_file))) diff --git a/biosutilities/fujitsu_upc_extract.py b/biosutilities/fujitsu_upc_extract.py index 79d63cf..b575222 100644 --- a/biosutilities/fujitsu_upc_extract.py +++ b/biosutilities/fujitsu_upc_extract.py @@ -10,7 +10,7 @@ Copyright (C) 2021-2024 Plato Mavropoulos import os from biosutilities.common.compression import efi_decompress, is_efi_compressed -from biosutilities.common.paths import delete_file, make_dirs, is_file, path_name, path_suffixes +from biosutilities.common.paths import delete_file, make_dirs, is_file_read, path_name, path_suffixes from biosutilities.common.templates import BIOSUtility @@ -23,7 +23,7 @@ class FujitsuUpcExtract(BIOSUtility): """ Check if input is Fujitsu UPC image """ is_upc: bool = False - if isinstance(self.input_object, str) and is_file(in_path=self.input_object): + if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object): is_upc = path_suffixes(self.input_object)[-1].upper() == '.UPC' elif isinstance(self.input_object, (bytes, bytearray)): is_upc = True @@ -38,7 +38,7 @@ class FujitsuUpcExtract(BIOSUtility): make_dirs(in_path=self.extract_path) - if isinstance(self.input_object, str) and is_file(in_path=self.input_object): + if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object): input_name: str = path_name(in_path=self.input_object) input_path: str = self.input_object diff --git a/biosutilities/insyde_ifd_extract.py b/biosutilities/insyde_ifd_extract.py index 0ba32ed..759e61a 100644 --- a/biosutilities/insyde_ifd_extract.py +++ b/biosutilities/insyde_ifd_extract.py @@ -14,7 +14,7 @@ import re from typing import Any, Final from biosutilities.common.compression import is_szip_supported, szip_decompress -from biosutilities.common.paths import (delete_file, extract_folder, is_access, is_file, path_files, +from biosutilities.common.paths import (delete_file, extract_folder, is_file_read, path_files, make_dirs, path_name, safe_name) from biosutilities.common.patterns import PAT_INSYDE_IFL, PAT_INSYDE_SFX from biosutilities.common.structs import CHAR, ctypes_struct, UINT32 @@ -224,7 +224,7 @@ class InsydeIfdExtract(BIOSUtility): exit_codes: list[int] = [] for sfx_file in path_files(in_path=extract_path): - if is_file(in_path=sfx_file) and is_access(in_path=sfx_file): + if is_file_read(in_path=sfx_file): insyde_ifd_extract: InsydeIfdExtract = InsydeIfdExtract( input_object=sfx_file, extract_path=extract_folder(sfx_file), padding=padding + 16) diff --git a/biosutilities/panasonic_bios_extract.py b/biosutilities/panasonic_bios_extract.py index 08bfc11..20ea243 100644 --- a/biosutilities/panasonic_bios_extract.py +++ b/biosutilities/panasonic_bios_extract.py @@ -20,7 +20,7 @@ import pefile from dissect.util.compression import lznt1 from biosutilities.common.compression import is_szip_supported, szip_decompress -from biosutilities.common.paths import delete_file, is_access, is_file, path_files, make_dirs, path_stem, safe_name +from biosutilities.common.paths import delete_file, is_file_read, path_files, make_dirs, path_stem, safe_name from biosutilities.common.executables import ms_pe_desc, ms_pe, is_ms_pe, ms_pe_info_show from biosutilities.common.patterns import PAT_MICROSOFT_CAB from biosutilities.common.system import printer @@ -97,7 +97,7 @@ class PanasonicBiosExtract(BIOSUtility): def _panasonic_pkg_name(input_object: str | bytes | bytearray) -> str: """ Get Panasonic BIOS Package file name, when applicable """ - if isinstance(input_object, str) and is_file(in_path=input_object): + if isinstance(input_object, str) and is_file_read(in_path=input_object): return safe_name(in_name=path_stem(in_path=input_object)) return '' @@ -129,7 +129,7 @@ class PanasonicBiosExtract(BIOSUtility): delete_file(in_path=cab_path) # Successful extraction, delete CAB archive for extracted_file_path in path_files(in_path=extract_path): - if is_file(in_path=extracted_file_path) and is_access(in_path=extracted_file_path): + if is_file_read(in_path=extracted_file_path): extracted_pe_file: pefile.PE | None = ms_pe( in_file=extracted_file_path, padding=padding, silent=True) diff --git a/biosutilities/phoenix_tdk_extract.py b/biosutilities/phoenix_tdk_extract.py index 7994dc1..ef40a49 100644 --- a/biosutilities/phoenix_tdk_extract.py +++ b/biosutilities/phoenix_tdk_extract.py @@ -17,7 +17,7 @@ from typing import Any, Final from pefile import PE -from biosutilities.common.paths import is_file, make_dirs, safe_name +from biosutilities.common.paths import is_file_read, make_dirs, safe_name from biosutilities.common.executables import ms_pe, ms_pe_info from biosutilities.common.patterns import PAT_MICROSOFT_MZ, PAT_MICROSOFT_PE, PAT_PHOENIX_TDK from biosutilities.common.structs import CHAR, ctypes_struct, UINT32 @@ -189,7 +189,7 @@ class PhoenixTdkExtract(BIOSUtility): mod_file: str = os.path.join(self.extract_path, safe_name(mod_name)) # Account for potential duplicate file names - if is_file(in_path=mod_file): + if is_file_read(in_path=mod_file): mod_file += f'_{entry_index + 1:02d}' # Save TDK Entry data to output file diff --git a/biosutilities/toshiba_com_extract.py b/biosutilities/toshiba_com_extract.py index a06e519..28ce2d8 100644 --- a/biosutilities/toshiba_com_extract.py +++ b/biosutilities/toshiba_com_extract.py @@ -11,7 +11,7 @@ import os import subprocess from biosutilities.common.externals import comextract_path -from biosutilities.common.paths import delete_file, is_file, make_dirs, path_stem +from biosutilities.common.paths import delete_file, is_file_read, make_dirs, path_stem from biosutilities.common.patterns import PAT_TOSHIBA_COM from biosutilities.common.system import printer from biosutilities.common.templates import BIOSUtility @@ -25,14 +25,20 @@ class ToshibaComExtract(BIOSUtility): def check_format(self) -> bool: """ Check if input is Toshiba BIOS COM image """ - return bool(PAT_TOSHIBA_COM.search(self.input_buffer, 0, 0x100)) + if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object): + with open(self.input_object, 'rb') as input_object: + check_buffer: bytes = input_object.read(0x100) + else: + check_buffer = self.input_buffer[:0x100] + + return bool(PAT_TOSHIBA_COM.search(check_buffer, 0, 0x100)) def parse_format(self) -> bool: """ Parse & Extract Toshiba BIOS COM image """ make_dirs(in_path=self.extract_path) - if isinstance(self.input_object, str) and is_file(in_path=self.input_object): + if isinstance(self.input_object, str) and is_file_read(in_path=self.input_object): input_path: str = self.input_object else: input_path = os.path.join(self.extract_path, 'toshiba_bios.com') @@ -48,7 +54,7 @@ class ToshibaComExtract(BIOSUtility): if input_path != self.input_object: delete_file(in_path=input_path) - if comextract_res.returncode == 0 and is_file(in_path=output_path): + if comextract_res.returncode == 0 and is_file_read(in_path=output_path): printer(message='Successful extraction via ToshibaComExtractor!', padding=self.padding) return True diff --git a/main.py b/main.py index 968c280..c40a194 100644 --- a/main.py +++ b/main.py @@ -31,7 +31,7 @@ from biosutilities.portwell_efi_extract import PortwellEfiExtract from biosutilities.toshiba_com_extract import ToshibaComExtract from biosutilities.vaio_package_extract import VaioPackageExtract -from biosutilities.common.paths import (delete_dirs, extract_folder, is_access, is_dir, is_empty_dir, is_file, +from biosutilities.common.paths import (delete_dirs, extract_folder, is_dir_read, is_empty_dir, is_file_read, path_files, path_name, path_parent, real_path, runtime_root) from biosutilities.common.system import python_version, printer, system_platform from biosutilities.common.texts import remove_quotes, to_boxed, to_ordinal @@ -68,11 +68,11 @@ class BIOSUtilities: for input_path in [input_path for input_path in input_paths if input_path]: input_path_real: str = real_path(in_path=input_path) - if is_dir(in_path=input_path_real): + if is_dir_read(in_path=input_path_real): for input_file in path_files(in_path=input_path_real): - if is_file(in_path=input_file) and is_access(in_path=input_file): + if is_file_read(in_path=input_file): self._input_files.append(input_file) - elif is_file(in_path=input_path_real) and is_access(in_path=input_path_real): + elif is_file_read(in_path=input_path_real): self._input_files.append(input_path_real) def _setup_output_dir(self, padding: int = 0) -> None: @@ -86,7 +86,7 @@ class BIOSUtilities: if not output_path and self._input_files: output_path = str(path_parent(in_path=self._input_files[0])) - if output_path and is_dir(in_path=output_path) and is_access(in_path=output_path): + if output_path and is_dir_read(in_path=output_path): self._output_path = output_path else: self._output_path = runtime_root() @@ -137,9 +137,9 @@ class BIOSUtilities: exit_code: int = len(self._input_files) utilities_classes: list[Any] = [ - AmiUcpExtract, AmiPfatExtract, InsydeIfdExtract, DellPfsExtract, PhoenixTdkExtract, PanasonicBiosExtract, - VaioPackageExtract, PortwellEfiExtract, ToshibaComExtract, FujitsuSfxExtract, FujitsuUpcExtract, - AwardBiosExtract, AppleEfiPkgExtract, AppleEfiPbzxExtract, AppleEfiIm4pSplit, AppleEfiIdentify + AppleEfiPkgExtract, AmiUcpExtract, AmiPfatExtract, InsydeIfdExtract, DellPfsExtract, PhoenixTdkExtract, + PanasonicBiosExtract, VaioPackageExtract, PortwellEfiExtract, ToshibaComExtract, FujitsuSfxExtract, + FujitsuUpcExtract, AwardBiosExtract, AppleEfiPbzxExtract, AppleEfiIm4pSplit, AppleEfiIdentify ] for input_file in self._input_files: @@ -150,11 +150,11 @@ class BIOSUtilities: for utility_class in utilities_classes: extract_path: str = os.path.join(self._output_path, extract_folder(in_path=input_name)) - if is_dir(in_path=extract_path): + if is_dir_read(in_path=extract_path): for suffix in range(2, self.MAX_FAT32_ITEMS): renamed_path: str = f'{os.path.normpath(extract_path)}_{to_ordinal(in_number=suffix)}' - if not is_dir(in_path=renamed_path): + if not is_dir_read(in_path=renamed_path): extract_path = renamed_path break