2015-04-02 16:04:37 +08:00
/* uefiextract_main.cpp
2018-04-30 13:33:19 +08:00
Copyright ( c ) 2018 , LongSoft . All rights reserved .
2015-04-02 16:04:37 +08:00
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution . The full text of the license may be found at
http : //opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN " AS IS " BASIS ,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND , EITHER EXPRESS OR IMPLIED .
*/
2016-07-09 17:18:11 +08:00
2015-04-02 16:04:37 +08:00
# include <iostream>
2018-07-13 05:17:08 +08:00
# include <fstream>
2018-07-13 05:31:46 +08:00
# include <cstring>
2018-07-13 05:17:08 +08:00
# include <cstdlib>
2015-04-02 16:04:37 +08:00
2018-05-22 05:59:23 +08:00
# include "../version.h"
2018-07-13 05:17:08 +08:00
# include "../common/basetypes.h"
# include "../common/ustring.h"
# include "../common/filesystem.h"
2015-04-04 21:22:52 +08:00
# include "../common/ffsparser.h"
2016-06-25 18:22:28 +08:00
# include "../common/ffsreport.h"
2018-08-02 10:37:09 +08:00
# include "../common/guiddatabase.h"
2015-04-02 16:04:37 +08:00
# include "ffsdumper.h"
2018-08-02 09:10:39 +08:00
# include "uefidump.h"
2015-04-02 16:04:37 +08:00
2018-06-03 02:59:57 +08:00
enum ReadType {
READ_INPUT ,
READ_OUTPUT ,
READ_MODE ,
READ_SECTION
} ;
2023-02-16 08:54:32 +08:00
void print_usage ( )
{
std : : cout < < " UEFIExtract " PROGRAM_VERSION < < std : : endl
< < " Usage: UEFIExtract {-h | --help | -v | --version} - show help and/or version information. " < < std : : endl
2023-04-24 07:46:59 +08:00
< < " UEFIExtract imagefile - generate report and GUID database, then dump only leaf tree items into .dump folder. " < < std : : endl
< < " UEFIExtract imagefile all - generate report and GUID database, then dump all tree items into .dump folder. " < < std : : endl
< < " UEFIExtract imagefile unpack - generate report, then dump all tree items into a single .dump folder (legacy UEFIDump compatibility mode). " < < std : : endl
< < " UEFIExtract imagefile dump - only generate dump, no report or GUID database needed. " < < std : : endl
< < " UEFIExtract imagefile report - only generate report, no dump or GUID database needed. " < < std : : endl
< < " UEFIExtract imagefile guids - only generate GUID database, no dump or report needed. " < < std : : endl
2023-02-16 08:54:32 +08:00
< < " UEFIExtract imagefile GUID_1 ... [ -o FILE_1 ... ] [ -m MODE_1 ... ] [ -t TYPE_1 ... ] - " < < std : : endl
2023-04-24 07:46:59 +08:00
< < " Dump only FFS file(s) with specific GUID(s), without report or GUID database. " < < std : : endl
2023-02-16 08:54:32 +08:00
< < " Type is section type or FF to ignore. Mode is one of: all, body, header, info, file. " < < std : : endl
2023-04-24 07:46:59 +08:00
< < " Return value is a bit mask where 0 at position N means that file with GUID_N was found and unpacked, 1 otherwise. " < < std : : endl ;
2023-02-16 08:54:32 +08:00
}
2015-04-02 16:04:37 +08:00
int main ( int argc , char * argv [ ] )
{
2018-08-02 10:37:09 +08:00
initGuidDatabase ( " guids.csv " ) ;
2023-04-24 07:46:59 +08:00
if ( argc < = 1 ) {
print_usage ( ) ;
return 1 ;
}
// Help and version
if ( argc = = 2 ) {
UString arg = UString ( argv [ 1 ] ) ;
if ( arg = = UString ( " -h " ) | | arg = = UString ( " --help " ) ) {
print_usage ( ) ;
return 0 ;
2018-08-02 09:10:39 +08:00
}
2023-04-24 07:46:59 +08:00
else if ( arg = = UString ( " -v " ) | | arg = = UString ( " --version " ) ) {
std : : cout < < PROGRAM_VERSION < < std : : endl ;
return 0 ;
2016-07-15 03:22:51 +08:00
}
2023-04-24 07:46:59 +08:00
}
// Check that input file exists
USTATUS result ;
UByteArray buffer ;
UString path = getAbsPath ( argv [ 1 ] ) ;
2023-06-20 09:01:25 +08:00
if ( false = = readFileIntoBuffer ( path , buffer ) )
return U_FILE_OPEN ;
2023-04-24 07:46:59 +08:00
// Hack to support legacy UEFIDump mode
if ( argc = = 3 & & ! std : : strcmp ( argv [ 2 ] , " unpack " ) ) {
UEFIDumper uefidumper ;
return ( uefidumper . dump ( buffer , UString ( argv [ 1 ] ) ) ! = U_SUCCESS ) ;
}
// Create model and ffsParser
TreeModel model ;
FfsParser ffsParser ( & model ) ;
// Parse input buffer
result = ffsParser . parse ( buffer ) ;
if ( result )
return result ;
ffsParser . outputInfo ( ) ;
// Create ffsDumper
FfsDumper ffsDumper ( & model ) ;
// Dump only leaf elements, no report or GUID database
if ( argc = = 3 & & ! std : : strcmp ( argv [ 2 ] , " dump " ) ) {
return ( ffsDumper . dump ( model . index ( 0 , 0 ) , path + UString ( " .dump " ) ) ! = U_SUCCESS ) ;
}
// Dump named GUIDs found in the image, no dump or report
else if ( argc = = 3 & & ! std : : strcmp ( argv [ 2 ] , " guids " ) ) {
GuidDatabase db = guidDatabaseFromTreeRecursive ( & model , model . index ( 0 , 0 ) ) ;
if ( ! db . empty ( ) ) {
return guidDatabaseExportToFile ( path + UString ( " .guids.csv " ) , db ) ;
2023-04-24 07:03:35 +08:00
}
2023-04-24 07:46:59 +08:00
}
// Generate report, no dump or GUID database
else if ( argc = = 3 & & ! std : : strcmp ( argv [ 2 ] , " report " ) ) {
FfsReport ffsReport ( & model ) ;
std : : vector < UString > report = ffsReport . generate ( ) ;
if ( report . size ( ) ) {
std : : ofstream file ;
file . open ( ( path + UString ( " .report.txt " ) ) . toLocal8Bit ( ) ) ;
for ( size_t i = 0 ; i < report . size ( ) ; i + + )
file < < report [ i ] . toLocal8Bit ( ) < < ' \n ' ;
return 0 ;
2016-07-15 03:22:51 +08:00
}
2023-04-24 07:46:59 +08:00
return 1 ;
}
// Either default or all mode
else if ( argc = = 2 | | ( argc = = 3 & & ! std : : strcmp ( argv [ 2 ] , " all " ) ) ) {
// Generate report
2016-06-25 18:22:28 +08:00
FfsReport ffsReport ( & model ) ;
2018-07-13 05:17:08 +08:00
std : : vector < UString > report = ffsReport . generate ( ) ;
2016-06-25 18:22:28 +08:00
if ( report . size ( ) ) {
2018-07-13 05:17:08 +08:00
std : : ofstream file ;
2018-08-02 08:41:11 +08:00
file . open ( ( path + UString ( " .report.txt " ) ) . toLocal8Bit ( ) ) ;
2018-07-13 05:17:08 +08:00
for ( size_t i = 0 ; i < report . size ( ) ; i + + )
2018-08-02 08:41:11 +08:00
file < < report [ i ] . toLocal8Bit ( ) < < ' \n ' ;
2016-06-25 18:22:28 +08:00
}
2023-04-24 07:46:59 +08:00
// Create GUID database
GuidDatabase db = guidDatabaseFromTreeRecursive ( & model , model . index ( 0 , 0 ) ) ;
if ( ! db . empty ( ) ) {
guidDatabaseExportToFile ( path + UString ( " .guids.csv " ) , db ) ;
}
// Dump all non-leaf elements, with report and GUID database, default
2018-07-13 05:17:08 +08:00
if ( argc = = 2 ) {
return ( ffsDumper . dump ( model . index ( 0 , 0 ) , path + UString ( " .dump " ) ) ! = U_SUCCESS ) ;
2015-05-17 17:45:32 +08:00
}
2023-04-24 07:46:59 +08:00
else if ( argc = = 3 & & ! std : : strcmp ( argv [ 2 ] , " all " ) ) { // Dump every element with report and GUID database
2018-07-13 05:17:08 +08:00
return ( ffsDumper . dump ( model . index ( 0 , 0 ) , path + UString ( " .dump " ) , FfsDumper : : DUMP_ALL ) ! = U_SUCCESS ) ;
2016-06-21 03:20:47 +08:00
}
2023-04-24 07:46:59 +08:00
}
// Dump specific files, without report or GUID database
else {
std : : vector < UString > inputs , outputs ;
std : : vector < FfsDumper : : DumpMode > modes ;
std : : vector < UINT8 > sectionTypes ;
ReadType readType = READ_INPUT ;
for ( int i = 2 ; i < argc ; i + + ) {
const char * arg = argv [ i ] ;
if ( ! std : : strcmp ( arg , " -i " ) ) {
readType = READ_INPUT ;
continue ;
} else if ( ! std : : strcmp ( arg , " -o " ) ) {
readType = READ_OUTPUT ;
continue ;
} else if ( ! std : : strcmp ( arg , " -m " ) ) {
readType = READ_MODE ;
continue ;
} else if ( ! std : : strcmp ( arg , " -t " ) ) {
readType = READ_SECTION ;
continue ;
}
if ( readType = = READ_INPUT ) {
inputs . push_back ( arg ) ;
} else if ( readType = = READ_OUTPUT ) {
outputs . push_back ( getAbsPath ( arg ) ) ;
} else if ( readType = = READ_MODE ) {
if ( ! std : : strcmp ( arg , " all " ) )
modes . push_back ( FfsDumper : : DUMP_ALL ) ;
else if ( ! std : : strcmp ( arg , " body " ) )
modes . push_back ( FfsDumper : : DUMP_BODY ) ;
else if ( ! std : : strcmp ( arg , " header " ) )
modes . push_back ( FfsDumper : : DUMP_HEADER ) ;
else if ( ! std : : strcmp ( arg , " info " ) )
modes . push_back ( FfsDumper : : DUMP_INFO ) ;
else if ( ! std : : strcmp ( arg , " file " ) )
modes . push_back ( FfsDumper : : DUMP_FILE ) ;
else
return U_INVALID_PARAMETER ;
} else if ( readType = = READ_SECTION ) {
char * converted = const_cast < char * > ( arg ) ;
UINT8 sectionType = ( UINT8 ) std : : strtol ( arg , & converted , 16 ) ;
if ( converted = = arg )
return U_INVALID_PARAMETER ;
sectionTypes . push_back ( sectionType ) ;
}
2016-06-25 18:22:28 +08:00
}
2023-04-24 07:46:59 +08:00
if ( inputs . empty ( ) | | ( ! outputs . empty ( ) & & inputs . size ( ) ! = outputs . size ( ) ) | |
( ! modes . empty ( ) & & inputs . size ( ) ! = modes . size ( ) ) | |
( ! sectionTypes . empty ( ) & & inputs . size ( ) ! = sectionTypes . size ( ) ) )
return U_INVALID_PARAMETER ;
USTATUS lastError = U_SUCCESS ;
for ( size_t i = 0 ; i < inputs . size ( ) ; i + + ) {
UString outPath = outputs . empty ( ) ? path + UString ( " .dump " ) : outputs [ i ] ;
FfsDumper : : DumpMode mode = modes . empty ( ) ? FfsDumper : : DUMP_ALL : modes [ i ] ;
UINT8 type = sectionTypes . empty ( ) ? FfsDumper : : IgnoreSectionType : sectionTypes [ i ] ;
result = ffsDumper . dump ( model . index ( 0 , 0 ) , outPath , mode , type , inputs [ i ] ) ;
if ( result ) {
std : : cout < < " Guid " < < inputs [ i ] . toLocal8Bit ( ) < < " failed with " < < result < < " code! " < < std : : endl ;
lastError = result ;
}
}
return lastError ;
2015-04-02 16:04:37 +08:00
}
2023-04-24 07:46:59 +08:00
2016-07-15 03:22:51 +08:00
// If parameters are different, show version and usage information
2023-02-16 08:54:32 +08:00
print_usage ( ) ;
2016-07-15 03:22:51 +08:00
return 1 ;
2018-05-05 02:52:25 +08:00
}