Created common template for executing all utilities

Unified extracted output directory naming logic

Multiple code fixes, refactors and improvements
This commit is contained in:
platomav 2022-09-12 23:09:12 +03:00
parent 5f364f4759
commit 6de50c422f
26 changed files with 377 additions and 1169 deletions

View file

@ -45,7 +45,7 @@ def efi_decompress(in_path, out_path, padding=0, silent=False, comp_type='--uefi
if os.path.getsize(out_path) != size_orig:
raise Exception('EFI_DECOMPRESS_ERROR')
except:
except Exception:
if not silent:
printer(f'Error: TianoCompress could not extract file {in_path}!', padding)

View file

@ -34,7 +34,7 @@ def is_szip_supported(in_path, padding=0, args=None, check=False, silent=False):
if check:
check_bad_exit_code(szip_t.returncode)
except:
except Exception:
if not silent:
printer(f'Error: 7-Zip could not check support for file {in_path}!', padding)
@ -60,7 +60,7 @@ def szip_decompress(in_path, out_path, in_name, padding=0, args=None, check=Fals
if not os.path.isdir(out_path):
raise Exception('EXTRACT_DIR_MISSING')
except:
except Exception:
if not silent:
printer(f'Error: 7-Zip could not extract {in_name} file {in_path}!', padding)

View file

@ -12,8 +12,9 @@ from common.system import get_os_ver
# https://github.com/platomav/BGScriptTool by Plato Mavropoulos
def get_bgs_tool():
try:
from external.big_script_tool import BigScript
except:
# noinspection PyUnresolvedReferences
from external.big_script_tool import BigScript # pylint: disable=E0401,E0611
except Exception:
BigScript = None
return BigScript
@ -22,10 +23,16 @@ def get_bgs_tool():
def get_uefifind_path():
exec_name = f'UEFIFind{".exe" if get_os_ver()[1] else ""}'
return safe_path(project_root(), ['external',exec_name])
return safe_path(project_root(), ['external', exec_name])
# Get UEFIExtract path
def get_uefiextract_path():
exec_name = f'UEFIExtract{".exe" if get_os_ver()[1] else ""}'
return safe_path(project_root(), ['external',exec_name])
return safe_path(project_root(), ['external', exec_name])
# Get ToshibaComExtractor path
def get_comextract_path():
exec_name = f'comextract{".exe" if get_os_ver()[1] else ""}'
return safe_path(project_root(), ['external', exec_name])

View file

@ -130,58 +130,13 @@ def get_dequoted_path(in_path):
return out_path
# Get absolute file path of argparse object
def get_argparse_path(argparse_path):
if not argparse_path:
# Use runtime directory if no user path is specified
absolute_path = runtime_root()
else:
# Check if user specified path is absolute
if is_path_absolute(argparse_path):
absolute_path = argparse_path
# Otherwise, make it runtime directory relative
else:
absolute_path = safe_path(runtime_root(), argparse_path)
return absolute_path
# Set utility extraction stem
def extract_suffix():
return '_extracted'
# Process input files (argparse object)
def process_input_files(argparse_args, sys_argv=None):
input_files = []
if sys_argv is None:
sys_argv = []
if len(sys_argv) >= 2:
# Drag & Drop or CLI
if argparse_args.input_dir:
input_path_user = argparse_args.input_dir
input_path_full = get_argparse_path(input_path_user) if input_path_user else ''
input_files = get_path_files(input_path_full)
else:
# Parse list of input files (i.e. argparse FileType objects)
for file_object in argparse_args.files:
# Store each argparse FileType object's name (i.e. path)
input_files.append(file_object.name)
# Close each argparse FileType object (i.e. allow input file changes)
file_object.close()
# Set output fallback value for missing argparse Output and Input Path
output_fallback = path_parent(input_files[0]) if input_files else None
# Set output path via argparse Output path or argparse Input path or first input file path
output_path = argparse_args.output_dir or argparse_args.input_dir or output_fallback
else:
# Script w/o parameters
input_path_user = get_dequoted_path(input('\nEnter input directory path: '))
input_path_full = get_argparse_path(input_path_user) if input_path_user else ''
input_files = get_path_files(input_path_full)
output_path = get_dequoted_path(input('\nEnter output directory path: '))
output_path_final = get_argparse_path(output_path)
return input_files, output_path_final
# Get utility extraction path
def get_extract_path(in_path, suffix=extract_suffix()):
return f'{in_path}{suffix}'
# Get project's root directory
def project_root():

View file

@ -21,7 +21,7 @@ def get_pe_file(in_file, fast=True):
try:
# Analyze detected MZ > PE image buffer
pe_file = pefile.PE(data=in_buffer, fast_load=fast)
except:
except Exception:
pe_file = None
return pe_file
@ -34,7 +34,7 @@ def get_pe_info(pe_file):
# Retrieve MZ > PE > FileInfo > StringTable information
pe_info = pe_file.FileInfo[0][0].StringTable[0].entries
except:
except Exception:
pe_info = {}
return pe_info

View file

@ -6,12 +6,8 @@ Copyright (C) 2022 Plato Mavropoulos
"""
import sys
import ctypes
import argparse
import traceback
from common.text_ops import padder, to_string
from common.path_ops import process_input_files
# Get Python Version (tuple)
def get_py_ver():
@ -59,62 +55,6 @@ def check_sys_os():
if os_win:
sys.stdout.reconfigure(encoding='utf-8')
# Initialize common argparse arguments
def argparse_init():
argparser = argparse.ArgumentParser()
argparser.add_argument('files', type=argparse.FileType('r'), nargs='*')
argparser.add_argument('-e', '--auto-exit', help='skip press enter to exit prompts', action='store_true')
argparser.add_argument('-v', '--version', help='show utility name and version', action='store_true')
argparser.add_argument('-o', '--output-dir', help='extract in given output directory')
argparser.add_argument('-i', '--input-dir', help='extract from given input directory')
return argparser
# Initialize Script (must be after argparse)
def script_init(title, arguments, padding=0):
# Pretty Python exception handler
sys.excepthook = nice_exc_handler
# Check Python Version
check_sys_py()
# Check OS Platform
check_sys_os()
# Show Script Title
printer(title, new_line=False)
# Show Utility Version on demand
if arguments.version:
sys.exit(0)
# Set console/terminal window title (Windows only)
if get_os_ver()[1]:
ctypes.windll.kernel32.SetConsoleTitleW(title)
# Process input files and generate output path
input_files,output_path = process_input_files(arguments, sys.argv)
# Count input files for exit code
input_count = len(input_files)
return input_count, input_files, output_path, padding
# https://stackoverflow.com/a/781074 by Torsten Marek
def nice_exc_handler(exc_type, exc_value, tb):
if exc_type is KeyboardInterrupt:
printer('')
else:
printer('Error: Script crashed, please report the following:\n')
traceback.print_exception(exc_type, exc_value, tb)
if not is_auto_exit():
input('\nPress enter to exit')
sys.exit(127)
# Show message(s) while controlling padding, newline, pausing & separator
def printer(in_message='', padd_count=0, new_line=True, pause=False, sep_char=' '):
message = to_string(in_message, sep_char)

152
common/templates.py Normal file
View file

@ -0,0 +1,152 @@
#!/usr/bin/env python3
#coding=utf-8
"""
Copyright (C) 2022 Plato Mavropoulos
"""
import os
import sys
import ctypes
import argparse
import traceback
from common.path_ops import runtime_root, is_path_absolute, safe_path, get_dequoted_path, get_path_files, path_parent, get_extract_path
from common.system import check_sys_py, check_sys_os, get_os_ver, printer, is_auto_exit
class BIOSUtility:
def __init__(self, title, check, main, padding=0):
self._title = title
self._main = main
self._check = check
self._padding = padding
self._arguments_kw = {}
# Initialize argparse argument parser
self._argparser = argparse.ArgumentParser()
self._argparser.add_argument('files', type=argparse.FileType('r', encoding='utf-8'), nargs='*')
self._argparser.add_argument('-e', '--auto-exit', help='skip press enter to exit prompts', action='store_true')
self._argparser.add_argument('-v', '--version', help='show utility name and version', action='store_true')
self._argparser.add_argument('-o', '--output-dir', help='extract in given output directory')
self._argparser.add_argument('-i', '--input-dir', help='extract from given input directory')
self._arguments,self._arguments_unk = self._argparser.parse_known_args()
# Managed Python exception handler
sys.excepthook = self._exception_handler
# Check Python Version
check_sys_py()
# Check OS Platform
check_sys_os()
# Show Script Title
printer(self._title, new_line=False)
# Show Utility Version on demand
if self._arguments.version:
sys.exit(0)
# Set console/terminal window title (Windows only)
if get_os_ver()[1]:
ctypes.windll.kernel32.SetConsoleTitleW(self._title)
# Process input files and generate output path
self._process_input_files()
# Count input files for exit code
self.exit_code = len(self._input_files)
def parse_argument(self, *args, **kwargs):
_dest = self._argparser.add_argument(*args, **kwargs).dest
self._arguments = self._argparser.parse_known_args(self._arguments_unk)[0]
self._arguments_kw.update({_dest: self._arguments.__dict__[_dest]})
def run_utility(self):
for _input_file in self._input_files:
_input_name = os.path.basename(_input_file)
printer(['***', _input_name], self._padding)
if not self._check(_input_file):
printer('Error: This is not a supported input!', self._padding + 4)
continue # Next input file
_extract_path = os.path.join(self._output_path, get_extract_path(_input_name))
if self._main(_input_file, _extract_path, self._padding + 4, **self._arguments_kw) in [0, None]:
self.exit_code -= 1
#print(self.exit_code)
printer('Done!', pause=True)
sys.exit(self.exit_code)
# Process input files
def _process_input_files(self):
self._input_files = []
if len(sys.argv) >= 2:
# Drag & Drop or CLI
if self._arguments.input_dir:
_input_path_user = self._arguments.input_dir
_input_path_full = self._get_input_path(_input_path_user) if _input_path_user else ''
self._input_files = get_path_files(_input_path_full)
else:
# Parse list of input files (i.e. argparse FileType objects)
for _file_object in self._arguments.files:
# Store each argparse FileType object's name (i.e. path)
self._input_files.append(_file_object.name)
# Close each argparse FileType object (i.e. allow input file changes)
_file_object.close()
# Set output fallback value for missing argparse Output and Input Path
_output_fallback = path_parent(self._input_files[0]) if self._input_files else None
# Set output path via argparse Output path or argparse Input path or first input file path
_output_path = self._arguments.output_dir or self._arguments.input_dir or _output_fallback
else:
# Script w/o parameters
_input_path_user = get_dequoted_path(input('\nEnter input directory path: '))
_input_path_full = self._get_input_path(_input_path_user) if _input_path_user else ''
self._input_files = get_path_files(_input_path_full)
_output_path = get_dequoted_path(input('\nEnter output directory path: '))
self._output_path = self._get_input_path(_output_path)
# Get absolute input file path
@staticmethod
def _get_input_path(input_path):
if not input_path:
# Use runtime directory if no user path is specified
absolute_path = runtime_root()
else:
# Check if user specified path is absolute
if is_path_absolute(input_path):
absolute_path = input_path
# Otherwise, make it runtime directory relative
else:
absolute_path = safe_path(runtime_root(), input_path)
return absolute_path
# https://stackoverflow.com/a/781074 by Torsten Marek
@staticmethod
def _exception_handler(exc_type, exc_value, exc_traceback):
if exc_type is KeyboardInterrupt:
printer('')
else:
printer('Error: Utility crashed, please report the following:\n')
traceback.print_exception(exc_type, exc_value, exc_traceback)
if not is_auto_exit():
input('\nPress enter to exit')
sys.exit(127)