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 .
*/
# include "entry_scan.h"
2020-02-29 08:30:21 +01:00
# include "../refit/menu.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-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 ) {
return BuiltinIcon ( BUILTIN_ICON_VOL_INTERNAL + Index ) ;
}
+ + Index ;
}
return NULL ;
}
EG_IMAGE * ScanVolumeDefaultIcon ( REFIT_VOLUME * Volume , IN UINT8 OSType , IN EFI_DEVICE_PATH_PROTOCOL * DevicePath ) //IN UINT8 DiskKind)
{
UINTN IconNum = 0 ;
// 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 ;
}
return BuiltinIcon ( IconNum ) ;
case DISK_KIND_EXTERNAL :
return BuiltinIcon ( BUILTIN_ICON_VOL_EXTERNAL ) ;
case DISK_KIND_OPTICAL :
return BuiltinIcon ( BUILTIN_ICON_VOL_OPTICAL ) ;
case DISK_KIND_FIREWIRE :
return BuiltinIcon ( BUILTIN_ICON_VOL_FIREWIRE ) ;
case DISK_KIND_BOOTER :
return BuiltinIcon ( BUILTIN_ICON_VOL_BOOTER ) ;
default :
break ;
}
return NULL ;
}
2020-02-17 21:41:09 +01:00
CHAR16 * AddLoadOption ( IN CONST CHAR16 * LoadOptions , IN CONST CHAR16 * LoadOption )
2019-09-03 11:58:42 +02:00
{
// If either option strings are null nothing to do
if ( LoadOptions = = NULL )
{
if ( LoadOption = = NULL ) return NULL ;
// Duplicate original options as nothing to add
return EfiStrDuplicate ( LoadOption ) ;
}
// If there is no option or it is already present duplicate original
2020-03-03 10:45:07 +01:00
else if ( ( LoadOption = = NULL ) | | StrStr ( LoadOptions , LoadOption ) )
return EfiStrDuplicate ( LoadOptions ) ;
2019-09-03 11:58:42 +02:00
// Otherwise add option
return PoolPrint ( L " %s %s " , LoadOptions , LoadOption ) ;
}
2020-02-17 21:41:09 +01:00
CHAR16 * RemoveLoadOption ( IN CONST CHAR16 * LoadOptions , IN CONST CHAR16 * LoadOption )
2019-09-03 11:58:42 +02:00
{
2020-02-17 21:41:09 +01:00
CONST CHAR16 * Placement ;
2019-09-03 11:58:42 +02:00
CHAR16 * NewLoadOptions ;
UINTN Length , Offset , OptionLength ;
//DBG("LoadOptions: '%s', remove LoadOption: '%s'\n", LoadOptions, LoadOption);
// If there are no options then nothing to do
if ( LoadOptions = = NULL ) return NULL ;
// If there is no option to remove then duplicate original
if ( LoadOption = = NULL ) return EfiStrDuplicate ( LoadOptions ) ;
// If not present duplicate original
Placement = StrStr ( LoadOptions , LoadOption ) ;
if ( Placement = = NULL ) return EfiStrDuplicate ( LoadOptions ) ;
// Get placement of option in original options
Offset = ( Placement - LoadOptions ) ;
Length = StrLen ( LoadOptions ) ;
OptionLength = StrLen ( LoadOption ) ;
// If this is just part of some larger option (contains non-space at the beginning or end)
if ( ( Offset > 0 & & LoadOptions [ Offset - 1 ] ! = L ' ' ) | |
( ( Offset + OptionLength ) < Length & & LoadOptions [ Offset + OptionLength ] ! = L ' ' ) ) {
return EfiStrDuplicate ( LoadOptions ) ;
}
// Consume preceeding spaces
while ( Offset > 0 & & LoadOptions [ Offset - 1 ] = = L ' ' ) {
OptionLength + + ;
Offset - - ;
}
// Consume following spaces
while ( LoadOptions [ Offset + OptionLength ] = = L ' ' ) {
OptionLength + + ;
}
// If it's the whole string return NULL
if ( OptionLength = = Length ) return NULL ;
if ( Offset = = 0 ) {
// Simple case - we just need substring after OptionLength position
NewLoadOptions = EfiStrDuplicate ( LoadOptions + OptionLength ) ;
} else {
// The rest of LoadOptions is Length - OptionLength, but we may need additional space and ending 0
2019-12-21 01:31:49 +01:00
NewLoadOptions = ( __typeof__ ( NewLoadOptions ) ) AllocateZeroPool ( ( Length - OptionLength + 2 ) * sizeof ( CHAR16 ) ) ;
2019-09-03 11:58:42 +02:00
// Copy preceeding substring
CopyMem ( NewLoadOptions , LoadOptions , Offset * sizeof ( CHAR16 ) ) ;
if ( ( Offset + OptionLength ) < Length ) {
// Copy following substring, but include one space also
OptionLength - - ;
CopyMem ( NewLoadOptions + Offset , LoadOptions + Offset + OptionLength , ( Length - OptionLength - Offset ) * sizeof ( CHAR16 ) ) ;
}
}
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
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-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
# if USE_XTHEME
STATIC REFIT_MENU_SCREEN AlertMessageMenu ( 0 , XStringW ( ) , XStringW ( ) , & MenuEntryReturn , NULL ) ;
VOID AlertMessage ( IN XStringW & Title , IN XStringW & Message )
{
CreateInfoLines ( Message . data ( ) , & AlertMessageMenu . InfoLines ) ;
AlertMessageMenu . Title = Title ;
AlertMessageMenu . RunMenu ( NULL ) ;
AlertMessageMenu . InfoLines . Empty ( ) ;
}
# else
2020-03-04 16:27:41 +01:00
STATIC REFIT_MENU_SCREEN AlertMessageMenu ( 0 , NULL , NULL , & MenuEntryReturn , NULL ) ;
2019-09-03 11:58:42 +02:00
// Display an alert message
2020-02-17 21:41:09 +01:00
VOID AlertMessage ( IN CONST CHAR16 * Title , IN CONST CHAR16 * Message )
2019-09-03 11:58:42 +02:00
{
2020-02-28 21:28:33 +01:00
// UINTN Count = 0;
2019-09-03 11:58:42 +02:00
// Break message into info lines
2020-02-28 21:28:33 +01:00
// CHAR16 **Information = CreateInfoLines(Message, &Count);
CreateInfoLines ( Message , & AlertMessageMenu . InfoLines ) ;
2020-03-03 21:44:07 +01:00
AlertMessageMenu . Title = EfiStrDuplicate ( Title ) ;
AlertMessageMenu . RunMenu ( NULL ) ;
2020-02-28 21:28:33 +01:00
// // Check parameters
// if (Information != NULL) {
// if (Count > 0) {
// // Display the alert message
// AlertMessageMenu.InfoLineCount = Count;
// AlertMessageMenu.InfoLines = (CONST CHAR16**)Information;
// AlertMessageMenu.Title = Title;
// RunMenu(&AlertMessageMenu, NULL);
// }
// FreePool(Information);
// }
AlertMessageMenu . InfoLines . Empty ( ) ;
2019-09-03 11:58:42 +02:00
}
2020-03-21 08:34:28 +01:00
# endif
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-10 17:50:55 +01:00
STATIC REFIT_SIMPLE_MENU_ENTRY_TAG YesMessageEntry = { XStringWP ( L " Yes " ) , TAG_YES , ActionEnter } ;
STATIC REFIT_SIMPLE_MENU_ENTRY_TAG NoMessageEntry = { XStringWP ( 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
# if USE_XTHEME
STATIC REFIT_MENU_SCREEN YesNoMessageMenu ( 0 , XStringW ( ) , XStringW ( ) , & YesMessageEntry , & NoMessageEntry ) ;
# else
2020-03-04 16:27:41 +01:00
STATIC REFIT_MENU_SCREEN YesNoMessageMenu ( 0 , NULL , NULL , & YesMessageEntry , & NoMessageEntry ) ;
2020-03-21 08:34:28 +01:00
# endif
2019-09-03 11:58:42 +02:00
// Display a yes/no prompt
2020-02-17 21:41:09 +01:00
BOOLEAN YesNoMessage ( IN CHAR16 * Title , IN CONST CHAR16 * Message )
2019-09-03 11:58:42 +02:00
{
BOOLEAN Result = FALSE ;
2020-02-28 21:28:33 +01:00
UINTN /*Count = 0,*/ MenuExit ;
2019-09-03 11:58:42 +02:00
// Break message into info lines
2020-02-28 21:28:33 +01:00
// CHAR16 **Information = CreateInfoLines(Message, &Count);
CreateInfoLines ( Message , & YesNoMessageMenu . InfoLines ) ;
2019-09-03 11:58:42 +02:00
// Display the yes/no message
2020-02-28 21:28:33 +01:00
// YesNoMessageMenu.InfoLineCount = Count;
// YesNoMessageMenu.InfoLines = (CONST CHAR16**)Information;
2019-09-03 11:58:42 +02:00
YesNoMessageMenu . Title = Title ;
do
{
2020-02-28 21:28:33 +01:00
REFIT_ABSTRACT_MENU_ENTRY * ChosenEntry = NULL ;
2020-03-03 21:44:07 +01:00
MenuExit = YesNoMessageMenu . RunMenu ( & ChosenEntry ) ;
2020-02-28 21:28:33 +01:00
if ( ChosenEntry ! = NULL & & ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) & & ChosenEntry - > getREFIT_SIMPLE_MENU_ENTRY_TAG ( ) - > Tag = = TAG_YES & &
2019-09-03 11:58:42 +02:00
( ( MenuExit = = MENU_EXIT_ENTER ) | | ( MenuExit = = MENU_EXIT_DETAILS ) ) ) {
Result = TRUE ;
MenuExit = MENU_EXIT_ENTER ;
}
} while ( MenuExit ! = MENU_EXIT_ENTER ) ;
2020-02-28 21:28:33 +01:00
YesNoMessageMenu . InfoLines . Empty ( ) ;
// if (Information != NULL) {
// FreePool(Information);
// }
2019-09-03 11:58:42 +02:00
return Result ;
}
// 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-21 08:34:28 +01:00
# if USE_XTHEME
STATIC REFIT_MENU_SCREEN InitialMenu ( 0 , XStringWP ( L " Please Select File... " ) , XStringW ( ) ) ;
# else
2020-03-04 16:27:41 +01:00
STATIC REFIT_MENU_SCREEN InitialMenu ( 0 , L " Please Select File... " , NULL ) ;
2020-03-21 08:34:28 +01:00
# endif
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 ;
// REFIT_MENU_ENTRY **Entries;
// REFIT_MENU_ENTRY *EntryPtr;
UINTN Index = 0 , /*Count = 0,*/ MenuExit ;
2019-09-03 11:58:42 +02:00
BOOLEAN Responded = FALSE ;
if ( Result = = NULL ) {
return FALSE ;
}
// Allocate entries
2020-02-28 21:28:33 +01:00
// Entries = (REFIT_MENU_ENTRY **)AllocateZeroPool(sizeof(REFIT_MENU_ENTRY *) + ((sizeof(REFIT_MENU_ENTRY *) + sizeof(REFIT_MENU_ENTRY)) * Volumes.size()));
// if (Entries == NULL) {
// return FALSE;
// }
// EntryPtr = (REFIT_MENU_ENTRY *)(Entries + (Volumes.size() + 1));
2019-09-03 11:58:42 +02:00
// 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-10 17:50:55 +01:00
REFIT_SIMPLE_MENU_ENTRY_TAG * Entry = new REFIT_SIMPLE_MENU_ENTRY_TAG ( XStringWP ( ( Volume - > VolName = = NULL ) ? Volume - > DevicePathString : Volume - > VolName ) , TAG_OFFSET + Index , MENU_EXIT_ENTER ) ;
2020-02-28 21:28:33 +01:00
// Entry = Entries[Count++] = EntryPtr++;
// Entry->Title = (Volume->VolName == NULL) ? Volume->DevicePathString : Volume->VolName;
// Entry->Tag = TAG_OFFSET + Index;
// Entry->AtClick = MENU_EXIT_ENTER;
Menu . Entries . AddReference ( Entry , true ) ;
2019-09-03 11:58:42 +02:00
}
// Setup menu
2020-02-28 21:28:33 +01:00
// CopyMem(&Menu, &InitialMenu, sizeof(REFIT_MENU_SCREEN));
// Entries[Count++] = &MenuEntryReturn;
Menu . Entries . AddReference ( & MenuEntryReturn , false ) ;
// Menu.Entries.size() = Count;
// Menu.Entries = Entries;
2019-09-03 11:58:42 +02:00
Menu . Title = Title ;
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 ) ;
}