2019-09-03 11:58:42 +02:00
/*
* refit / scan / common . c
*
* Copyright ( c ) 2006 - 2010 Christoph Pfisterer
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are
* met :
*
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
*
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the
* distribution .
*
* * Neither the name of Christoph Pfisterer nor the names of the
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
* LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2020-04-11 08:21:06 +02:00
# include "../Platform/Platform.h"
2019-09-03 11:58:42 +02:00
# include "entry_scan.h"
2020-02-29 08:30:21 +01:00
# include "../refit/menu.h"
2020-04-16 09:15:26 +02:00
# include "../Platform/guid.h"
# include "../Platform/APFS.h"
# include "../Platform/cpu.h"
2019-09-03 11:58:42 +02:00
# ifndef DEBUG_ALL
# define DEBUG_COMMON_MENU 1
# else
# define DEBUG_COMMON_MENU DEBUG_ALL
# endif
# if DEBUG_COMMON_MENU == 0
# define DBG(...)
# else
# define DBG(...) DebugLog(DEBUG_COMMON_MENU, __VA_ARGS__)
# endif
2020-04-10 16:35:24 +02:00
extern CONST CHAR8 * IconsNames [ ] ;
#if 0
2020-02-17 21:41:09 +01:00
static CONST CHAR16 * BuiltinIconNames [ ] = {
2019-09-03 11:58:42 +02:00
/*
L " About " ,
L " Options " ,
L " Clover " ,
L " Reset " ,
L " Shutdown " ,
L " Help " ,
L " Shell " ,
L " Part " ,
L " Rescue " ,
L " Pointer " ,
*/
L " Internal " ,
L " External " ,
L " Optical " ,
L " FireWire " ,
L " Boot " ,
L " HFS " ,
L " APFS " ,
L " NTFS " ,
L " EXT " ,
L " Recovery " ,
} ;
static const UINTN BuiltinIconNamesCount = ( sizeof ( BuiltinIconNames ) / sizeof ( CHAR16 * ) ) ;
2020-02-17 21:41:09 +01:00
EG_IMAGE * LoadBuiltinIcon ( IN CONST CHAR16 * IconName )
2019-09-03 11:58:42 +02:00
{
UINTN Index = 0 ;
if ( IconName = = NULL ) {
return NULL ;
}
while ( Index < BuiltinIconNamesCount ) {
if ( StriCmp ( IconName , BuiltinIconNames [ Index ] ) = = 0 ) {
2020-03-30 10:34:16 +02:00
XImage IconX = ThemeX . GetIcon ( BUILTIN_ICON_VOL_INTERNAL + Index ) ;
return IconX . ToEGImage ( ) ;
2019-09-03 11:58:42 +02:00
}
+ + Index ;
}
return NULL ;
}
2020-04-10 16:35:24 +02:00
# endif
2019-09-03 11:58:42 +02:00
2020-04-05 20:56:36 +02:00
const XImage & ScanVolumeDefaultIcon ( REFIT_VOLUME * Volume , IN UINT8 OSType , IN EFI_DEVICE_PATH_PROTOCOL * DevicePath )
2020-04-10 12:04:21 +02:00
2019-09-03 11:58:42 +02:00
{
UINTN IconNum = 0 ;
2020-04-05 20:56:36 +02:00
const XImage * IconX ;
2019-09-03 11:58:42 +02:00
// default volume icon based on disk kind
switch ( Volume - > DiskKind ) {
case DISK_KIND_INTERNAL :
switch ( OSType ) {
case OSTYPE_OSX :
case OSTYPE_OSX_INSTALLER :
while ( ! IsDevicePathEndType ( DevicePath ) & &
! ( DevicePathType ( DevicePath ) = = MEDIA_DEVICE_PATH & & DevicePathSubType ( DevicePath ) = = MEDIA_VENDOR_DP ) ) {
DevicePath = NextDevicePathNode ( DevicePath ) ;
}
if ( DevicePathType ( DevicePath ) = = MEDIA_DEVICE_PATH & & DevicePathSubType ( DevicePath ) = = MEDIA_VENDOR_DP ) {
if ( StriCmp ( GuidLEToStr ( ( EFI_GUID * ) ( ( UINT8 * ) DevicePath + 0x04 ) ) , GuidLEToStr ( & APFSSignature ) ) = = 0 ) {
IconNum = BUILTIN_ICON_VOL_INTERNAL_APFS ;
}
} else {
IconNum = BUILTIN_ICON_VOL_INTERNAL_HFS ;
}
break ;
case OSTYPE_RECOVERY :
IconNum = BUILTIN_ICON_VOL_INTERNAL_REC ;
break ;
case OSTYPE_LIN :
case OSTYPE_LINEFI :
IconNum = BUILTIN_ICON_VOL_INTERNAL_EXT3 ;
break ;
case OSTYPE_WIN :
case OSTYPE_WINEFI :
IconNum = BUILTIN_ICON_VOL_INTERNAL_NTFS ;
break ;
default :
IconNum = BUILTIN_ICON_VOL_INTERNAL ;
break ;
}
2020-03-30 10:34:16 +02:00
break ;
case DISK_KIND_EXTERNAL :
2020-04-06 17:40:45 +02:00
IconNum = BUILTIN_ICON_VOL_EXTERNAL ;
2020-03-30 10:34:16 +02:00
break ;
case DISK_KIND_OPTICAL :
2020-04-06 17:40:45 +02:00
IconNum = BUILTIN_ICON_VOL_OPTICAL ;
2020-03-30 10:34:16 +02:00
break ;
case DISK_KIND_FIREWIRE :
2020-04-06 17:40:45 +02:00
IconNum = BUILTIN_ICON_VOL_FIREWIRE ;
2020-03-30 10:34:16 +02:00
break ;
case DISK_KIND_BOOTER :
2020-04-06 17:40:45 +02:00
IconNum = BUILTIN_ICON_VOL_BOOTER ;
2020-03-30 10:34:16 +02:00
break ;
default :
2020-04-06 17:40:45 +02:00
IconNum = BUILTIN_ICON_VOL_INTERNAL ;
2020-04-05 20:56:36 +02:00
break ;
2020-03-30 10:34:16 +02:00
}
2020-04-10 16:35:24 +02:00
// DBG("asked IconNum = %llu Volume->DiskKind=%d OSType=%d\n", IconNum, Volume->DiskKind, OSType);
IconX = & ThemeX . GetIcon ( IconNum ) ; //asked IconNum = BUILTIN_ICON_VOL_INTERNAL_HFS, got day icon
2020-04-06 17:40:45 +02:00
if ( IconX - > isEmpty ( ) ) {
2020-04-10 16:35:24 +02:00
DBG ( " asked Icon %s not found, took internal \n " , IconsNames [ IconNum ] ) ;
2020-04-06 17:40:45 +02:00
IconX = & ThemeX . GetIcon ( BUILTIN_ICON_VOL_INTERNAL ) ; //including embedded which is really present
}
2020-04-05 20:56:36 +02:00
return * IconX ;
2019-09-03 11:58:42 +02:00
}
2020-04-05 14:25:39 +02:00
XString AddLoadOption ( IN CONST XString & LoadOptions , IN CONST XString & LoadOption )
2019-09-03 11:58:42 +02:00
{
2020-04-11 19:55:47 +02:00
// LoadOptions assumed out
2019-09-03 11:58:42 +02:00
// If either option strings are null nothing to do
2020-04-11 20:16:05 +02:00
if ( LoadOptions . isEmpty ( ) ) //initially empty so return new option even if empty
2019-09-03 11:58:42 +02:00
{
2020-04-11 20:16:05 +02:00
// return LoadOption
return LoadOption ;
2019-09-03 11:58:42 +02:00
}
// If there is no option or it is already present duplicate original
2020-04-05 14:25:39 +02:00
else {
2020-04-11 19:55:47 +02:00
if ( LoadOptions . ExistIn ( LoadOption ) ) return LoadOptions ; //good
2020-04-05 14:25:39 +02:00
// Otherwise add option
2020-04-11 19:55:47 +02:00
// return SPrintf("%s %s", LoadOptions.c_str(), LoadOption.c_str()); //LoadOptions + LoadOption
2020-04-11 22:39:51 +02:00
return LoadOptions + " " _XS + LoadOption ; //why not?
2020-04-05 14:25:39 +02:00
}
2019-09-03 11:58:42 +02:00
}
2020-04-05 14:25:39 +02:00
XString RemoveLoadOption ( IN const XString & LoadOptions , IN const XString & LoadOption )
2019-09-03 11:58:42 +02:00
{
2020-04-05 14:25:39 +02:00
// CONST CHAR16 *Placement;
// CHAR16 *NewLoadOptions;
// UINTN Length, Offset, OptionLength;
2019-09-03 11:58:42 +02:00
2020-03-25 19:32:44 +01:00
//DBG("LoadOptions: '%ls', remove LoadOption: '%ls'\n", LoadOptions, LoadOption);
2019-09-03 11:58:42 +02:00
// If there are no options then nothing to do
2020-04-05 14:25:39 +02:00
if ( LoadOptions . isEmpty ( ) ) return " " _XS ;
2019-09-03 11:58:42 +02:00
// If there is no option to remove then duplicate original
2020-04-05 14:25:39 +02:00
if ( LoadOption . isEmpty ( ) ) return LoadOptions ;
2019-09-03 11:58:42 +02:00
// If not present duplicate original
2020-04-05 14:25:39 +02:00
xsize Offset = LoadOptions . IdxOf ( LoadOption ) ;
if ( Offset = = MAX_XSIZE ) return LoadOptions ;
2019-09-03 11:58:42 +02:00
// Get placement of option in original options
2020-04-05 14:25:39 +02:00
// Offset = (Placement - LoadOptions);
xsize Length = LoadOptions . length ( ) ;
xsize OptionLength = LoadOption . length ( ) ;
2019-09-03 11:58:42 +02:00
// If this is just part of some larger option (contains non-space at the beginning or end)
2020-04-05 14:25:39 +02:00
if ( ( Offset > 0 & & LoadOptions [ Offset - 1 ] ! = ' ' ) | |
( ( Offset + OptionLength ) < Length & & LoadOptions [ Offset + OptionLength ] ! = ' ' ) ) {
return LoadOptions ;
2019-09-03 11:58:42 +02:00
}
// Consume preceeding spaces
2020-04-05 14:25:39 +02:00
while ( Offset > 0 & & LoadOptions [ Offset - 1 ] = = ' ' ) {
2019-09-03 11:58:42 +02:00
OptionLength + + ;
Offset - - ;
}
// Consume following spaces
2020-04-05 14:25:39 +02:00
while ( LoadOptions [ Offset + OptionLength ] = = ' ' ) {
2019-09-03 11:58:42 +02:00
OptionLength + + ;
}
// If it's the whole string return NULL
2020-04-05 14:25:39 +02:00
if ( OptionLength = = Length ) return " " _XS ;
2019-09-03 11:58:42 +02:00
2020-04-05 14:25:39 +02:00
XString NewLoadOptions ;
2019-09-03 11:58:42 +02:00
if ( Offset = = 0 ) {
// Simple case - we just need substring after OptionLength position
2020-04-05 14:25:39 +02:00
NewLoadOptions = LoadOptions . SubString ( OptionLength , MAX_XSIZE ) ;
2019-09-03 11:58:42 +02:00
} else {
// Copy preceeding substring
2020-04-05 14:25:39 +02:00
NewLoadOptions = LoadOptions . SubString ( 0 , Offset ) ;
// CopyMem(NewLoadOptions, LoadOptions, Offset * sizeof(CHAR16));
2019-09-03 11:58:42 +02:00
if ( ( Offset + OptionLength ) < Length ) {
// Copy following substring, but include one space also
OptionLength - - ;
2020-04-05 14:25:39 +02:00
NewLoadOptions + = LoadOptions . SubString ( Offset + OptionLength , MAX_XSIZE ) ;
// CopyMem(NewLoadOptions + Offset, LoadOptions + Offset + OptionLength, (Length - OptionLength - Offset) * sizeof(CHAR16));
2019-09-03 11:58:42 +02:00
}
}
return NewLoadOptions ;
}
# define TO_LOWER(ch) (((ch >= L'A') && (ch <= L'Z')) ? ((ch - L'A') + L'a') : ch)
2020-02-17 21:41:09 +01:00
INTN StrniCmp ( IN CONST CHAR16 * Str1 ,
IN CONST CHAR16 * Str2 ,
2019-09-03 11:58:42 +02:00
IN UINTN Count )
{
CHAR16 Ch1 , Ch2 ;
if ( Count = = 0 ) {
return 0 ;
}
if ( Str1 = = NULL ) {
if ( Str2 = = NULL ) {
return 0 ;
} else {
return - 1 ;
}
} else if ( Str2 = = NULL ) {
return 1 ;
}
do {
Ch1 = TO_LOWER ( * Str1 ) ;
Ch2 = TO_LOWER ( * Str2 ) ;
Str1 + + ;
Str2 + + ;
if ( Ch1 ! = Ch2 ) {
return ( Ch1 - Ch2 ) ;
}
if ( Ch1 = = 0 ) {
return 0 ;
}
} while ( - - Count > 0 ) ;
return 0 ;
}
2020-02-17 21:41:09 +01:00
CONST CHAR16 * StriStr ( IN CONST CHAR16 * Str ,
IN CONST CHAR16 * SearchFor )
2019-09-03 11:58:42 +02:00
{
2020-02-17 21:41:09 +01:00
CONST CHAR16 * End ;
2019-09-03 11:58:42 +02:00
UINTN Length ;
UINTN SearchLength ;
if ( ( Str = = NULL ) | | ( SearchFor = = NULL ) ) {
return NULL ;
}
Length = StrLen ( Str ) ;
if ( Length = = 0 ) {
return NULL ;
}
SearchLength = StrLen ( SearchFor ) ;
if ( SearchLength > Length ) {
return NULL ;
}
End = Str + ( Length - SearchLength ) + 1 ;
while ( Str < End ) {
if ( StrniCmp ( Str , SearchFor , SearchLength ) = = 0 ) {
return Str ;
}
+ + Str ;
}
return NULL ;
}
VOID StrToLower ( IN CHAR16 * Str )
{
while ( * Str ) {
* Str = TO_LOWER ( * Str ) ;
+ + Str ;
}
}
2020-02-28 21:28:33 +01:00
// TODO remove that and AlertMessage with a printf-like format
2020-04-10 12:04:21 +02:00
2020-03-21 20:52:28 +01:00
STATIC void CreateInfoLines ( IN CONST XStringW & Message , OUT XStringWArray * Information )
{
if ( Message . isEmpty ( ) ) {
return ;
}
Information - > Empty ( ) ;
//TODO will fill later
}
2020-04-10 12:04:21 +02:00
#if 0 //not needed?
2020-02-28 21:28:33 +01:00
STATIC void CreateInfoLines ( IN CONST CHAR16 * Message , OUT XStringWArray * Information )
2019-09-03 11:58:42 +02:00
{
2020-02-17 21:41:09 +01:00
CONST CHAR16 * Ptr ;
2020-02-28 21:28:33 +01:00
// CHAR16 **Information;
2019-09-03 11:58:42 +02:00
UINTN Index = 0 , Total = 0 ;
UINTN Length = ( ( Message = = NULL ) ? 0 : StrLen ( Message ) ) ;
// Check parameters
if ( Length = = 0 ) {
2020-02-28 21:28:33 +01:00
return ;
2019-09-03 11:58:42 +02:00
}
// Count how many new lines
Ptr = Message - 1 ;
while ( Ptr ! = NULL ) {
+ + Total ;
Ptr = StrStr ( + + Ptr , L " \n " ) ;
}
2020-02-28 21:28:33 +01:00
// // Create information
// Information = (CHAR16 **)AllocatePool((Total * sizeof(CHAR16 *)) + ((Length + 1) * sizeof(CHAR16)));
// if (Information == NULL) {
// return NULL;
// }
Information - > Empty ( ) ;
2019-09-03 11:58:42 +02:00
// Copy strings
2020-03-04 17:33:30 +01:00
CHAR16 * Ptr2 = NULL ; // VS2017 complains about uninitialized var.
2020-02-28 21:28:33 +01:00
// CHAR16* Ptr2 = Information[Index++] = (CHAR16 *)(Information + Total);
// StrCpyS(Ptr2, Length + 1, Message);
2019-09-03 11:58:42 +02:00
while ( ( Index < Total ) & &
2020-02-17 21:41:09 +01:00
( ( Ptr2 = ( CHAR16 * ) StrStr ( Ptr2 , L " \n " ) ) ! = NULL ) ) { // cast is ok because FilePath is not const, and we know that StrStr returns a pointer in FilePath. Will disappear when using a string object instead of CHAR16*
* Ptr2 + + = 0 ;
2020-03-10 17:50:55 +01:00
XStringW * s = new XStringW ;
s - > takeValueFrom ( Ptr2 ) ;
Information - > AddReference ( s , true ) ;
2020-02-28 21:28:33 +01:00
// Information[Index++] = Ptr2;
2019-09-03 11:58:42 +02:00
}
2020-02-28 21:28:33 +01:00
// // Return the info lines
// if (Count != NULL) {
// *Count = Total;
// }
// return Information;
2019-09-03 11:58:42 +02:00
}
2020-03-21 20:52:28 +01:00
# endif
2020-02-28 21:28:33 +01:00
extern REFIT_MENU_ITEM_RETURN MenuEntryReturn ;
2019-09-03 11:58:42 +02:00
2020-03-21 08:34:28 +01:00
// it is not good to use Options menu style for messages and one line dialogs
// it can be a semitransparent rectangular at the screen centre as it was in Clover v1.0
STATIC REFIT_MENU_SCREEN AlertMessageMenu ( 0 , XStringW ( ) , XStringW ( ) , & MenuEntryReturn , NULL ) ;
2020-03-21 20:52:28 +01:00
VOID AlertMessage ( IN XStringW & Title , IN CONST XStringW & Message )
2020-03-21 08:34:28 +01:00
{
2020-03-21 20:52:28 +01:00
CreateInfoLines ( Message , & AlertMessageMenu . InfoLines ) ;
2020-03-21 08:34:28 +01:00
AlertMessageMenu . Title = Title ;
AlertMessageMenu . RunMenu ( NULL ) ;
AlertMessageMenu . InfoLines . Empty ( ) ;
}
2019-09-03 11:58:42 +02:00
# define TAG_YES 1
# define TAG_NO 2
2020-03-10 10:45:17 +01:00
//REFIT_SIMPLE_MENU_ENTRY_TAG(CONST CHAR16 *Title_, UINTN Tag_, ACTION AtClick_)
2020-03-21 20:52:28 +01:00
STATIC REFIT_SIMPLE_MENU_ENTRY_TAG YesMessageEntry ( XStringW ( ) . takeValueFrom ( L " Yes " ) , TAG_YES , ActionEnter ) ;
STATIC REFIT_SIMPLE_MENU_ENTRY_TAG NoMessageEntry ( XStringW ( ) . takeValueFrom ( L " No " ) , TAG_NO , ActionEnter ) ;
2020-03-10 10:45:17 +01:00
//REFIT_MENU_SCREEN(UINTN ID, CONST CHAR16* Title, CONST CHAR16* TimeoutText, REFIT_ABSTRACT_MENU_ENTRY* entry1, REFIT_ABSTRACT_MENU_ENTRY* entry2)
2020-03-21 08:34:28 +01:00
STATIC REFIT_MENU_SCREEN YesNoMessageMenu ( 0 , XStringW ( ) , XStringW ( ) , & YesMessageEntry , & NoMessageEntry ) ;
2019-09-03 11:58:42 +02:00
// Display a yes/no prompt
2020-03-21 20:52:28 +01:00
BOOLEAN YesNoMessage ( IN XStringW & Title , IN CONST XStringW & Message )
{
BOOLEAN Result = FALSE ;
UINTN MenuExit ;
CreateInfoLines ( Message , & YesNoMessageMenu . InfoLines ) ;
YesNoMessageMenu . Title = Title ;
do
{
REFIT_ABSTRACT_MENU_ENTRY * ChosenEntry = NULL ;
MenuExit = YesNoMessageMenu . RunMenu ( & ChosenEntry ) ;
if ( ChosenEntry ! = NULL & & ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) & & ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) - > Tag = = TAG_YES & &
( ( MenuExit = = MENU_EXIT_ENTER ) | | ( MenuExit = = MENU_EXIT_DETAILS ) ) ) {
Result = TRUE ;
MenuExit = MENU_EXIT_ENTER ;
}
} while ( MenuExit ! = MENU_EXIT_ENTER ) ;
YesNoMessageMenu . InfoLines . Empty ( ) ;
return Result ;
}
2019-09-03 11:58:42 +02:00
// Ask user for file path from directory menu
BOOLEAN AskUserForFilePathFromDir ( IN CHAR16 * Title OPTIONAL , IN REFIT_VOLUME * Volume ,
IN CHAR16 * ParentPath OPTIONAL , IN EFI_FILE * Dir ,
OUT EFI_DEVICE_PATH_PROTOCOL * * Result )
{
//REFIT_MENU_SCREEN Menu = { 0, L"Please Select File...", NULL, 0, NULL, 0, NULL,
// 0, NULL, FALSE, FALSE, 0, 0, 0, 0, { 0, 0, 0, 0 }, NULL};
// Check parameters
if ( ( Volume = = NULL ) | | ( Dir = = NULL ) | | ( Result = = NULL ) ) {
return FALSE ;
}
// TODO: Generate directory menu
return FALSE ;
}
# define TAG_OFFSET 1000
2020-03-04 16:27:41 +01:00
//STATIC REFIT_MENU_SCREEN InitialMenu = {0, L"Please Select File...", NULL, 0, NULL,
// 0, NULL, NULL, FALSE, FALSE, 0, 0, 0, 0,
// { 0, 0, 0, 0 }, NULL};
2020-03-31 17:59:35 +02:00
STATIC REFIT_MENU_SCREEN InitialMenu ( 0 , L " Please Select File... " _XSW , XStringW ( ) ) ;
2019-09-03 11:58:42 +02:00
// Ask user for file path from volumes menu
BOOLEAN AskUserForFilePathFromVolumes ( IN CHAR16 * Title OPTIONAL , OUT EFI_DEVICE_PATH_PROTOCOL * * Result )
{
2020-02-28 21:28:33 +01:00
REFIT_MENU_SCREEN Menu = InitialMenu ;
UINTN Index = 0 , /*Count = 0,*/ MenuExit ;
2019-09-03 11:58:42 +02:00
BOOLEAN Responded = FALSE ;
if ( Result = = NULL ) {
return FALSE ;
}
// Create volume entries
2020-02-27 15:34:29 +01:00
for ( Index = 0 ; Index < Volumes . size ( ) ; + + Index ) {
REFIT_VOLUME * Volume = & Volumes [ Index ] ;
2019-09-03 11:58:42 +02:00
if ( ( Volume = = NULL ) | | ( Volume - > RootDir = = NULL ) | |
( ( Volume - > DevicePathString = = NULL ) & & ( Volume - > VolName = = NULL ) ) ) {
continue ;
}
2020-03-31 17:59:35 +02:00
REFIT_SIMPLE_MENU_ENTRY_TAG * Entry = new REFIT_SIMPLE_MENU_ENTRY_TAG ( SWPrintf ( " %ls " , ( Volume - > VolName = = NULL ) ? Volume - > DevicePathString : Volume - > VolName ) , TAG_OFFSET + Index , MENU_EXIT_ENTER ) ;
2020-02-28 21:28:33 +01:00
Menu . Entries . AddReference ( Entry , true ) ;
2019-09-03 11:58:42 +02:00
}
// Setup menu
2020-02-28 21:28:33 +01:00
Menu . Entries . AddReference ( & MenuEntryReturn , false ) ;
2020-03-21 20:52:28 +01:00
Menu . Title . takeValueFrom ( Title ) ;
2020-04-10 12:04:21 +02:00
2019-09-03 11:58:42 +02:00
do
{
2020-02-28 21:28:33 +01:00
REFIT_ABSTRACT_MENU_ENTRY * ChosenEntry = NULL ;
2019-09-03 11:58:42 +02:00
// Run the volume chooser menu
2020-03-03 21:44:07 +01:00
MenuExit = Menu . RunMenu ( & ChosenEntry ) ;
2020-02-28 21:28:33 +01:00
if ( ( ChosenEntry ! = NULL ) & & ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) & &
2019-09-03 11:58:42 +02:00
( ( MenuExit = = MENU_EXIT_ENTER ) | | ( MenuExit = = MENU_EXIT_DETAILS ) ) ) {
2020-02-28 21:28:33 +01:00
if ( ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) - > Tag > = TAG_OFFSET ) {
Index = ( ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) - > Tag - TAG_OFFSET ) ;
2020-02-27 15:34:29 +01:00
if ( Index < Volumes . size ( ) ) {
2019-09-03 11:58:42 +02:00
// Run directory chooser menu
2020-02-27 15:34:29 +01:00
if ( ! AskUserForFilePathFromDir ( Title , & Volumes [ Index ] , NULL , Volumes [ Index ] . RootDir , Result ) ) {
2019-09-03 11:58:42 +02:00
continue ;
}
Responded = TRUE ;
}
}
break ;
}
} while ( MenuExit ! = MENU_EXIT_ESCAPE ) ;
2020-02-28 21:28:33 +01:00
// FreePool(Entries);
2019-09-03 11:58:42 +02:00
return Responded ;
}
// Ask user for file path
BOOLEAN AskUserForFilePath ( IN CHAR16 * Title OPTIONAL , IN EFI_DEVICE_PATH_PROTOCOL * Root OPTIONAL , OUT EFI_DEVICE_PATH_PROTOCOL * * Result )
{
EFI_FILE * Dir = NULL ;
if ( Result = = NULL ) {
return FALSE ;
}
if ( Root ! = NULL ) {
// Get the file path
CHAR16 * DevicePathStr = FileDevicePathToStr ( Root ) ;
if ( DevicePathStr ! = NULL ) {
UINTN Index = 0 ;
// Check the volumes for a match
2020-02-27 15:34:29 +01:00
for ( Index = 0 ; Index < Volumes . size ( ) ; + + Index ) {
REFIT_VOLUME * Volume = & Volumes [ Index ] ;
2019-09-03 11:58:42 +02:00
UINTN Length ;
if ( ( Volume = = NULL ) | | ( Volume - > RootDir = = NULL ) | |
( Volume - > DevicePathString = = NULL ) ) {
continue ;
}
Length = StrLen ( Volume - > DevicePathString ) ;
if ( Length = = 0 ) {
continue ;
}
// If the path begins with this volumes path it matches
if ( StrniCmp ( DevicePathStr , Volume - > DevicePathString , Length ) ) {
// Need to
CHAR16 * FilePath = DevicePathStr + Length ;
UINTN FileLength = StrLen ( FilePath ) ;
if ( FileLength = = 0 ) {
// If there is no path left then open the root
return AskUserForFilePathFromDir ( Title , Volume , NULL , Volume - > RootDir , Result ) ;
} else {
// Check to make sure this is directory
if ( ! EFI_ERROR ( Volume - > RootDir - > Open ( Volume - > RootDir , & Dir , FilePath , EFI_FILE_MODE_READ , 0 ) ) & &
( Dir ! = NULL ) ) {
// Get file information
EFI_FILE_INFO * Info = EfiLibFileInfo ( Dir ) ;
if ( Info ! = NULL ) {
// Check if the file is a directory
if ( ( Info - > Attribute & EFI_FILE_DIRECTORY ) = = 0 ) {
// Return the passed device path if it is a file
FreePool ( Info ) ;
Dir - > Close ( Dir ) ;
* Result = Root ;
return TRUE ;
} else {
// Ask user other wise
BOOLEAN Success = AskUserForFilePathFromDir ( Title , Volume , FilePath , Dir , Result ) ;
FreePool ( Info ) ;
Dir - > Close ( Dir ) ;
return Success ;
}
//FreePool(Info);
}
Dir - > Close ( Dir ) ;
}
}
}
}
FreePool ( DevicePathStr ) ;
}
}
return AskUserForFilePathFromVolumes ( Title , Result ) ;
}
2020-04-16 09:15:26 +02:00
// input - tsc
// output - milliseconds
// the caller is responsible for t1 > t0
UINT64 TimeDiff ( UINT64 t0 , UINT64 t1 )
{
return DivU64x64Remainder ( ( t1 - t0 ) , DivU64x32 ( gCPUStructure . TSCFrequency , 1000 ) , 0 ) ;
}