BIOSUtilities/biosutilities/apple_efi_pkg.py
Plato Mavropoulos b174ce40e6 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
2024-10-10 02:18:17 +03:00

220 lines
10 KiB
Python

#!/usr/bin/env python3 -B
# coding=utf-8
"""
Apple EFI PKG
Apple EFI Package Extractor
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, extract_folder, is_access, is_file, make_dirs,
path_files, path_name, path_parent, path_suffixes, runtime_root)
from biosutilities.common.system import printer
from biosutilities.common.templates import BIOSUtility
from biosutilities.common.texts import file_to_bytes
from biosutilities.apple_efi_id import AppleEfiIdentify
from biosutilities.apple_efi_im4p import AppleEfiIm4pSplit
from biosutilities.apple_efi_pbzx import AppleEfiPbzxExtract
class AppleEfiPkgExtract(BIOSUtility):
""" Apple EFI Package Extractor """
TITLE: str = 'Apple EFI Package Extractor'
def check_format(self, input_object: str | bytes | bytearray) -> bool:
""" Check if input is Apple EFI PKG package """
is_apple_efi_pkg: bool = False
input_buffer: bytes = file_to_bytes(in_object=input_object)
if isinstance(input_object, str) and is_file(in_path=input_object):
input_path: str = input_object
else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_CHECK.bin')
with open(file=input_path, mode='wb') as input_path_object:
input_path_object.write(input_buffer)
for pkg_type in ('XAR', 'TAR', 'DMG'):
if is_szip_supported(in_path=input_path, args=[f'-t{pkg_type}:s0']):
is_apple_efi_pkg = True
break
if input_path != input_object:
os.remove(path=input_path)
return is_apple_efi_pkg
def parse_format(self, input_object: str | bytes | bytearray, extract_path: str, padding: int = 0) -> bool:
""" Parse & Extract Apple EFI PKG packages """
if isinstance(input_object, str) and is_file(in_path=input_object):
input_path: str = input_object
else:
input_path = os.path.join(runtime_root(), 'APPLE_EFI_PKG_INPUT_BUFFER_PARSE.bin')
with open(file=input_path, mode='wb') as input_path_object:
input_path_object.write(file_to_bytes(in_object=input_object))
make_dirs(in_path=extract_path, delete=True)
working_dir: str = os.path.join(extract_path, 'temp')
make_dirs(in_path=working_dir)
for pkg_type in ('XAR', 'TAR', 'DMG'):
if is_szip_supported(in_path=input_path, padding=padding, args=[f'-t{pkg_type}']):
if szip_decompress(in_path=input_path, out_path=working_dir, in_name=pkg_type, padding=padding,
args=None if pkg_type == 'DMG' else [f'-t{pkg_type}']):
break
else:
return False
if input_path != input_object:
os.remove(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):
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._dmg_zip(input_path=work_file, extract_path=extract_path, padding=padding + 4)
self._xar_gzip(input_path=work_file, extract_path=extract_path, padding=padding + 4)
delete_dirs(in_path=working_dir)
return True
def _xar_gzip(self, input_path: str, extract_path: str, padding: int = 0) -> None:
""" XAR/TAR > GZIP """
for pkg_type in ('XAR', 'TAR'):
if is_szip_supported(in_path=input_path, padding=padding, args=[f'-t{pkg_type}']):
pkg_path: str = extract_folder(in_path=input_path, suffix=f'_{pkg_type.lower()}_gzip')
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):
self._gzip_cpio(input_path=pkg_file, extract_path=extract_path, padding=padding + 4)
break
def _dmg_zip(self, input_path: str, extract_path: str, padding: int = 0) -> None:
""" DMG > ZIP """
if is_szip_supported(in_path=input_path, padding=padding, args=['-tDMG']):
dmg_path: str = extract_folder(in_path=input_path, suffix='_dmg_zip')
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 is_szip_supported(in_path=dmg_file, padding=padding + 4, 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, output_path=extract_path, padding=padding + 8)
def _pbzx_zip(self, input_path: str, extract_path: str, padding: int = 0) -> None:
""" PBZX > ZIP """
pbzx_module: AppleEfiPbzxExtract = AppleEfiPbzxExtract()
if pbzx_module.check_format(input_object=input_path):
printer(message=f'Extracting PBZX via {pbzx_module.title}', padding=padding)
pbzx_path: str = extract_folder(in_path=input_path, suffix='_pbzx_zip')
if pbzx_module.parse_format(input_object=input_path, extract_path=pbzx_path, padding=padding + 4):
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 is_szip_supported(in_path=pbzx_file, padding=padding + 4, 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, output_path=extract_path, padding=padding + 8)
def _gzip_cpio(self, input_path: str, extract_path: str, padding: int = 0) -> None:
""" GZIP > CPIO """
if is_szip_supported(in_path=input_path, padding=padding, args=['-tGZIP']):
gzip_path: str = extract_folder(in_path=input_path, suffix='_gzip_cpio')
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 is_szip_supported(in_path=gzip_file, padding=padding + 4, 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, output_path=extract_path, padding=padding + 8)
@staticmethod
def _im4p_id(input_path: str, output_path: str, padding: int = 0) -> None:
""" 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'):
return None
if not AppleEfiIdentify().check_format(input_object=input_path):
return None
input_name: str = path_name(in_path=input_path)
printer(message=input_name, padding=padding)
working_dir: str = extract_folder(in_path=input_path)
im4p_module: AppleEfiIm4pSplit = AppleEfiIm4pSplit()
if im4p_module.check_format(input_object=input_path):
printer(message=f'Splitting IM4P via {im4p_module.title}', padding=padding + 4)
im4p_module.parse_format(input_object=input_path, extract_path=working_dir, padding=padding + 8)
else:
make_dirs(in_path=working_dir, delete=True)
copy_file(in_path=input_path, out_path=working_dir, metadata=True)
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()
if efi_id_module.check_format(input_object=efi_source):
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), padding=padding + 8):
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)
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)
delete_dirs(in_path=working_dir)
return None
if __name__ == '__main__':
AppleEfiPkgExtract().run_utility()