BIOSUtilities v24.10.09

Added Apple EFI EFI Image Identifier new argument -q
Improved Apple EFI EFI Image Identifier detection flow
Improved Apple EFI Package Extractor file parsing flow
Improved file vs link detection and read access control
Improved common switches handling of 7-Zip decompressor
Improved non-PATH external executable dependencies names
Fixed requirement instruction misalignments at the README
This commit is contained in:
Plato Mavropoulos 2024-10-10 02:18:17 +03:00
parent bbf0008384
commit b174ce40e6
18 changed files with 322 additions and 288 deletions

View file

@ -1,3 +1,13 @@
24.10.09
Added Apple EFI EFI Image Identifier new argument -q
Improved Apple EFI EFI Image Identifier detection flow
Improved Apple EFI Package Extractor file parsing flow
Improved file vs link detection and read access control
Improved common switches handling of 7-Zip decompressor
Improved non-PATH external executable dependencies names
Fixed requirement instruction misalignments at the README
24.10.07 24.10.07
Downgraded pefile dependency from 2024.8.26 to 2023.2.7 Downgraded pefile dependency from 2024.8.26 to 2023.2.7

256
README.md
View file

@ -135,9 +135,13 @@ Show title and version of utility
show_version(is_boxed: bool = True, padding: int = 0) -> None show_version(is_boxed: bool = True, padding: int = 0) -> None
``` ```
## Compatibility
Unless explicitely noted, all utilities should work under Windows, Linux or macOS operating systems which have Python 3.10 - 3.12 support.
## Requirements ## Requirements
There are two main types of requirements (dependencies), depending on the utility. There are two main types of requirements, depending on the utility.
### Python Packages ### Python Packages
@ -148,7 +152,7 @@ python -m pip install --upgrade -r requirements.txt
``` ```
``` bash ``` bash
python -m pip install --upgrade pefile dissect.util python -m pip install pefile==2023.2.7 dissect.util==3.18
``` ```
### External Executables / Scripts ### External Executables / Scripts
@ -171,7 +175,7 @@ sudo install "/path/to/downloaded/external/executable/to/install" /usr/local/bin
[Windows Path](https://www.computerhope.com/issues/ch000549.htm) [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", as many guides suggest.
#### MacOS #### MacOS
@ -179,62 +183,54 @@ sudo install "/path/to/downloaded/external/executable/to/install" /usr/local/bin
## Utilities ## Utilities
* [**AMI BIOS Guard Extractor**](#ami-bios-guard-extractor) * [AMI BIOS Guard Extractor](#ami-bios-guard-extractor)
* [**AMI UCP Update Extractor**](#ami-ucp-update-extractor) * [AMI UCP Update Extractor](#ami-ucp-update-extractor)
* [**Apple EFI IM4P Splitter**](#apple-efi-im4p-splitter) * [Apple EFI IM4P Splitter](#apple-efi-im4p-splitter)
* [**Apple EFI Image Identifier**](#apple-efi-image-identifier) * [Apple EFI Image Identifier](#apple-efi-image-identifier)
* [**Apple EFI Package Extractor**](#apple-efi-package-extractor) * [Apple EFI Package Extractor](#apple-efi-package-extractor)
* [**Apple EFI PBZX Extractor**](#apple-efi-pbzx-extractor) * [Apple EFI PBZX Extractor](#apple-efi-pbzx-extractor)
* [**Award BIOS Module Extractor**](#award-bios-module-extractor) * [Award BIOS Module Extractor](#award-bios-module-extractor)
* [**Dell PFS Update Extractor**](#dell-pfs-update-extractor) * [Dell PFS Update Extractor](#dell-pfs-update-extractor)
* [**Fujitsu SFX BIOS Extractor**](#fujitsu-sfx-bios-extractor) * [Fujitsu SFX BIOS Extractor](#fujitsu-sfx-bios-extractor)
* [**Fujitsu UPC BIOS Extractor**](#fujitsu-upc-bios-extractor) * [Fujitsu UPC BIOS Extractor](#fujitsu-upc-bios-extractor)
* [**Insyde iFlash/iFdPacker Extractor**](#insyde-iflashifdpacker-extractor) * [Insyde iFlash/iFdPacker Extractor](#insyde-iflashifdpacker-extractor)
* [**Panasonic BIOS Package Extractor**](#panasonic-bios-package-extractor) * [Panasonic BIOS Package Extractor](#panasonic-bios-package-extractor)
* [**Phoenix TDK Packer Extractor**](#phoenix-tdk-packer-extractor) * [Phoenix TDK Packer Extractor](#phoenix-tdk-packer-extractor)
* [**Portwell EFI Update Extractor**](#portwell-efi-update-extractor) * [Portwell EFI Update Extractor](#portwell-efi-update-extractor)
* [**Toshiba BIOS COM Extractor**](#toshiba-bios-com-extractor) * [Toshiba BIOS COM Extractor](#toshiba-bios-com-extractor)
* [**VAIO Packaging Manager Extractor**](#vaio-packaging-manager-extractor) * [VAIO Packaging Manager Extractor](#vaio-packaging-manager-extractor)
### **AMI BIOS Guard Extractor** ### AMI BIOS Guard Extractor
#### **Description** #### Description
Parses AMI BIOS Guard (a.k.a. PFAT, Platform Firmware Armoring Technology) images, extracts their SPI/BIOS/UEFI firmware components and optionally decompiles the Intel BIOS Guard Scripts. It supports all AMI PFAT revisions and formats, including those with Index Information tables or nested AMI PFAT structures. The output comprises only final firmware components which are directly usable by end users. Parses AMI BIOS Guard (a.k.a. PFAT, Platform Firmware Armoring Technology) images, extracts their SPI/BIOS/UEFI firmware components and optionally decompiles the Intel BIOS Guard Scripts. It supports all AMI PFAT revisions and formats, including those with Index Information tables or nested AMI PFAT structures. The output comprises only final firmware components which are directly usable by end users.
Note that the AMI PFAT structure may not have an explicit component order. AMI's BIOS Guard Firmware Update Tool (AFUBGT) updates components based on the user/OEM provided Parameters and Options or Index Information table, when applicable. Thus, merging all the components together does not usually yield a proper SPI/BIOS/UEFI image. The utility does generate such a merged file with the name "00 -- \<filename\>\_ALL.bin" but it is up to the end user to determine its usefulness. Additionally, any custom OEM data, after the AMI PFAT structure, is stored in the last file with the name "\<n+1\> -- \_OOB.bin" and it is once again up to the end user to determine its usefulness. In cases where the trailing custom OEM data includes a nested AMI PFAT structure, the utility will process and extract it automatically as well. Note that the AMI PFAT structure may not have an explicit component order. AMI's BIOS Guard Firmware Update Tool (AFUBGT) updates components based on the user/OEM provided Parameters and Options or Index Information table, when applicable. Thus, merging all the components together does not usually yield a proper SPI/BIOS/UEFI image. The utility does generate such a merged file with the name "00 -- \<filename\>\_ALL.bin" but it is up to the end user to determine its usefulness. Additionally, any custom OEM data, after the AMI PFAT structure, is stored in the last file with the name "\<n+1\> -- \_OOB.bin" and it is once again up to the end user to determine its usefulness. In cases where the trailing custom OEM data includes a nested AMI PFAT structure, the utility will process and extract it automatically as well.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
Optionally, to decompile the AMI PFAT \> Intel BIOS Guard Scripts, you must have the following 3rd party python script at PATH or "external": 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](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py)
### **AMI UCP Update Extractor** ### AMI UCP Update Extractor
#### **Description** #### Description
Parses AMI UCP (Utility Configuration Program) Update executables, extracts their firmware components (e.g. SPI/BIOS/UEFI, EC, ME etc) and shows all relevant info. It supports all AMI UCP revisions and formats, including those with nested AMI PFAT, AMI UCP or Insyde iFlash/iFdPacker structures. The output comprises only final firmware components and utilities which are directly usable by end users. Parses AMI UCP (Utility Configuration Program) Update executables, extracts their firmware components (e.g. SPI/BIOS/UEFI, EC, ME etc) and shows all relevant info. It supports all AMI UCP revisions and formats, including those with nested AMI PFAT, AMI UCP or Insyde iFlash/iFdPacker structures. The output comprises only final firmware components and utilities which are directly usable by end users.
#### **Usage** #### Usage
Additional optional arguments are provided for this utility: Additional optional arguments are provided for this utility:
* -c or --checksum : verify AMI UCP Checksums (slow) * -c or --checksum : verify AMI UCP Checksums (slow)
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
To run the utility, you must have the following 3rd party tools at PATH or "external": To run the utility, you must have the following 3rd party tools at PATH or "external":
@ -245,205 +241,173 @@ Optionally, to decompile the AMI UCP \> AMI PFAT \> Intel BIOS Guard Scripts (wh
* [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py) * [BIOS Guard Script Tool](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py)
### **Apple EFI IM4P Splitter** Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists.
#### **Description** ### Apple EFI IM4P Splitter
#### Description
Parses Apple IM4P multi-EFI files and splits all detected EFI firmware into separate Intel SPI/BIOS images. The output comprises only final firmware components and utilities which are directly usable by end users. Parses Apple IM4P multi-EFI files and splits all detected EFI firmware into separate Intel SPI/BIOS images. The output comprises only final firmware components and utilities which are directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists.
#### **Prerequisites**
To run the utility, you do not need any prerequisites. To run the utility, you do not need any prerequisites.
### **Apple EFI Image Identifier** ### Apple EFI Image Identifier
#### **Description** #### Description
Parses Apple EFI images and identifies them based on Intel's official "IBIOSI" tag, which contains info such as Model, Version, Build, Date and Time. Additionally, the utility can provide both "IBIOSI" and "Apple ROM Version" structure info, when available, as well as a suggested EFI image filename, while also making sure to differentiate any EFI images with the same "IBIOSI" tag (e.g. Production, Pre-Production) by appending a checksum of their data. Parses Apple EFI images and identifies them based on Intel's official "IBIOSI" tag, which contains info such as Model, Version, Build, Date and Time. Additionally, the utility can provide both "IBIOSI" and "Apple ROM Version" structure info, when available, as well as a suggested EFI image filename, while also making sure to differentiate any EFI images with the same "IBIOSI" tag (e.g. Production, Pre-Production) by appending a checksum of their data.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. Additional optional arguments are provided for this utility:
#### **Compatibility** * -q or --silent : suppress structure display
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support. The utility exposes certain public class attributes, once parse_format() method has been successfully executed:
#### **Prerequisites** * _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
#### Prerequisites
To run the utility, you must have the following 3rd party tools at PATH or "external": 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)) * [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)) * [UEFIExtract](https://github.com/LongSoft/UEFITool/) (i.e. [UEFIExtract.exe for Windows or UEFIExtract for Linux/macOS](https://github.com/LongSoft/UEFITool/releases))
### **Apple EFI Package Extractor** ### Apple EFI Package Extractor
#### **Description** #### Description
Parses Apple EFI PKG firmware packages (e.g. FirmwareUpdate.pkg, BridgeOSUpdateCustomer.pkg, InstallAssistant.pkg, iMacEFIUpdate.pkg, iMacFirmwareUpdate.tar), extracts their EFI images, splits those in IM4P format and identifies/renames the final Intel SPI/BIOS images accordingly. The output comprises only final firmware components which are directly usable by end users. Parses Apple EFI PKG firmware packages (e.g. FirmwareUpdate.pkg, BridgeOSUpdateCustomer.pkg, InstallAssistant.pkg, iMacEFIUpdate.pkg, iMacFirmwareUpdate.tar), extracts their EFI images, splits those in IM4P format and identifies/renames the final Intel SPI/BIOS images accordingly. The output comprises only final firmware components which are directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
To run the utility, you must have the following 3rd party tools at PATH or "external": 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 Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
### **Apple EFI PBZX Extractor** ### Apple EFI PBZX Extractor
#### **Description** #### Description
Parses Apple EFI PBZX images, re-assembles their CPIO payload and extracts its firmware components (e.g. IM4P, EFI, Utilities, Scripts etc). It supports CPIO re-assembly from both Raw and XZ compressed PBZX Chunks. The output comprises only final firmware components and utilities which are directly usable by end users. Parses Apple EFI PBZX images, re-assembles their CPIO payload and extracts its firmware components (e.g. IM4P, EFI, Utilities, Scripts etc). It supports CPIO re-assembly from both Raw and XZ compressed PBZX Chunks. The output comprises only final firmware components and utilities which are directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
To run the utility, you must have the following 3rd party tools at PATH or "external": 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 Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
### **Award BIOS Module Extractor** ### Award BIOS Module Extractor
#### **Description** #### Description
Parses Award BIOS images and extracts their modules (e.g. RAID, MEMINIT, \_EN_CODE, awardext etc). It supports all Award BIOS image revisions and formats, including those which contain LZH compressed files. The output comprises only final firmware components which are directly usable by end users. Parses Award BIOS images and extracts their modules (e.g. RAID, MEMINIT, \_EN_CODE, awardext etc). It supports all Award BIOS image revisions and formats, including those which contain LZH compressed files. The output comprises only final firmware components which are directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
To run the utility, you must have the following 3rd party tool at PATH or "external": 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 Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
### **Dell PFS Update Extractor** ### Dell PFS Update Extractor
#### **Description** #### Description
Parses Dell PFS Update images and extracts their Firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and Utilities (e.g. Flasher etc) component sections. It supports all Dell PFS revisions and formats, including those which are originally LZMA compressed in ThinOS packages (PKG), ZLIB compressed or Intel BIOS Guard (PFAT) protected. The output comprises only final firmware components which are directly usable by end users. Parses Dell PFS Update images and extracts their Firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and Utilities (e.g. Flasher etc) component sections. It supports all Dell PFS revisions and formats, including those which are originally LZMA compressed in ThinOS packages (PKG), ZLIB compressed or Intel BIOS Guard (PFAT) protected. The output comprises only final firmware components which are directly usable by end users.
#### **Usage** #### Usage
Additional optional arguments are provided for this utility: Additional optional arguments are provided for this utility:
* -a or --advanced : extract signatures and metadata * -a or --advanced : extract signatures and metadata
* -s or --structure : show PFS structure information * -s or --structure : show PFS structure information
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
Optionally, to decompile the Intel BIOS Guard (PFAT) Scripts, you must have the following 3rd party utility at PATH or "external": 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](https://github.com/platomav/BGScriptTool) (i.e. big_script_tool.py)
### **Fujitsu SFX BIOS Extractor** ### Fujitsu SFX BIOS Extractor
#### **Description** #### Description
Parses Fujitsu SFX BIOS images and extracts their obfuscated Microsoft CAB archived firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and utilities (e.g. WinPhlash, PHLASH.INI etc) components. The output comprises only final firmware components which are directly usable by end users. Parses Fujitsu SFX BIOS images and extracts their obfuscated Microsoft CAB archived firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and utilities (e.g. WinPhlash, PHLASH.INI etc) components. The output comprises only final firmware components which are directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
To run the utility, you must have the following 3rd party tool at PATH or "external": 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 Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
### **Fujitsu UPC BIOS Extractor** ### Fujitsu UPC BIOS Extractor
#### **Description** #### Description
Parses Fujitsu UPC BIOS images and extracts their EFI compressed SPI/BIOS/UEFI firmware component. The output comprises only a final firmware component which is directly usable by end users. Parses Fujitsu UPC BIOS images and extracts their EFI compressed SPI/BIOS/UEFI firmware component. The output comprises only a final firmware component which is directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
To run the utility, you must have the following 3rd party tool at PATH or "external": 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) * [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)
### **Insyde iFlash/iFdPacker Extractor** Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists.
#### **Description** ### Insyde iFlash/iFdPacker Extractor
#### Description
Parses Insyde iFlash/iFdPacker Update images and extracts their firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and utilities (e.g. InsydeFlash, H2OFFT, FlsHook, iscflash, platform.ini etc) components. It supports all Insyde iFlash/iFdPacker revisions and formats, including those which are 7-Zip SFX 7z compressed in raw, obfuscated or password-protected form. The output comprises only final firmware components which are directly usable by end users. Parses Insyde iFlash/iFdPacker Update images and extracts their firmware (e.g. SPI, BIOS/UEFI, EC, ME etc) and utilities (e.g. InsydeFlash, H2OFFT, FlsHook, iscflash, platform.ini etc) components. It supports all Insyde iFlash/iFdPacker revisions and formats, including those which are 7-Zip SFX 7z compressed in raw, obfuscated or password-protected form. The output comprises only final firmware components which are directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists.
#### **Prerequisites**
To run the utility, you do not need any prerequisites. To run the utility, you do not need any prerequisites.
### **Panasonic BIOS Package Extractor** ### Panasonic BIOS Package Extractor
#### **Description** #### Description
Parses Panasonic BIOS Package executables and extracts their firmware (e.g. SPI, BIOS/UEFI, EC etc) and utilities (e.g. winprom, configuration etc) components. It supports all Panasonic BIOS Package revisions and formats, including those which contain LZNT1 compressed files and/or AMI PFAT payloads. The output comprises only final firmware components which are directly usable by end users. Parses Panasonic BIOS Package executables and extracts their firmware (e.g. SPI, BIOS/UEFI, EC etc) and utilities (e.g. winprom, configuration etc) components. It supports all Panasonic BIOS Package revisions and formats, including those which contain LZNT1 compressed files and/or AMI PFAT payloads. The output comprises only final firmware components which are directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
To run the utility, you must have the following 3rd party Python modules installed: To run the utility, you must have the following 3rd party Python modules installed:
@ -454,41 +418,33 @@ 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 Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zz for macOS or 7zz, 7zzs for Linux)
### **Phoenix TDK Packer Extractor** ### Phoenix TDK Packer Extractor
#### **Description** #### Description
Parses Phoenix Tools Development Kit (TDK) Packer executables and extracts their firmware (e.g. SPI, BIOS/UEFI, EC etc) and utilities (e.g. WinFlash etc) components. It supports all Phoenix TDK Packer revisions and formats, including those which contain LZMA compressed files. The output comprises only final firmware components which are directly usable by end users. Parses Phoenix Tools Development Kit (TDK) Packer executables and extracts their firmware (e.g. SPI, BIOS/UEFI, EC etc) and utilities (e.g. WinFlash etc) components. It supports all Phoenix TDK Packer revisions and formats, including those which contain LZMA compressed files. The output comprises only final firmware components which are directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
To run the utility, you must have the following 3rd party Python module installed: To run the utility, you must have the following 3rd party Python module installed:
* [pefile](https://pypi.org/project/pefile/) * [pefile](https://pypi.org/project/pefile/)
### **Portwell EFI Update Extractor** ### Portwell EFI Update Extractor
#### **Description** #### Description
Parses Portwell UEFI Unpacker EFI executables (usually named "Update.efi") and extracts their firmware (e.g. SPI, BIOS/UEFI, EC etc) and utilities (e.g. Flasher etc) components. It supports all known Portwell UEFI Unpacker revisions (v1.1, v1.2, v2.0) and formats (used, empty, null), including those which contain EFI compressed files. The output comprises only final firmware components and utilities which are directly usable by end users. Parses Portwell UEFI Unpacker EFI executables (usually named "Update.efi") and extracts their firmware (e.g. SPI, BIOS/UEFI, EC etc) and utilities (e.g. Flasher etc) components. It supports all known Portwell UEFI Unpacker revisions (v1.1, v1.2, v2.0) and formats (used, empty, null), including those which contain EFI compressed files. The output comprises only final firmware components and utilities which are directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
#### **Prerequisites**
To run the utility, you must have the following 3rd party Python module installed: To run the utility, you must have the following 3rd party Python module installed:
@ -498,45 +454,37 @@ 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) * [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)
### **Toshiba BIOS COM Extractor** Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists.
#### **Description** ### Toshiba BIOS COM Extractor
#### Description
Parses Toshiba BIOS COM images and extracts their raw or compressed SPI/BIOS/UEFI firmware component. This utility is effectively a python wrapper around [ToshibaComExtractor by LongSoft](https://github.com/LongSoft/ToshibaComExtractor). The output comprises only a final firmware component which is directly usable by end users. Parses Toshiba BIOS COM images and extracts their raw or compressed SPI/BIOS/UEFI firmware component. This utility is effectively a python wrapper around [ToshibaComExtractor by LongSoft](https://github.com/LongSoft/ToshibaComExtractor). The output comprises only a final firmware component which is directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
Note: On Linux and macOS, you'll need to compile TianoCompress from sources as no pre-built binary exists.
#### **Prerequisites**
To run the utility, you must have the following 3rd party tool at PATH or "external": 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)) * [ToshibaComExtractor](https://github.com/LongSoft/ToshibaComExtractor) (i.e. [comextract.exe for Windows or comextract for Linux/macOS](https://github.com/LongSoft/ToshibaComExtractor/releases))
### **VAIO Packaging Manager Extractor** Note: On Linux, you'll need to compile comextract from sources as no pre-built binary exists.
#### **Description** ### VAIO Packaging Manager Extractor
#### Description
Parses VAIO Packaging Manager executables and extracts their firmware (e.g. SPI, BIOS/UEFI, EC, ME etc), utilities (e.g. WBFLASH etc) and driver (audio, video etc) components. If direct extraction fails, it attempts to unlock the executable in order to run at all non-VAIO systems and allow the user to choose the extraction location. It supports all VAIO Packaging Manager revisions and formats, including those which contain obfuscated Microsoft CAB archives or obfuscated unlock values. The output comprises only final firmware components which are directly usable by end users. Parses VAIO Packaging Manager executables and extracts their firmware (e.g. SPI, BIOS/UEFI, EC, ME etc), utilities (e.g. WBFLASH etc) and driver (audio, video etc) components. If direct extraction fails, it attempts to unlock the executable in order to run at all non-VAIO systems and allow the user to choose the extraction location. It supports all VAIO Packaging Manager revisions and formats, including those which contain obfuscated Microsoft CAB archives or obfuscated unlock values. The output comprises only final firmware components which are directly usable by end users.
#### **Usage** #### Usage
No additional optional arguments are provided for this utility. No additional optional arguments are provided for this utility.
#### **Compatibility** #### Prerequisites
Should work at all Windows, Linux or macOS operating systems which have Python 3.10 or newer support.
Note: On Linux, you'll need to compile comextract from sources as no pre-built binary exists.
#### **Prerequisites**
To run the utility, you must have the following 3rd party tool at PATH or "external": To run the utility, you must have the following 3rd party tool at PATH or "external":

View file

@ -5,4 +5,4 @@
Copyright (C) 2018-2024 Plato Mavropoulos Copyright (C) 2018-2024 Plato Mavropoulos
""" """
__version__ = '24.10.07' __version__ = '24.10.09'

View file

@ -19,7 +19,7 @@ from re import Match
from typing import Any, Final from typing import Any, Final
from biosutilities.common.externals import uefiextract_path, uefifind_path from biosutilities.common.externals import uefiextract_path, uefifind_path
from biosutilities.common.paths import delete_dirs, delete_file, path_suffixes, runtime_root from biosutilities.common.paths import delete_dirs, delete_file, is_access, is_file, path_suffixes, runtime_root
from biosutilities.common.patterns import PAT_INTEL_IBIOSI, PAT_APPLE_ROM_VER from biosutilities.common.patterns import PAT_INTEL_IBIOSI, PAT_APPLE_ROM_VER
from biosutilities.common.structs import CHAR, ctypes_struct, UINT8 from biosutilities.common.structs import CHAR, ctypes_struct, UINT8
from biosutilities.common.system import printer from biosutilities.common.system import printer
@ -116,7 +116,11 @@ class AppleEfiIdentify(BIOSUtility):
TITLE: str = 'Apple EFI Image Identifier' TITLE: str = 'Apple EFI Image Identifier'
PAT_UEFIFIND: Final[str] = f'244942494F534924{"." * 32}2E00{"." * 12}2E00{"." * 16}2E00{"." * 12}2E00{"." * 40}0000' ARGUMENTS: list[tuple[list[str], dict[str, str]]] = [
(['-q', '--silent'], {'help': 'suppress structure display', 'action': 'store_true'})
]
PAT_UEFIFIND: Final[str] = f'244942494F534924{"." * 32}2E00{"." * 12}2E00{"." * 16}2E00{"." * 12}2E00{"." * 40}00'
def __init__(self, arguments: list[str] | None = None) -> None: def __init__(self, arguments: list[str] | None = None) -> None:
super().__init__(arguments=arguments) super().__init__(arguments=arguments)
@ -128,20 +132,25 @@ class AppleEfiIdentify(BIOSUtility):
def check_format(self, input_object: str | bytes | bytearray) -> bool: def check_format(self, input_object: str | bytes | bytearray) -> bool:
""" Check if input is Apple EFI image """ """ Check if input is Apple EFI image """
input_buffer: bytes = file_to_bytes(in_object=input_object) if isinstance(input_object, str) and is_file(in_path=input_object) and is_access(in_path=input_object):
if path_suffixes(in_path=input_object)[-1].lower() not in ('.fd', '.scap', '.im4p'):
return False
if PAT_INTEL_IBIOSI.search(string=input_buffer):
return True
if isinstance(input_object, str) and os.path.isfile(path=input_object):
input_path: str = input_object input_path: str = input_object
else: input_buffer: bytes = file_to_bytes(in_object=input_path)
elif isinstance(input_object, (bytes, bytearray)):
input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_CHECK.tmp') input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_CHECK.tmp')
input_buffer = input_object
with open(file=input_path, mode='wb') as check_out: with open(file=input_path, mode='wb') as check_out:
check_out.write(input_buffer) check_out.write(input_buffer)
else:
return False
try: try:
if PAT_INTEL_IBIOSI.search(string=input_buffer):
return True
_ = subprocess.run([uefifind_path(), input_path, 'body', 'list', self.PAT_UEFIFIND], _ = subprocess.run([uefifind_path(), input_path, 'body', 'list', self.PAT_UEFIFIND],
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
@ -159,7 +168,7 @@ class AppleEfiIdentify(BIOSUtility):
input_buffer: bytes = file_to_bytes(in_object=input_object) input_buffer: bytes = file_to_bytes(in_object=input_object)
if isinstance(input_object, str) and os.path.isfile(path=input_object): if isinstance(input_object, str) and is_file(in_path=input_object):
input_path: str = input_object input_path: str = input_object
else: else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_PARSE.bin') input_path = os.path.join(runtime_root(), 'APPLE_EFI_ID_INPUT_BUFFER_PARSE.bin')
@ -204,6 +213,7 @@ class AppleEfiIdentify(BIOSUtility):
return False return False
if not self.arguments.silent:
printer(message=f'Detected Intel BIOS Info at {bios_id_res}\n', padding=padding) printer(message=f'Detected Intel BIOS Info at {bios_id_res}\n', padding=padding)
bios_id_hdr.struct_print(padding=padding + 4) bios_id_hdr.struct_print(padding=padding + 4)
@ -245,6 +255,7 @@ class AppleEfiIdentify(BIOSUtility):
self.apple_rom_version[rom_version_parts[0].strip()].add(rom_version_parts[1].strip()) self.apple_rom_version[rom_version_parts[0].strip()].add(rom_version_parts[1].strip())
if not self.arguments.silent:
printer(message=f'Detected Apple ROM Version at 0x{rom_version_match_off:X}', padding=padding) 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) printer(message=rom_version_text, strip=True, padding=padding + 4)

View file

@ -24,12 +24,15 @@ class AppleEfiIm4pSplit(BIOSUtility):
TITLE: str = 'Apple EFI IM4P Splitter' TITLE: str = 'Apple EFI IM4P Splitter'
# Intel Flash Descriptor Component Sizes (4MB, 8MB, 16MB and 32MB) # Intel Flash Descriptor Component Sizes (2MB, 4MB, 8MB, 16MB and 32MB)
IFD_COMP_LEN: Final[dict[int, int]] = {3: 0x400000, 4: 0x800000, 5: 0x1000000, 6: 0x2000000} IFD_COMP_LEN: Final[dict[int, int]] = {2: 0x200000, 3: 0x400000, 4: 0x800000, 5: 0x1000000, 6: 0x2000000}
def check_format(self, input_object: str | bytes | bytearray) -> bool: def check_format(self, input_object: str | bytes | bytearray) -> bool:
""" Check if input is Apple EFI IM4P image """ """ Check if input is Apple EFI IM4P image """
if isinstance(input_object, str) and not input_object.lower().endswith('.im4p'):
return False
input_buffer: bytes = file_to_bytes(in_object=input_object) input_buffer: bytes = file_to_bytes(in_object=input_object)
if PAT_APPLE_IM4P.search(string=input_buffer) and PAT_INTEL_FD.search(string=input_buffer): if PAT_APPLE_IM4P.search(string=input_buffer) and PAT_INTEL_FD.search(string=input_buffer):

View file

@ -10,9 +10,8 @@ Copyright (C) 2019-2024 Plato Mavropoulos
import os import os
from biosutilities.common.compression import is_szip_supported, szip_decompress from biosutilities.common.compression import is_szip_supported, szip_decompress
from biosutilities.common.paths import (copy_file, delete_dirs, extract_folder, make_dirs, path_files, from biosutilities.common.paths import (copy_file, delete_dirs, extract_folder, is_access, is_file, make_dirs,
path_name, path_parent, path_suffixes, runtime_root) path_files, path_name, path_parent, path_suffixes, runtime_root)
from biosutilities.common.patterns import PAT_APPLE_PKG_DMG, PAT_APPLE_PKG_TAR, PAT_APPLE_PKG_XAR
from biosutilities.common.system import printer from biosutilities.common.system import printer
from biosutilities.common.templates import BIOSUtility from biosutilities.common.templates import BIOSUtility
from biosutilities.common.texts import file_to_bytes from biosutilities.common.texts import file_to_bytes
@ -34,7 +33,7 @@ class AppleEfiPkgExtract(BIOSUtility):
input_buffer: bytes = file_to_bytes(in_object=input_object) input_buffer: bytes = file_to_bytes(in_object=input_object)
if isinstance(input_object, str) and os.path.isfile(path=input_object): if isinstance(input_object, str) and is_file(in_path=input_object):
input_path: str = input_object input_path: str = input_object
else: else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_CHECK.bin') input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_CHECK.bin')
@ -42,16 +41,12 @@ class AppleEfiPkgExtract(BIOSUtility):
with open(file=input_path, mode='wb') as input_path_object: with open(file=input_path, mode='wb') as input_path_object:
input_path_object.write(input_buffer) input_path_object.write(input_buffer)
if is_szip_supported(in_path=input_path, args=['-tXAR:s0']): for pkg_type in ('XAR', 'TAR', 'DMG'):
if bool(PAT_APPLE_PKG_XAR.search(string=input_buffer, endpos=4)): if is_szip_supported(in_path=input_path, args=[f'-t{pkg_type}:s0']):
is_apple_efi_pkg = True
elif is_szip_supported(in_path=input_path, args=['-tTAR:s0']):
if bool(PAT_APPLE_PKG_TAR.search(string=input_buffer)):
is_apple_efi_pkg = True
elif is_szip_supported(in_path=input_path, args=['-tDMG:s0']):
if bool(PAT_APPLE_PKG_DMG.search(string=input_buffer, endpos=200)):
is_apple_efi_pkg = True is_apple_efi_pkg = True
break
if input_path != input_object: if input_path != input_object:
os.remove(path=input_path) os.remove(path=input_path)
@ -60,7 +55,7 @@ class AppleEfiPkgExtract(BIOSUtility):
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool: def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
""" Parse & Extract Apple EFI PKG packages """ """ Parse & Extract Apple EFI PKG packages """
if isinstance(input_object, str) and os.path.isfile(path=input_object): if isinstance(input_object, str) and is_file(in_path=input_object):
input_path: str = input_object input_path: str = input_object
else: else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_PARSE.bin') input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_PARSE.bin')
@ -72,7 +67,7 @@ class AppleEfiPkgExtract(BIOSUtility):
working_dir: str = os.path.join(extract_path, 'temp') working_dir: str = os.path.join(extract_path, 'temp')
make_dirs(in_path=working_dir, delete=True) make_dirs(in_path=working_dir)
for pkg_type in ('XAR', 'TAR', 'DMG'): for pkg_type in ('XAR', 'TAR', 'DMG'):
if is_szip_supported(in_path=input_path, padding=padding, args=[f'-t{pkg_type}']): if is_szip_supported(in_path=input_path, padding=padding, args=[f'-t{pkg_type}']):
@ -86,6 +81,7 @@ class AppleEfiPkgExtract(BIOSUtility):
os.remove(path=input_path) os.remove(path=input_path)
for work_file in path_files(in_path=working_dir): for work_file in path_files(in_path=working_dir):
if is_file(in_path=work_file) and is_access(in_path=work_file):
self._pbzx_zip(input_path=work_file, extract_path=extract_path, padding=padding + 4) self._pbzx_zip(input_path=work_file, extract_path=extract_path, padding=padding + 4)
self._gzip_cpio(input_path=work_file, extract_path=extract_path, padding=padding + 4) self._gzip_cpio(input_path=work_file, extract_path=extract_path, padding=padding + 4)
self._dmg_zip(input_path=work_file, extract_path=extract_path, padding=padding + 4) self._dmg_zip(input_path=work_file, extract_path=extract_path, padding=padding + 4)
@ -105,6 +101,7 @@ class AppleEfiPkgExtract(BIOSUtility):
if szip_decompress(in_path=input_path, out_path=pkg_path, in_name=pkg_type, if szip_decompress(in_path=input_path, out_path=pkg_path, in_name=pkg_type,
padding=padding, args=[f'-t{pkg_type}']): padding=padding, args=[f'-t{pkg_type}']):
for pkg_file in path_files(in_path=pkg_path): for pkg_file in path_files(in_path=pkg_path):
if is_file(in_path=pkg_file) and is_access(in_path=pkg_file):
self._gzip_cpio(input_path=pkg_file, extract_path=extract_path, padding=padding + 4) self._gzip_cpio(input_path=pkg_file, extract_path=extract_path, padding=padding + 4)
break break
@ -117,6 +114,7 @@ class AppleEfiPkgExtract(BIOSUtility):
if szip_decompress(in_path=input_path, out_path=dmg_path, in_name='DMG', padding=padding, args=None): 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): 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 is_szip_supported(in_path=dmg_file, padding=padding + 4, args=['-tZIP']): if is_szip_supported(in_path=dmg_file, padding=padding + 4, args=['-tZIP']):
zip_path: str = extract_folder(in_path=dmg_file) zip_path: str = extract_folder(in_path=dmg_file)
@ -139,6 +137,7 @@ class AppleEfiPkgExtract(BIOSUtility):
printer(message=f'Successful PBZX extraction via {pbzx_module.title}!', padding=padding) printer(message=f'Successful PBZX extraction via {pbzx_module.title}!', padding=padding)
for pbzx_file in path_files(in_path=pbzx_path): 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 is_szip_supported(in_path=pbzx_file, padding=padding + 4, args=['-tZIP']): if is_szip_supported(in_path=pbzx_file, padding=padding + 4, args=['-tZIP']):
zip_path: str = extract_folder(in_path=pbzx_file) zip_path: str = extract_folder(in_path=pbzx_file)
@ -156,6 +155,7 @@ class AppleEfiPkgExtract(BIOSUtility):
if szip_decompress(in_path=input_path, out_path=gzip_path, in_name='GZIP', if szip_decompress(in_path=input_path, out_path=gzip_path, in_name='GZIP',
padding=padding, args=['-tGZIP']): padding=padding, args=['-tGZIP']):
for gzip_file in path_files(in_path=gzip_path): 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 is_szip_supported(in_path=gzip_file, padding=padding + 4, args=['-tCPIO']): if is_szip_supported(in_path=gzip_file, padding=padding + 4, args=['-tCPIO']):
cpio_path: str = extract_folder(in_path=gzip_file) cpio_path: str = extract_folder(in_path=gzip_file)
@ -168,6 +168,9 @@ class AppleEfiPkgExtract(BIOSUtility):
def _im4p_id(input_path: str, output_path: str, padding: int = 0) -> None: def _im4p_id(input_path: str, output_path: str, padding: int = 0) -> None:
""" Split IM4P (if applicable), identify and rename EFI """ """ Split IM4P (if applicable), identify and rename EFI """
if not (is_file(in_path=input_path) and is_access(in_path=input_path)):
return None
if path_suffixes(in_path=input_path)[-1].lower() not in ('.fd', '.scap', '.im4p'): if path_suffixes(in_path=input_path)[-1].lower() not in ('.fd', '.scap', '.im4p'):
return None return None
@ -192,18 +195,20 @@ class AppleEfiPkgExtract(BIOSUtility):
copy_file(in_path=input_path, out_path=working_dir, metadata=True) copy_file(in_path=input_path, out_path=working_dir, metadata=True)
for efi_source in path_files(in_path=working_dir): for efi_source in path_files(in_path=working_dir):
if is_file(in_path=efi_source) and is_access(in_path=efi_source):
efi_id_module: AppleEfiIdentify = AppleEfiIdentify() efi_id_module: AppleEfiIdentify = AppleEfiIdentify()
if efi_id_module.check_format(input_object=efi_source): if efi_id_module.check_format(input_object=efi_source):
printer(message=f'Identifying EFI via {efi_id_module.title}', padding=padding + 4) printer(message=f'Identifying EFI via {efi_id_module.title}', padding=padding + 4)
if efi_id_module.parse_format(input_object=efi_source, extract_path=extract_folder(in_path=efi_source), if efi_id_module.parse_format(input_object=efi_source, extract_path=extract_folder(
padding=padding + 8): in_path=efi_source), padding=padding + 8):
efi_dest: str = os.path.join(path_parent(in_path=efi_source), efi_id_module.efi_file_name) efi_dest: str = os.path.join(path_parent(in_path=efi_source), efi_id_module.efi_file_name)
os.rename(src=efi_source, dst=efi_dest) os.rename(src=efi_source, dst=efi_dest)
for efi_final in path_files(in_path=working_dir): for efi_final in path_files(in_path=working_dir):
if is_file(in_path=efi_final) and is_access(in_path=efi_final):
copy_file(in_path=efi_final, out_path=output_path, metadata=True) copy_file(in_path=efi_final, out_path=output_path, metadata=True)
delete_dirs(in_path=working_dir) delete_dirs(in_path=working_dir)

View file

@ -11,7 +11,7 @@ import os
import stat import stat
from biosutilities.common.compression import szip_decompress from biosutilities.common.compression import szip_decompress
from biosutilities.common.paths import extract_folder, make_dirs, safe_name from biosutilities.common.paths import extract_folder, is_file, make_dirs, safe_name
from biosutilities.common.patterns import PAT_AWARD_LZH from biosutilities.common.patterns import PAT_AWARD_LZH
from biosutilities.common.system import printer from biosutilities.common.system import printer
from biosutilities.common.templates import BIOSUtility from biosutilities.common.templates import BIOSUtility
@ -77,7 +77,7 @@ class AwardBiosExtract(BIOSUtility):
padding=padding + 4) padding=padding + 4)
# Manually check if 7-Zip extracted LZH due to its CRC check issue # Manually check if 7-Zip extracted LZH due to its CRC check issue
if os.path.isfile(path=mod_path): if is_file(in_path=mod_path):
os.chmod(path=lzh_path, mode=stat.S_IWRITE) os.chmod(path=lzh_path, mode=stat.S_IWRITE)
os.remove(path=lzh_path) # Successful extraction, delete LZH archive os.remove(path=lzh_path) # Successful extraction, delete LZH archive

View file

@ -8,17 +8,44 @@ Copyright (C) 2022-2024 Plato Mavropoulos
import os import os
import subprocess import subprocess
from typing import Final
from biosutilities.common.externals import szip_path, tiano_path from biosutilities.common.externals import szip_path, tiano_path
from biosutilities.common.paths import is_dir, is_empty_dir
from biosutilities.common.system import printer from biosutilities.common.system import printer
# 7-Zip switches to auto rename, ignore passwords, ignore prompts, ignore wildcards,
# eliminate root duplication, set UTF-8 charset, suppress stdout, suppress stderr,
# suppress progress, disable headers, disable progress, disable output logs
SZIP_COMMON: Final[list[str]] = ['-aou', '-p', '-y', '-spd', '-spe', '-sccUTF-8',
'-bso0', '-bse0', '-bsp0', '-ba', '-bd', '-bb0']
# Success exit codes (0 = OK, 1 = Warnings)
SZIP_SUCCESS: Final[list[int]] = [0, 1]
def szip_code_assert(exit_code: int) -> None: def szip_code_assert(exit_code: int) -> None:
""" Check 7-Zip bad exit codes (0 OK, 1 Warning) """ """ Check 7-Zip bad exit codes (0 OK, 1 Warning) """
if exit_code not in (0, 1): if exit_code not in SZIP_SUCCESS:
raise ValueError(f'Bad exit code: {exit_code}') raise ValueError(f'Bad exit code: {exit_code}')
def szip_switches(in_switches: list[str]) -> list[str]:
""" Generate 7-Zip command line switches """
common_switches: list[str] = SZIP_COMMON
for in_switch in in_switches:
for sw_pattern in ('-p', '-ao', '-bs', '-bb', '-scc'):
if in_switch.startswith(sw_pattern):
common_switches = [sw for sw in common_switches if not sw.startswith(sw_pattern)]
break
return [*set(common_switches + in_switches), '--']
def is_szip_supported(in_path: str, padding: int = 0, args: list | None = None, silent: bool = True) -> bool: def is_szip_supported(in_path: str, padding: int = 0, args: list | None = None, silent: bool = True) -> bool:
""" Check if file is 7-Zip supported """ """ Check if file is 7-Zip supported """
@ -26,7 +53,7 @@ def is_szip_supported(in_path: str, padding: int = 0, args: list | None = None,
if args is None: if args is None:
args = [] args = []
szip_c: list[str] = [szip_path(), 't', in_path, *args, '-bso0', '-bse0', '-bsp0'] szip_c: list[str] = [szip_path(), 't', *szip_switches(in_switches=[*args]), in_path]
szip_t: subprocess.CompletedProcess[bytes] = subprocess.run(args=szip_c, check=False) szip_t: subprocess.CompletedProcess[bytes] = subprocess.run(args=szip_c, check=False)
@ -40,26 +67,23 @@ def is_szip_supported(in_path: str, padding: int = 0, args: list | None = None,
return True return True
def szip_decompress(in_path: str, out_path: str, in_name: str | None, padding: int = 0, args: list | None = None, def szip_decompress(in_path: str, out_path: str, in_name: str = 'archive', padding: int = 0, args: list | None = None,
check: bool = False, silent: bool = False) -> bool: check: bool = False, silent: bool = False) -> bool:
""" Archive decompression via 7-Zip """ """ Archive decompression via 7-Zip """
if not in_name:
in_name = 'archive'
try: try:
if args is None: if args is None:
args = [] args = []
szip_c: list[str] = [szip_path(), 'x', *args, '-aou', '-bso0', '-bse0', '-bsp0', f'-o{out_path}', in_path] szip_c: list[str] = [szip_path(), 'x', *szip_switches(in_switches=[*args, f'-o{out_path}']), in_path]
szip_x: subprocess.CompletedProcess[bytes] = subprocess.run(args=szip_c, check=False) szip_x: subprocess.CompletedProcess[bytes] = subprocess.run(args=szip_c, check=False)
if check: if check:
szip_code_assert(exit_code=szip_x.returncode) szip_code_assert(exit_code=szip_x.returncode)
if not os.path.isdir(out_path): if not (is_dir(in_path=out_path) and not is_empty_dir(in_path=out_path)):
raise OSError(f'Extraction directory not found: {out_path}') raise OSError(f'Extraction directory is empty or missing: {out_path}')
except Exception as error: # pylint: disable=broad-except except Exception as error: # pylint: disable=broad-except
if not silent: if not silent:
printer(message=f'Error: 7-Zip could not extract {in_name} file {in_path}: {error}!', padding=padding) printer(message=f'Error: 7-Zip could not extract {in_name} file {in_path}: {error}!', padding=padding)

View file

@ -16,7 +16,7 @@ from importlib.util import module_from_spec, spec_from_file_location
from types import ModuleType from types import ModuleType
from typing import Type from typing import Type
from biosutilities.common.paths import project_root from biosutilities.common.paths import is_dir, is_file, project_root
from biosutilities.common.texts import to_string from biosutilities.common.texts import to_string
@ -25,12 +25,12 @@ def get_external_path(cmd: str | list | tuple) -> str:
external_root: str = os.path.join(project_root(), 'external') external_root: str = os.path.join(project_root(), 'external')
external_path: str | None = external_root if os.path.isdir(external_root) else None external_path: str | None = external_root if is_dir(in_path=external_root) else None
for command in cmd if isinstance(cmd, (list, tuple)) else [to_string(in_object=cmd)]: for command in cmd if isinstance(cmd, (list, tuple)) else [to_string(in_object=cmd)]:
command_path: str | None = shutil.which(cmd=command, path=external_path) command_path: str | None = shutil.which(cmd=command, path=external_path)
if command_path and os.path.isfile(path=command_path): if command_path and is_file(in_path=command_path):
return 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=", ")} could not be found!')
@ -63,7 +63,7 @@ def big_script_tool() -> Type | None:
def comextract_path() -> str: def comextract_path() -> str:
""" Get ToshibaComExtractor path """ """ Get ToshibaComExtractor path """
return get_external_path(cmd='comextract') return get_external_path(cmd=['comextract', 'ComExtract'])
def szip_path() -> str: def szip_path() -> str:
@ -75,16 +75,16 @@ def szip_path() -> str:
def tiano_path() -> str: def tiano_path() -> str:
""" Get TianoCompress path """ """ Get TianoCompress path """
return get_external_path(cmd='TianoCompress') return get_external_path(cmd=['TianoCompress', 'tianocompress'])
def uefifind_path() -> str: def uefifind_path() -> str:
""" Get UEFIFind path """ """ Get UEFIFind path """
return get_external_path(cmd='UEFIFind') return get_external_path(cmd=['uefifind', 'UEFIFind'])
def uefiextract_path() -> str: def uefiextract_path() -> str:
""" Get UEFIExtract path """ """ Get UEFIExtract path """
return get_external_path(cmd='UEFIExtract') return get_external_path(cmd=['uefiextract', 'UEFIExtract'])

View file

@ -131,7 +131,7 @@ def make_dirs(in_path: str, parents: bool = True, exist_ok: bool = False, delete
def delete_dirs(in_path: str) -> None: def delete_dirs(in_path: str) -> None:
""" Delete folder(s), if present """ """ Delete folder(s), if present """
if Path(in_path).is_dir(): if is_dir(in_path=in_path):
shutil.rmtree(path=in_path, onerror=clear_readonly_callback) # pylint: disable=deprecated-argument shutil.rmtree(path=in_path, onerror=clear_readonly_callback) # pylint: disable=deprecated-argument
@ -167,18 +167,54 @@ def clear_readonly_callback(in_func: Callable, in_path: str, _) -> None:
in_func(path=in_path) in_func(path=in_path)
def path_files(in_path: str, follow_links: bool = False) -> list[str]: def path_files(in_path: str, follow_links: bool = False, root_only: bool = False) -> list[str]:
""" Walk path to get all files """ """ Walk path to get all files """
file_paths: list[str] = [] file_paths: list[str] = []
for root, _, filenames in os.walk(top=in_path, followlinks=follow_links): for root_path, _, file_names in os.walk(top=in_path, followlinks=follow_links):
for filename in filenames: for file_name in file_names:
file_paths.append(os.path.abspath(path=os.path.join(root, filename))) file_path: str = os.path.abspath(path=os.path.join(root_path, file_name))
if is_file(in_path=file_path):
file_paths.append(file_path)
if root_only:
break
return file_paths return file_paths
def is_dir(in_path: str) -> bool:
""" Check if path is a directory """
return Path(in_path).is_dir()
def is_file(in_path: str, allow_broken_links: bool = False) -> bool:
""" Check if path is a regural file or symlink (valid or broken) """
in_path_abs: str = os.path.abspath(path=in_path)
if os.path.lexists(path=in_path_abs):
if not is_dir(in_path=in_path_abs):
if allow_broken_links:
return os.path.isfile(path=in_path_abs) or os.path.islink(path=in_path_abs)
return os.path.isfile(path=in_path_abs)
return False
def is_access(in_path: str, access_mode: int = os.R_OK, follow_links: bool = False) -> bool:
""" Check if path is accessible """
if not follow_links and os.access not in os.supports_follow_symlinks:
follow_links = True
return os.access(path=in_path, mode=access_mode, follow_symlinks=follow_links)
def is_empty_dir(in_path: str, follow_links: bool = False) -> bool: def is_empty_dir(in_path: str, follow_links: bool = False) -> bool:
""" Check if directory is empty (file-wise) """ """ Check if directory is empty (file-wise) """

View file

@ -31,18 +31,6 @@ PAT_APPLE_PBZX: Final[re.Pattern[bytes]] = re.compile(
pattern=br'pbzx' pattern=br'pbzx'
) )
PAT_APPLE_PKG_DMG: Final[re.Pattern[bytes]] = re.compile(
pattern=br'EFI PART'
)
PAT_APPLE_PKG_TAR: Final[re.Pattern[bytes]] = re.compile(
pattern=br'<key>IFPkgDescriptionDescription</key>'
)
PAT_APPLE_PKG_XAR: Final[re.Pattern[bytes]] = re.compile(
pattern=br'xar!'
)
PAT_AWARD_LZH: Final[re.Pattern[bytes]] = re.compile( PAT_AWARD_LZH: Final[re.Pattern[bytes]] = re.compile(
pattern=br'-lh[04567]-' pattern=br'-lh[04567]-'
) )

View file

@ -12,8 +12,8 @@ from argparse import ArgumentParser, Namespace
from typing import Final from typing import Final
from biosutilities import __version__ from biosutilities import __version__
from biosutilities.common.paths import (delete_dirs, extract_folder, is_empty_dir, path_files, from biosutilities.common.paths import (delete_dirs, extract_folder, is_access, is_dir, is_file, is_empty_dir,
path_name, path_parent, real_path, runtime_root) path_files, path_name, path_parent, real_path, runtime_root)
from biosutilities.common.system import system_platform, python_version, printer from biosutilities.common.system import system_platform, python_version, printer
from biosutilities.common.texts import remove_quotes, to_boxed, to_ordinal from biosutilities.common.texts import remove_quotes, to_boxed, to_ordinal
@ -76,11 +76,11 @@ class BIOSUtility:
extract_path: str = os.path.join(self._output_path, extract_folder(in_path=input_name)) extract_path: str = os.path.join(self._output_path, extract_folder(in_path=input_name))
if os.path.isdir(extract_path): if is_dir(in_path=extract_path):
for suffix in range(2, self.MAX_FAT32_ITEMS): for suffix in range(2, self.MAX_FAT32_ITEMS):
renamed_path: str = f'{os.path.normpath(path=extract_path)}_{to_ordinal(in_number=suffix)}' renamed_path: str = f'{os.path.normpath(path=extract_path)}_{to_ordinal(in_number=suffix)}'
if not os.path.isdir(renamed_path): if not is_dir(in_path=renamed_path):
extract_path = renamed_path extract_path = renamed_path
break break
@ -121,9 +121,11 @@ class BIOSUtility:
for input_path in [input_path for input_path in input_paths if input_path]: 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) input_path_real: str = real_path(in_path=input_path)
if os.path.isdir(input_path_real): if is_dir(in_path=input_path_real):
self._input_files.extend(path_files(input_path_real)) for input_file in path_files(in_path=input_path_real):
else: if is_file(in_path=input_file) and is_access(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):
self._input_files.append(input_path_real) self._input_files.append(input_path_real)
def _setup_output_dir(self, padding: int = 0) -> None: def _setup_output_dir(self, padding: int = 0) -> None:
@ -137,7 +139,10 @@ class BIOSUtility:
if not output_path and self._input_files: if not output_path and self._input_files:
output_path = str(path_parent(in_path=self._input_files[0])) output_path = str(path_parent(in_path=self._input_files[0]))
self._output_path = output_path or runtime_root() if output_path and is_dir(in_path=output_path) and is_access(in_path=output_path):
self._output_path = output_path
else:
self._output_path = runtime_root()
def _check_sys_py(self) -> None: def _check_sys_py(self) -> None:
""" Check Python Version """ """ Check Python Version """

View file

@ -19,8 +19,8 @@ from typing import Any, Final
from biosutilities.common.checksums import checksum_8_xor from biosutilities.common.checksums import checksum_8_xor
from biosutilities.common.compression import is_szip_supported, szip_decompress from biosutilities.common.compression import is_szip_supported, szip_decompress
from biosutilities.common.paths import (delete_dirs, path_files, make_dirs, path_name, from biosutilities.common.paths import (delete_dirs, path_files, is_access, is_file, make_dirs,
path_parent, path_stem, safe_name) 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.patterns import PAT_DELL_FTR, PAT_DELL_HDR, PAT_DELL_PKG
from biosutilities.common.structs import CHAR, ctypes_struct, UINT8, UINT16, UINT32, UINT64 from biosutilities.common.structs import CHAR, ctypes_struct, UINT8, UINT16, UINT32, UINT64
from biosutilities.common.system import printer from biosutilities.common.system import printer
@ -265,8 +265,8 @@ class DellPfsExtract(BIOSUtility):
pfs_results: dict[str, bytes] = self._thinos_pkg_extract( pfs_results: dict[str, bytes] = self._thinos_pkg_extract(
input_object=input_buffer, extract_path=extract_path) input_object=input_buffer, extract_path=extract_path)
else: else:
pfs_results = {path_stem(in_path=str(input_object)) if os.path.isfile(path=input_object) pfs_results = {path_stem(in_path=input_object) if isinstance(input_object, str) and is_file(
else 'Image': input_buffer} in_path=input_object) else 'Image': input_buffer}
# Parse each Dell PFS image contained in the input file # Parse each Dell PFS image contained in the input file
for pfs_index, (pfs_name, pfs_buffer) in enumerate(iterable=pfs_results.items(), start=1): for pfs_index, (pfs_name, pfs_buffer) in enumerate(iterable=pfs_results.items(), start=1):
@ -363,8 +363,9 @@ class DellPfsExtract(BIOSUtility):
return pfs_results return pfs_results
for pkg_file in path_files(in_path=working_path): 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 self._is_pfs_hdr(input_object=pkg_file): if self._is_pfs_hdr(input_object=pkg_file):
pfs_name: str = path_name(in_path=str(path_parent(pkg_file))) pfs_name: str = path_name(in_path=str(path_parent(in_path=pkg_file)))
pfs_results.update({pfs_name: file_to_bytes(in_object=pkg_file)}) pfs_results.update({pfs_name: file_to_bytes(in_object=pkg_file)})

View file

@ -10,7 +10,7 @@ Copyright (C) 2021-2024 Plato Mavropoulos
import os import os
from biosutilities.common.compression import efi_decompress, is_efi_compressed from biosutilities.common.compression import efi_decompress, is_efi_compressed
from biosutilities.common.paths import make_dirs, path_name, path_suffixes from biosutilities.common.paths import make_dirs, is_file, path_name, path_suffixes
from biosutilities.common.templates import BIOSUtility from biosutilities.common.templates import BIOSUtility
from biosutilities.common.texts import file_to_bytes from biosutilities.common.texts import file_to_bytes
@ -24,7 +24,7 @@ class FujitsuUpcExtract(BIOSUtility):
""" Check if input is Fujitsu UPC image """ """ Check if input is Fujitsu UPC image """
is_upc: bool = False is_upc: bool = False
if isinstance(input_object, str) and os.path.isfile(path=input_object): if isinstance(input_object, str) and is_file(in_path=input_object):
is_upc = path_suffixes(input_object)[-1].upper() == '.UPC' is_upc = path_suffixes(input_object)[-1].upper() == '.UPC'
elif isinstance(input_object, (bytes, bytearray)): elif isinstance(input_object, (bytes, bytearray)):
is_upc = True is_upc = True
@ -39,7 +39,7 @@ class FujitsuUpcExtract(BIOSUtility):
make_dirs(in_path=extract_path, delete=True) make_dirs(in_path=extract_path, delete=True)
if isinstance(input_object, str) and os.path.isfile(path=input_object): if isinstance(input_object, str) and is_file(in_path=input_object):
input_name: str = path_name(in_path=input_object) input_name: str = path_name(in_path=input_object)
input_path: str = input_object input_path: str = input_object

View file

@ -14,7 +14,8 @@ import re
from typing import Any, Final from typing import Any, Final
from biosutilities.common.compression import is_szip_supported, szip_decompress from biosutilities.common.compression import is_szip_supported, szip_decompress
from biosutilities.common.paths import extract_folder, path_files, make_dirs, path_name, safe_name from biosutilities.common.paths import (extract_folder, is_access, is_file, path_files,
make_dirs, path_name, safe_name)
from biosutilities.common.patterns import PAT_INSYDE_IFL, PAT_INSYDE_SFX from biosutilities.common.patterns import PAT_INSYDE_IFL, PAT_INSYDE_SFX
from biosutilities.common.structs import CHAR, ctypes_struct, UINT32 from biosutilities.common.structs import CHAR, ctypes_struct, UINT32
from biosutilities.common.system import printer from biosutilities.common.system import printer
@ -229,6 +230,7 @@ class InsydeIfdExtract(BIOSUtility):
exit_codes: list[int] = [] exit_codes: list[int] = []
for sfx_file in path_files(in_path=extract_path): 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 self.check_format(input_object=sfx_file): if self.check_format(input_object=sfx_file):
printer(message=path_name(in_path=sfx_file), padding=padding + 12) printer(message=path_name(in_path=sfx_file), padding=padding + 12)

View file

@ -20,7 +20,7 @@ import pefile
from dissect.util.compression import lznt1 from dissect.util.compression import lznt1
from biosutilities.common.compression import is_szip_supported, szip_decompress from biosutilities.common.compression import is_szip_supported, szip_decompress
from biosutilities.common.paths import path_files, make_dirs, path_stem, safe_name from biosutilities.common.paths import is_access, is_file, 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.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.patterns import PAT_MICROSOFT_CAB
from biosutilities.common.system import printer from biosutilities.common.system import printer
@ -97,7 +97,7 @@ class PanasonicBiosExtract(BIOSUtility):
def _panasonic_pkg_name(input_object: str | bytes | bytearray) -> str: def _panasonic_pkg_name(input_object: str | bytes | bytearray) -> str:
""" Get Panasonic BIOS Package file name, when applicable """ """ Get Panasonic BIOS Package file name, when applicable """
if isinstance(input_object, str) and os.path.isfile(path=input_object): if isinstance(input_object, str) and is_file(in_path=input_object):
return safe_name(in_name=path_stem(in_path=input_object)) return safe_name(in_name=path_stem(in_path=input_object))
return '' return ''
@ -129,6 +129,7 @@ class PanasonicBiosExtract(BIOSUtility):
os.remove(path=cab_path) # Successful extraction, delete CAB archive os.remove(path=cab_path) # Successful extraction, delete CAB archive
for extracted_file_path in path_files(in_path=extract_path): 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):
extracted_pe_file: pefile.PE | None = ms_pe( extracted_pe_file: pefile.PE | None = ms_pe(
in_file=extracted_file_path, padding=padding, silent=True) in_file=extracted_file_path, padding=padding, silent=True)

View file

@ -17,7 +17,7 @@ from typing import Any, Final
from pefile import PE from pefile import PE
from biosutilities.common.paths import make_dirs, safe_name from biosutilities.common.paths import is_file, make_dirs, safe_name
from biosutilities.common.executables import ms_pe, ms_pe_info 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.patterns import PAT_MICROSOFT_MZ, PAT_MICROSOFT_PE, PAT_PHOENIX_TDK
from biosutilities.common.structs import CHAR, ctypes_struct, UINT32 from biosutilities.common.structs import CHAR, ctypes_struct, UINT32
@ -192,7 +192,7 @@ class PhoenixTdkExtract(BIOSUtility):
mod_file: str = os.path.join(extract_path, safe_name(mod_name)) mod_file: str = os.path.join(extract_path, safe_name(mod_name))
# Account for potential duplicate file names # Account for potential duplicate file names
if os.path.isfile(path=mod_file): if is_file(in_path=mod_file):
mod_file += f'_{entry_index + 1:02d}' mod_file += f'_{entry_index + 1:02d}'
# Save TDK Entry data to output file # Save TDK Entry data to output file

View file

@ -11,7 +11,7 @@ import os
import subprocess import subprocess
from biosutilities.common.externals import comextract_path from biosutilities.common.externals import comextract_path
from biosutilities.common.paths import make_dirs, path_stem, safe_name from biosutilities.common.paths import is_file, make_dirs, path_stem, safe_name
from biosutilities.common.patterns import PAT_TOSHIBA_COM from biosutilities.common.patterns import PAT_TOSHIBA_COM
from biosutilities.common.system import printer from biosutilities.common.system import printer
from biosutilities.common.templates import BIOSUtility from biosutilities.common.templates import BIOSUtility
@ -35,7 +35,7 @@ class ToshibaComExtract(BIOSUtility):
make_dirs(in_path=extract_path, delete=True) make_dirs(in_path=extract_path, delete=True)
if isinstance(input_object, str) and os.path.isfile(path=input_object): if isinstance(input_object, str) and is_file(in_path=input_object):
input_path: str = input_object input_path: str = input_object
else: else:
input_path = os.path.join(extract_path, 'toshiba_bios.com') input_path = os.path.join(extract_path, 'toshiba_bios.com')
@ -50,7 +50,7 @@ class ToshibaComExtract(BIOSUtility):
try: try:
subprocess.run([comextract_path(), input_path, output_path], check=True, stdout=subprocess.DEVNULL) subprocess.run([comextract_path(), input_path, output_path], check=True, stdout=subprocess.DEVNULL)
if not os.path.isfile(path=output_path): if not is_file(in_path=output_path):
raise FileNotFoundError('EXTRACTED_FILE_MISSING') raise FileNotFoundError('EXTRACTED_FILE_MISSING')
except Exception as error: # pylint: disable=broad-except except Exception as error: # pylint: disable=broad-except
printer(message=f'Error: ToshibaComExtractor could not extract {input_path}: {error}!', padding=padding) printer(message=f'Error: ToshibaComExtractor could not extract {input_path}: {error}!', padding=padding)