aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/ShellPkg/Application/Shell/FileHandleWrappers.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/ShellPkg/Application/Shell/FileHandleWrappers.c')
-rw-r--r--roms/edk2/ShellPkg/Application/Shell/FileHandleWrappers.c2154
1 files changed, 2154 insertions, 0 deletions
diff --git a/roms/edk2/ShellPkg/Application/Shell/FileHandleWrappers.c b/roms/edk2/ShellPkg/Application/Shell/FileHandleWrappers.c
new file mode 100644
index 000000000..a622a763f
--- /dev/null
+++ b/roms/edk2/ShellPkg/Application/Shell/FileHandleWrappers.c
@@ -0,0 +1,2154 @@
+/** @file
+ EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables,
+ StdIn, StdOut, StdErr, etc...).
+
+ Copyright 2016 Dell Inc.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Shell.h"
+#include "FileHandleInternal.h"
+
+#define MEM_WRITE_REALLOC_OVERHEAD 1024
+
+/**
+ File style interface for console (Open).
+
+ @param[in] This Ignored.
+ @param[out] NewHandle Ignored.
+ @param[in] FileName Ignored.
+ @param[in] OpenMode Ignored.
+ @param[in] Attributes Ignored.
+
+ @retval EFI_NOT_FOUND
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceOpenNotFound(
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+{
+ return (EFI_NOT_FOUND);
+}
+
+/**
+ File style interface for console (Close, Delete, & Flush)
+
+ @param[in] This Ignored.
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceNopGeneric(
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ return (EFI_SUCCESS);
+}
+
+/**
+ File style interface for console (GetPosition).
+
+ @param[in] This Ignored.
+ @param[out] Position Ignored.
+
+ @retval EFI_UNSUPPORTED
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceNopGetPosition(
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ )
+{
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ File style interface for console (SetPosition).
+
+ @param[in] This Ignored.
+ @param[in] Position Ignored.
+
+ @retval EFI_UNSUPPORTED
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceNopSetPosition(
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ )
+{
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ File style interface for console (GetInfo).
+
+ @param[in] This Ignored.
+ @param[in] InformationType Ignored.
+ @param[in, out] BufferSize Ignored.
+ @param[out] Buffer Ignored.
+
+ @retval EFI_UNSUPPORTED
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceNopGetInfo(
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ File style interface for console (SetInfo).
+
+ @param[in] This Ignored.
+ @param[in] InformationType Ignored.
+ @param[in] BufferSize Ignored.
+ @param[in] Buffer Ignored.
+
+ @retval EFI_UNSUPPORTED
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceNopSetInfo(
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ File style interface for StdOut (Write).
+
+ Writes data to the screen.
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+ @param[in, out] BufferSize Size in bytes of Buffer.
+ @param[in] Buffer The pointer to the buffer to write.
+
+ @retval EFI_UNSUPPORTED No output console is supported.
+ @return A return value from gST->ConOut->OutputString.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceStdOutWrite(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
+ return (EFI_UNSUPPORTED);
+ }
+ if (*((CHAR16 *)Buffer) == gUnicodeFileTag) {
+ return (gST->ConOut->OutputString(gST->ConOut, (CHAR16 *)Buffer + 1));
+ }
+ return (gST->ConOut->OutputString(gST->ConOut, Buffer));
+}
+
+/**
+ File style interface for StdIn (Write).
+
+ @param[in] This Ignored.
+ @param[in, out] BufferSize Ignored.
+ @param[in] Buffer Ignored.
+
+ @retval EFI_UNSUPPORTED
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceStdInWrite(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ File style interface for console StdErr (Write).
+
+ Writes error to the error output.
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+ @param[in, out] BufferSize Size in bytes of Buffer.
+ @param[in] Buffer The pointer to the buffer to write.
+
+ @return A return value from gST->StdErr->OutputString.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceStdErrWrite(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return (gST->StdErr->OutputString(gST->StdErr, Buffer));
+}
+
+/**
+ File style interface for console StdOut (Read).
+
+ @param[in] This Ignored.
+ @param[in, out] BufferSize Ignored.
+ @param[out] Buffer Ignored.
+
+ @retval EFI_UNSUPPORTED
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceStdOutRead(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ File style interface for console StdErr (Read).
+
+ @param[in] This Ignored.
+ @param[in, out] BufferSize Ignored.
+ @param[out] Buffer Ignored.
+
+ @retval EFI_UNSUPPORTED Always.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceStdErrRead(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ File style interface for NUL file (Read).
+
+ @param[in] This Ignored.
+ @param[in, out] BufferSize Poiner to 0 upon return.
+ @param[out] Buffer Ignored.
+
+ @retval EFI_SUCCESS Always.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceNulRead(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ *BufferSize = 0;
+ return (EFI_SUCCESS);
+}
+
+/**
+ File style interface for NUL file (Write).
+
+ @param[in] This Ignored.
+ @param[in, out] BufferSize Ignored.
+ @param[in] Buffer Ignored.
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceNulWrite(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return (EFI_SUCCESS);
+}
+
+/**
+ Create the TAB completion list.
+
+ @param[in] InputString The command line to expand.
+ @param[in] StringLen Length of the command line.
+ @param[in] BufferSize Buffer size.
+ @param[in, out] TabCompletionList Return the TAB completion list.
+ @param[in, out] TabUpdatePos Return the TAB update position.
+**/
+EFI_STATUS
+CreateTabCompletionList (
+ IN CONST CHAR16 *InputString,
+ IN CONST UINTN StringLen,
+ IN CONST UINTN BufferSize,
+ IN OUT EFI_SHELL_FILE_INFO **TabCompletionList,
+ IN OUT UINTN *TabUpdatePos
+)
+{
+ BOOLEAN InQuotation;
+ UINTN TabPos;
+ UINTN Index;
+ CONST CHAR16 *Cwd;
+ EFI_STATUS Status;
+ CHAR16 *TabStr;
+ EFI_SHELL_FILE_INFO *FileList;
+ EFI_SHELL_FILE_INFO *FileInfo;
+ EFI_SHELL_FILE_INFO *TempFileInfo;
+
+ //
+ // Allocate buffers
+ //
+ TabStr = AllocateZeroPool (BufferSize);
+ if (TabStr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // handle auto complete of file and directory names...
+ // E.g.: cd fs0:\EFI\Bo<TAB>
+ // ^ ^
+ // TabPos TabUpdatePos
+ //
+ TabPos = 0;
+ *TabUpdatePos = 0;
+ FileList = NULL;
+ InQuotation = FALSE;
+ for (Index = 0; Index < StringLen; Index++) {
+ switch (InputString[Index]) {
+ case L'\"':
+ InQuotation = (BOOLEAN) (!InQuotation);
+ break;
+
+ case L' ':
+ if (!InQuotation) {
+ TabPos = Index + 1;
+ *TabUpdatePos = TabPos;
+ }
+ break;
+
+ case L':':
+ //
+ // handle the case "fs0:<TAB>"
+ // Update the TabUpdatePos as well.
+ //
+ case L'\\':
+ *TabUpdatePos = Index + 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (StrStr (InputString + TabPos, L":") == NULL) {
+ //
+ // If file path doesn't contain ":", ...
+ //
+ Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL);
+ if (Cwd != NULL) {
+ if (InputString[TabPos] != L'\\') {
+ //
+ // and it doesn't begin with "\\", it's a path relative to current directory.
+ // TabStr = "<cwd>\\"
+ //
+ StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1);
+ StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\");
+ } else {
+ //
+ // and it begins with "\\", it's a path pointing to root directory of current map.
+ // TabStr = "fsx:"
+ //
+ Index = StrStr (Cwd, L":") - Cwd + 1;
+ StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, Index);
+ }
+ }
+ }
+ StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), InputString + TabPos, StringLen - TabPos);
+ StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"*", (BufferSize) / sizeof (CHAR16) - 1 - StrLen (TabStr));
+ Status = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FileList);
+
+ //
+ // Filter out the non-directory for "CD" command
+ // Filter "." and ".." for all
+ //
+ if (!EFI_ERROR (Status) && FileList != NULL) {
+ //
+ // Skip the spaces in the beginning
+ //
+ while (*InputString == L' ') {
+ InputString++;
+ }
+
+ for (FileInfo = (EFI_SHELL_FILE_INFO *) GetFirstNode (&FileList->Link); !IsNull (&FileList->Link, &FileInfo->Link); ) {
+ if (((StrCmp (FileInfo->FileName, L".") == 0) || (StrCmp (FileInfo->FileName, L"..") == 0)) ||
+ (((InputString[0] == L'c' || InputString[0] == L'C') && (InputString[1] == L'd' || InputString[1] == L'D')) &&
+ (ShellIsDirectory (FileInfo->FullName) != EFI_SUCCESS))) {
+ TempFileInfo = FileInfo;
+ FileInfo = (EFI_SHELL_FILE_INFO *) RemoveEntryList (&FileInfo->Link);
+ InternalFreeShellFileInfoNode (TempFileInfo);
+ } else {
+ FileInfo = (EFI_SHELL_FILE_INFO *) GetNextNode (&FileList->Link, &FileInfo->Link);
+ }
+ }
+ }
+
+ if (FileList != NULL && !IsListEmpty (&FileList->Link)) {
+ Status = EFI_SUCCESS;
+ } else {
+ ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FileList);
+ Status = EFI_NOT_FOUND;
+ }
+
+ FreePool (TabStr);
+
+ *TabCompletionList = FileList;
+ return Status;
+}
+
+/**
+ File style interface for console (Read).
+
+ This will return a single line of input from the console.
+
+ @param This A pointer to the EFI_FILE_PROTOCOL instance that is the
+ file handle to read data from. Not used.
+ @param BufferSize On input, the size of the Buffer. On output, the amount
+ of data returned in Buffer. In both cases, the size is
+ measured in bytes.
+ @param Buffer The buffer into which the data is read.
+
+
+ @retval EFI_SUCCESS The data was read.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file.
+ @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory
+ entry. BufferSize has been updated with the size
+ needed to complete the request.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceStdInRead(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ CHAR16 *CurrentString;
+ BOOLEAN Done;
+ UINTN TabUpdatePos; // Start index of the string updated by TAB stroke
+ UINTN Column; // Column of current cursor
+ UINTN Row; // Row of current cursor
+ UINTN StartColumn; // Column at the beginning of the line
+ UINTN Update; // Line index for update
+ UINTN Delete; // Num of chars to delete from console after update
+ UINTN StringLen; // Total length of the line
+ UINTN StringCurPos; // Line index corresponding to the cursor
+ UINTN MaxStr; // Maximum possible line length
+ UINTN TotalColumn; // Num of columns in the console
+ UINTN TotalRow; // Num of rows in the console
+ UINTN SkipLength;
+ UINTN OutputLength; // Length of the update string
+ UINTN TailRow; // Row of end of line
+ UINTN TailColumn; // Column of end of line
+ EFI_INPUT_KEY Key;
+
+ BUFFER_LIST *LinePos;
+ BUFFER_LIST *NewPos;
+ BOOLEAN InScrolling;
+ EFI_STATUS Status;
+ BOOLEAN InTabScrolling; // Whether in TAB-completion state
+ EFI_SHELL_FILE_INFO *TabCompleteList;
+ EFI_SHELL_FILE_INFO *TabCurrent;
+ UINTN EventIndex;
+ CHAR16 *TabOutputStr;
+
+ //
+ // If buffer is not large enough to hold a CHAR16, return minimum buffer size
+ //
+ if (*BufferSize < sizeof (CHAR16) * 2) {
+ *BufferSize = sizeof (CHAR16) * 2;
+ return (EFI_BUFFER_TOO_SMALL);
+ }
+
+ Done = FALSE;
+ CurrentString = Buffer;
+ StringLen = 0;
+ StringCurPos = 0;
+ OutputLength = 0;
+ Update = 0;
+ Delete = 0;
+ LinePos = NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);
+ InScrolling = FALSE;
+ InTabScrolling = FALSE;
+ Status = EFI_SUCCESS;
+ TabOutputStr = NULL;
+ TabUpdatePos = 0;
+ TabCompleteList = NULL;
+ TabCurrent = NULL;
+
+ //
+ // Get the screen setting and the current cursor location
+ //
+ Column = StartColumn = gST->ConOut->Mode->CursorColumn;
+ Row = gST->ConOut->Mode->CursorRow;
+ gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &TotalColumn, &TotalRow);
+
+ //
+ // Limit the line length to the buffer size or the minimum size of the
+ // screen. (The smaller takes effect)
+ //
+ MaxStr = TotalColumn * (TotalRow - 1) - StartColumn;
+ if (MaxStr > *BufferSize / sizeof (CHAR16)) {
+ MaxStr = *BufferSize / sizeof (CHAR16);
+ }
+ ZeroMem (CurrentString, MaxStr * sizeof (CHAR16));
+ do {
+ //
+ // Read a key
+ //
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (EFI_ERROR (Status)) {
+
+ if (Status == EFI_NOT_READY)
+ continue;
+
+ ZeroMem (CurrentString, MaxStr * sizeof(CHAR16));
+ StringLen = 0;
+ break;
+ }
+
+ //
+ // Press PageUp or PageDown to scroll the history screen up or down.
+ // Press any other key to quit scrolling.
+ //
+ if (Key.UnicodeChar == 0 && (Key.ScanCode == SCAN_PAGE_UP || Key.ScanCode == SCAN_PAGE_DOWN)) {
+ if (Key.ScanCode == SCAN_PAGE_UP) {
+ ConsoleLoggerDisplayHistory(FALSE, 0, ShellInfoObject.ConsoleInfo);
+ } else if (Key.ScanCode == SCAN_PAGE_DOWN) {
+ ConsoleLoggerDisplayHistory(TRUE, 0, ShellInfoObject.ConsoleInfo);
+ }
+
+ InScrolling = TRUE;
+ } else {
+ if (InScrolling) {
+ ConsoleLoggerStopHistory(ShellInfoObject.ConsoleInfo);
+ InScrolling = FALSE;
+ }
+ }
+
+ //
+ // If we are quitting TAB scrolling...
+ //
+ if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) {
+ if (TabCompleteList != NULL) {
+ ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);
+ DEBUG_CODE(TabCompleteList = NULL;);
+ }
+ InTabScrolling = FALSE;
+ }
+
+ switch (Key.UnicodeChar) {
+ case CHAR_CARRIAGE_RETURN:
+ //
+ // All done, print a newline at the end of the string
+ //
+ TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn;
+ TailColumn = (StringLen - StringCurPos + Column) % TotalColumn;
+ ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n");
+ Done = TRUE;
+ break;
+
+ case CHAR_BACKSPACE:
+ if (StringCurPos != 0) {
+ //
+ // If not move back beyond string beginning, move all characters behind
+ // the current position one character forward
+ //
+ StringCurPos--;
+ Update = StringCurPos;
+ Delete = 1;
+ CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
+
+ //
+ // Adjust the current column and row
+ //
+ MoveCursorBackward (TotalColumn, &Column, &Row);
+ }
+ break;
+
+ case CHAR_TAB:
+ if (!InTabScrolling) {
+ TabCurrent = NULL;
+ //
+ // Initialize a tab complete operation.
+ //
+ Status = CreateTabCompletionList (CurrentString, StringLen, *BufferSize, &TabCompleteList, &TabUpdatePos);
+ if (!EFI_ERROR(Status)) {
+ InTabScrolling = TRUE;
+ }
+
+ //
+ // We do not set up the replacement.
+ // The next section will do that.
+ //
+ }
+
+ if (InTabScrolling) {
+ //
+ // We are in a tab complete operation.
+ // set up the next replacement.
+ //
+ ASSERT(TabCompleteList != NULL);
+ if (TabCurrent == NULL) {
+ TabCurrent = (EFI_SHELL_FILE_INFO*) GetFirstNode (&TabCompleteList->Link);
+ } else {
+ TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);
+ }
+
+ //
+ // Skip over the empty list beginning node
+ //
+ if (IsNull(&TabCompleteList->Link, &TabCurrent->Link)) {
+ TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);
+ }
+ }
+ break;
+
+ default:
+ if (Key.UnicodeChar >= ' ') {
+ //
+ // If we are at the buffer's end, drop the key
+ //
+ if (StringLen == MaxStr - 1 && (ShellInfoObject.ViewingSettings.InsertMode || StringCurPos == StringLen)) {
+ break;
+ }
+ //
+ // If in insert mode, make space by moving each other character 1
+ // space higher in the array
+ //
+ if (ShellInfoObject.ViewingSettings.InsertMode) {
+ CopyMem(CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof(CurrentString[0]));
+ }
+
+ CurrentString[StringCurPos] = Key.UnicodeChar;
+ Update = StringCurPos;
+
+ StringCurPos += 1;
+ OutputLength = 1;
+ }
+ break;
+
+ case 0:
+ switch (Key.ScanCode) {
+ case SCAN_DELETE:
+ //
+ // Move characters behind current position one character forward
+ //
+ if (StringLen != 0) {
+ Update = StringCurPos;
+ Delete = 1;
+ CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
+ }
+ break;
+
+ case SCAN_UP:
+ //
+ // Prepare to print the previous command
+ //
+ NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
+ if (IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link)) {
+ NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
+ }
+ break;
+
+ case SCAN_DOWN:
+ //
+ // Prepare to print the next command
+ //
+ NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
+ if (NewPos == (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
+ NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
+ }
+ break;
+
+ case SCAN_LEFT:
+ //
+ // Adjust current cursor position
+ //
+ if (StringCurPos != 0) {
+ --StringCurPos;
+ MoveCursorBackward (TotalColumn, &Column, &Row);
+ }
+ break;
+
+ case SCAN_RIGHT:
+ //
+ // Adjust current cursor position
+ //
+ if (StringCurPos < StringLen) {
+ ++StringCurPos;
+ MoveCursorForward (TotalColumn, TotalRow, &Column, &Row);
+ }
+ break;
+
+ case SCAN_HOME:
+ //
+ // Move current cursor position to the beginning of the command line
+ //
+ Row -= (StringCurPos + StartColumn) / TotalColumn;
+ Column = StartColumn;
+ StringCurPos = 0;
+ break;
+
+ case SCAN_END:
+ //
+ // Move current cursor position to the end of the command line
+ //
+ TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn;
+ TailColumn = (StringLen - StringCurPos + Column) % TotalColumn;
+ Row = TailRow;
+ Column = TailColumn;
+ StringCurPos = StringLen;
+ break;
+
+ case SCAN_ESC:
+ //
+ // Prepare to clear the current command line
+ //
+ CurrentString[0] = 0;
+ Update = 0;
+ Delete = StringLen;
+ Row -= (StringCurPos + StartColumn) / TotalColumn;
+ Column = StartColumn;
+ OutputLength = 0;
+ break;
+
+ case SCAN_INSERT:
+ //
+ // Toggle the SEnvInsertMode flag
+ //
+ ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN)!ShellInfoObject.ViewingSettings.InsertMode;
+ break;
+
+ case SCAN_F7:
+ //
+ // Print command history
+ //
+ PrintCommandHistory (TotalColumn, TotalRow, 4);
+ *CurrentString = CHAR_NULL;
+ Done = TRUE;
+ break;
+ }
+ }
+
+ if (Done) {
+ break;
+ }
+
+ //
+ // If we are in auto-complete mode, we are preparing to print
+ // the next file or directory name
+ //
+ if (InTabScrolling) {
+ TabOutputStr = AllocateZeroPool (*BufferSize);
+ if (TabOutputStr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if (InTabScrolling && TabOutputStr != NULL) {
+
+ //
+ // Adjust the column and row to the start of TAB-completion string.
+ //
+ Column = (StartColumn + TabUpdatePos) % TotalColumn;
+ Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;
+ OutputLength = StrLen (TabCurrent->FileName);
+ //
+ // if the output string contains blank space, quotation marks L'\"'
+ // should be added to the output.
+ //
+ if (StrStr(TabCurrent->FileName, L" ") != NULL){
+ TabOutputStr[0] = L'\"';
+ CopyMem (TabOutputStr + 1, TabCurrent->FileName, OutputLength * sizeof (CHAR16));
+ TabOutputStr[OutputLength + 1] = L'\"';
+ TabOutputStr[OutputLength + 2] = CHAR_NULL;
+ } else {
+ CopyMem (TabOutputStr, TabCurrent->FileName, OutputLength * sizeof (CHAR16));
+ TabOutputStr[OutputLength] = CHAR_NULL;
+ }
+ OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1;
+ CopyMem (CurrentString + TabUpdatePos, TabOutputStr, OutputLength * sizeof (CHAR16));
+ CurrentString[TabUpdatePos + OutputLength] = CHAR_NULL;
+ StringCurPos = TabUpdatePos + OutputLength;
+ Update = TabUpdatePos;
+ if (StringLen > TabUpdatePos + OutputLength) {
+ Delete = StringLen - TabUpdatePos - OutputLength;
+ }
+
+ FreePool(TabOutputStr);
+ }
+
+ //
+ // If we have a new position, we are preparing to print a previous or
+ // next command.
+ //
+ if (NewPos != (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
+ Column = StartColumn;
+ Row -= (StringCurPos + StartColumn) / TotalColumn;
+
+ LinePos = NewPos;
+ NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);
+
+ OutputLength = StrLen (LinePos->Buffer) < MaxStr - 1 ? StrLen (LinePos->Buffer) : MaxStr - 1;
+ CopyMem (CurrentString, LinePos->Buffer, OutputLength * sizeof (CHAR16));
+ CurrentString[OutputLength] = CHAR_NULL;
+
+ StringCurPos = OutputLength;
+
+ //
+ // Draw new input string
+ //
+ Update = 0;
+ if (StringLen > OutputLength) {
+ //
+ // If old string was longer, blank its tail
+ //
+ Delete = StringLen - OutputLength;
+ }
+ }
+ //
+ // If we need to update the output do so now
+ //
+ if (Update != (UINTN) -1) {
+ ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L"");
+ StringLen = StrLen (CurrentString);
+
+ if (Delete != 0) {
+ SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL);
+ }
+
+ if (StringCurPos > StringLen) {
+ StringCurPos = StringLen;
+ }
+
+ Update = (UINTN) -1;
+
+ //
+ // After using print to reflect newly updates, if we're not using
+ // BACKSPACE and DELETE, we need to move the cursor position forward,
+ // so adjust row and column here.
+ //
+ if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
+ //
+ // Calculate row and column of the tail of current string
+ //
+ TailRow = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn;
+ TailColumn = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn;
+
+ //
+ // If the tail of string reaches screen end, screen rolls up, so if
+ // Row does not equal TailRow, Row should be decremented
+ //
+ // (if we are recalling commands using UPPER and DOWN key, and if the
+ // old command is too long to fit the screen, TailColumn must be 79.
+ //
+ if (TailColumn == 0 && TailRow >= TotalRow && Row != TailRow) {
+ Row--;
+ }
+ //
+ // Calculate the cursor position after current operation. If cursor
+ // reaches line end, update both row and column, otherwise, only
+ // column will be changed.
+ //
+ if (Column + OutputLength >= TotalColumn) {
+ SkipLength = OutputLength - (TotalColumn - Column);
+
+ Row += SkipLength / TotalColumn + 1;
+ if (Row > TotalRow - 1) {
+ Row = TotalRow - 1;
+ }
+
+ Column = SkipLength % TotalColumn;
+ } else {
+ Column += OutputLength;
+ }
+ }
+
+ Delete = 0;
+ }
+ //
+ // Set the cursor position for this key
+ //
+ gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);
+ } while (!Done);
+
+ if (CurrentString != NULL && StrLen(CurrentString) > 0) {
+ //
+ // add the line to the history buffer
+ //
+ AddLineToCommandHistory(CurrentString);
+ }
+
+ //
+ // Return the data to the caller
+ //
+ *BufferSize = StringLen * sizeof (CHAR16);
+
+ //
+ // if this was used it should be deallocated by now...
+ // prevent memory leaks...
+ //
+ if (TabCompleteList != NULL) {
+ ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);
+ }
+ ASSERT(TabCompleteList == NULL);
+
+ return Status;
+}
+
+//
+// FILE style interfaces for StdIn/StdOut/StdErr
+//
+EFI_FILE_PROTOCOL FileInterfaceStdIn = {
+ EFI_FILE_REVISION,
+ FileInterfaceOpenNotFound,
+ FileInterfaceNopGeneric,
+ FileInterfaceNopGeneric,
+ FileInterfaceStdInRead,
+ FileInterfaceStdInWrite,
+ FileInterfaceNopGetPosition,
+ FileInterfaceNopSetPosition,
+ FileInterfaceNopGetInfo,
+ FileInterfaceNopSetInfo,
+ FileInterfaceNopGeneric
+};
+
+EFI_FILE_PROTOCOL FileInterfaceStdOut = {
+ EFI_FILE_REVISION,
+ FileInterfaceOpenNotFound,
+ FileInterfaceNopGeneric,
+ FileInterfaceNopGeneric,
+ FileInterfaceStdOutRead,
+ FileInterfaceStdOutWrite,
+ FileInterfaceNopGetPosition,
+ FileInterfaceNopSetPosition,
+ FileInterfaceNopGetInfo,
+ FileInterfaceNopSetInfo,
+ FileInterfaceNopGeneric
+};
+
+EFI_FILE_PROTOCOL FileInterfaceStdErr = {
+ EFI_FILE_REVISION,
+ FileInterfaceOpenNotFound,
+ FileInterfaceNopGeneric,
+ FileInterfaceNopGeneric,
+ FileInterfaceStdErrRead,
+ FileInterfaceStdErrWrite,
+ FileInterfaceNopGetPosition,
+ FileInterfaceNopSetPosition,
+ FileInterfaceNopGetInfo,
+ FileInterfaceNopSetInfo,
+ FileInterfaceNopGeneric
+};
+
+EFI_FILE_PROTOCOL FileInterfaceNulFile = {
+ EFI_FILE_REVISION,
+ FileInterfaceOpenNotFound,
+ FileInterfaceNopGeneric,
+ FileInterfaceNopGeneric,
+ FileInterfaceNulRead,
+ FileInterfaceNulWrite,
+ FileInterfaceNopGetPosition,
+ FileInterfaceNopSetPosition,
+ FileInterfaceNopGetInfo,
+ FileInterfaceNopSetInfo,
+ FileInterfaceNopGeneric
+};
+
+
+
+
+//
+// This is identical to EFI_FILE_PROTOCOL except for the additional member
+// for the name.
+//
+
+typedef struct {
+ UINT64 Revision;
+ EFI_FILE_OPEN Open;
+ EFI_FILE_CLOSE Close;
+ EFI_FILE_DELETE Delete;
+ EFI_FILE_READ Read;
+ EFI_FILE_WRITE Write;
+ EFI_FILE_GET_POSITION GetPosition;
+ EFI_FILE_SET_POSITION SetPosition;
+ EFI_FILE_GET_INFO GetInfo;
+ EFI_FILE_SET_INFO SetInfo;
+ EFI_FILE_FLUSH Flush;
+ CHAR16 Name[1];
+} EFI_FILE_PROTOCOL_ENVIRONMENT;
+//ANSI compliance helper to get size of the struct.
+#define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name)
+
+/**
+ File style interface for Environment Variable (Close).
+
+ Frees the memory for this object.
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceEnvClose(
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ VOID* NewBuffer;
+ UINTN NewSize;
+ EFI_STATUS Status;
+ BOOLEAN Volatile;
+ UINTN TotalSize;
+
+ //
+ // Most if not all UEFI commands will have an '\r\n' at the end of any output.
+ // Since the output was redirected to a variable, it does not make sense to
+ // keep this. So, before closing, strip the trailing '\r\n' from the variable
+ // if it exists.
+ //
+ NewBuffer = NULL;
+ NewSize = 0;
+ TotalSize = 0;
+
+ Status = IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &Volatile);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ TotalSize = NewSize + sizeof (CHAR16);
+ NewBuffer = AllocateZeroPool (TotalSize);
+ if (NewBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
+ }
+
+ if (!EFI_ERROR(Status) && NewBuffer != NULL) {
+
+ if (TotalSize / sizeof (CHAR16) >= 3) {
+ if ( (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 2] == CHAR_LINEFEED) &&
+ (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] == CHAR_CARRIAGE_RETURN)
+ ) {
+ ((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] = CHAR_NULL;
+ //
+ // If the NewBuffer end with \r\n\0, We will replace '\r' by '\0' and then update TotalSize.
+ //
+ TotalSize -= sizeof(CHAR16) * 2;
+ }
+
+ if (Volatile) {
+ Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
+ TotalSize - sizeof (CHAR16),
+ NewBuffer
+ );
+
+ if (!EFI_ERROR(Status)) {
+ Status = ShellAddEnvVarToList (
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
+ NewBuffer,
+ TotalSize,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+ }
+ } else {
+ Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
+ TotalSize - sizeof (CHAR16),
+ NewBuffer
+ );
+
+ if (!EFI_ERROR(Status)) {
+ Status = ShellAddEnvVarToList (
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
+ NewBuffer,
+ TotalSize,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+ }
+ }
+ }
+ }
+
+ SHELL_FREE_NON_NULL(NewBuffer);
+ FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This);
+ return (Status);
+}
+
+/**
+ File style interface for Environment Variable (Delete).
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+
+ @retval The return value from FileInterfaceEnvClose().
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceEnvDelete(
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
+ return (FileInterfaceEnvClose(This));
+}
+
+/**
+ File style interface for Environment Variable (Read).
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+ @param[in, out] BufferSize Size in bytes of Buffer.
+ @param[out] Buffer The pointer to the buffer to fill.
+
+ @retval EFI_SUCCESS The data was read.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceEnvRead(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ *BufferSize = *BufferSize / sizeof (CHAR16) * sizeof (CHAR16);
+ if (*BufferSize != 0) {
+ //
+ // Make sure the first unicode character is \xFEFF
+ //
+ *(CHAR16 *)Buffer = gUnicodeFileTag;
+ Buffer = (CHAR16 *)Buffer + 1;
+ *BufferSize -= sizeof (gUnicodeFileTag);
+ }
+
+ Status = SHELL_GET_ENVIRONMENT_VARIABLE (
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
+ BufferSize,
+ Buffer
+ );
+ if (!EFI_ERROR (Status) || (Status == EFI_BUFFER_TOO_SMALL)) {
+ //
+ // BufferSize is valid and needs update when Status is Success or BufferTooSmall.
+ //
+ *BufferSize += sizeof (gUnicodeFileTag);
+ }
+ return Status;
+}
+
+/**
+ File style interface for Volatile Environment Variable (Write).
+ This function also caches the environment variable into gShellEnvVarList.
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+ @param[in, out] BufferSize Size in bytes of Buffer.
+ @param[in] Buffer The pointer to the buffer to write.
+
+ @retval EFI_SUCCESS The data was successfully write to variable.
+ @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceEnvVolWrite(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ VOID* NewBuffer;
+ UINTN NewSize;
+ EFI_STATUS Status;
+ UINTN TotalSize;
+
+ NewBuffer = NULL;
+ NewSize = 0;
+ TotalSize = 0;
+
+ Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ TotalSize = NewSize + *BufferSize + sizeof (CHAR16);
+ } else if (Status == EFI_NOT_FOUND) {
+ TotalSize = *BufferSize + sizeof(CHAR16);
+ } else {
+ return Status;
+ }
+
+ NewBuffer = AllocateZeroPool (TotalSize);
+ if (NewBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
+ }
+
+ if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
+ FreePool (NewBuffer);
+ return Status;
+ }
+
+ CopyMem ((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);
+ Status = ShellAddEnvVarToList (
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
+ NewBuffer,
+ TotalSize,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool (NewBuffer);
+ return Status;
+ }
+
+ Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
+ TotalSize - sizeof (CHAR16),
+ NewBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
+ }
+
+ FreePool (NewBuffer);
+ return Status;
+}
+
+
+/**
+ File style interface for Non Volatile Environment Variable (Write).
+ This function also caches the environment variable into gShellEnvVarList.
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+ @param[in, out] BufferSize Size in bytes of Buffer.
+ @param[in] Buffer The pointer to the buffer to write.
+
+ @retval EFI_SUCCESS The data was successfully write to variable.
+ @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceEnvNonVolWrite(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ VOID* NewBuffer;
+ UINTN NewSize;
+ EFI_STATUS Status;
+ UINTN TotalSize;
+
+ NewBuffer = NULL;
+ NewSize = 0;
+ TotalSize = 0;
+
+ Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ TotalSize = NewSize + *BufferSize + sizeof (CHAR16);
+ } else if (Status == EFI_NOT_FOUND) {
+ TotalSize = *BufferSize + sizeof (CHAR16);
+ } else {
+ return Status;
+ }
+
+ NewBuffer = AllocateZeroPool (TotalSize);
+ if (NewBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
+ }
+
+ if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {
+ FreePool (NewBuffer);
+ return Status;
+ }
+
+ CopyMem ((UINT8*) NewBuffer + NewSize, Buffer, *BufferSize);
+ Status = ShellAddEnvVarToList (
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
+ NewBuffer,
+ TotalSize,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (NewBuffer);
+ return Status;
+ }
+
+ Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
+ TotalSize - sizeof (CHAR16),
+ NewBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
+ }
+
+ FreePool (NewBuffer);
+ return Status;
+}
+
+/**
+ Creates a EFI_FILE_PROTOCOL (almost) object for using to access
+ environment variables through file operations.
+
+ @param EnvName The name of the Environment Variable to be operated on.
+
+ @retval NULL Memory could not be allocated.
+ @return other a pointer to an EFI_FILE_PROTOCOL structure
+**/
+EFI_FILE_PROTOCOL*
+CreateFileInterfaceEnv(
+ IN CONST CHAR16 *EnvName
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_PROTOCOL_ENVIRONMENT *EnvFileInterface;
+ UINTN EnvNameSize;
+ BOOLEAN Volatile;
+
+ if (EnvName == NULL) {
+ return (NULL);
+ }
+
+ Status = IsVolatileEnv (EnvName, &Volatile);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Get some memory
+ //
+ EnvNameSize = StrSize(EnvName);
+ EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize);
+ if (EnvFileInterface == NULL){
+ return (NULL);
+ }
+
+ //
+ // Assign the generic members
+ //
+ EnvFileInterface->Revision = EFI_FILE_REVISION;
+ EnvFileInterface->Open = FileInterfaceOpenNotFound;
+ EnvFileInterface->Close = FileInterfaceEnvClose;
+ EnvFileInterface->GetPosition = FileInterfaceNopGetPosition;
+ EnvFileInterface->SetPosition = FileInterfaceNopSetPosition;
+ EnvFileInterface->GetInfo = FileInterfaceNopGetInfo;
+ EnvFileInterface->SetInfo = FileInterfaceNopSetInfo;
+ EnvFileInterface->Flush = FileInterfaceNopGeneric;
+ EnvFileInterface->Delete = FileInterfaceEnvDelete;
+ EnvFileInterface->Read = FileInterfaceEnvRead;
+
+ CopyMem(EnvFileInterface->Name, EnvName, EnvNameSize);
+
+ //
+ // Assign the different members for Volatile and Non-Volatile variables
+ //
+ if (Volatile) {
+ EnvFileInterface->Write = FileInterfaceEnvVolWrite;
+ } else {
+ EnvFileInterface->Write = FileInterfaceEnvNonVolWrite;
+ }
+ return ((EFI_FILE_PROTOCOL *)EnvFileInterface);
+}
+
+/**
+ Move the cursor position one character backward.
+
+ @param[in] LineLength Length of a line. Get it by calling QueryMode
+ @param[in, out] Column Current column of the cursor position
+ @param[in, out] Row Current row of the cursor position
+**/
+VOID
+MoveCursorBackward (
+ IN UINTN LineLength,
+ IN OUT UINTN *Column,
+ IN OUT UINTN *Row
+ )
+{
+ //
+ // If current column is 0, move to the last column of the previous line,
+ // otherwise, just decrement column.
+ //
+ if (*Column == 0) {
+ *Column = LineLength - 1;
+ if (*Row > 0) {
+ (*Row)--;
+ }
+ return;
+ }
+ (*Column)--;
+}
+
+/**
+ Move the cursor position one character forward.
+
+ @param[in] LineLength Length of a line.
+ @param[in] TotalRow Total row of a screen
+ @param[in, out] Column Current column of the cursor position
+ @param[in, out] Row Current row of the cursor position
+**/
+VOID
+MoveCursorForward (
+ IN UINTN LineLength,
+ IN UINTN TotalRow,
+ IN OUT UINTN *Column,
+ IN OUT UINTN *Row
+ )
+{
+ //
+ // Increment Column.
+ // If this puts column past the end of the line, move to first column
+ // of the next row.
+ //
+ (*Column)++;
+ if (*Column >= LineLength) {
+ (*Column) = 0;
+ if ((*Row) < TotalRow - 1) {
+ (*Row)++;
+ }
+ }
+}
+
+/**
+ Prints out each previously typed command in the command list history log.
+
+ When each screen is full it will pause for a key before continuing.
+
+ @param[in] TotalCols How many columns are on the screen
+ @param[in] TotalRows How many rows are on the screen
+ @param[in] StartColumn which column to start at
+**/
+VOID
+PrintCommandHistory (
+ IN CONST UINTN TotalCols,
+ IN CONST UINTN TotalRows,
+ IN CONST UINTN StartColumn
+ )
+{
+ BUFFER_LIST *Node;
+ UINTN Index;
+ UINTN LineNumber;
+ UINTN LineCount;
+
+ ShellPrintEx (-1, -1, L"\n");
+ Index = 0;
+ LineNumber = 0;
+ //
+ // go through history list...
+ //
+ for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link)
+ ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)
+ ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)
+ ){
+ Index++;
+ LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1;
+
+ if (LineNumber + LineCount >= TotalRows) {
+ ShellPromptForResponseHii(
+ ShellPromptResponseTypeEnterContinue,
+ STRING_TOKEN (STR_SHELL_ENTER_TO_CONT),
+ ShellInfoObject.HiiHandle,
+ NULL
+ );
+ LineNumber = 0;
+ }
+ ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer);
+ LineNumber += LineCount;
+ }
+}
+
+
+
+
+
+
+//
+// This is identical to EFI_FILE_PROTOCOL except for the additional members
+// for the buffer, size, and position.
+//
+
+typedef struct {
+ UINT64 Revision;
+ EFI_FILE_OPEN Open;
+ EFI_FILE_CLOSE Close;
+ EFI_FILE_DELETE Delete;
+ EFI_FILE_READ Read;
+ EFI_FILE_WRITE Write;
+ EFI_FILE_GET_POSITION GetPosition;
+ EFI_FILE_SET_POSITION SetPosition;
+ EFI_FILE_GET_INFO GetInfo;
+ EFI_FILE_SET_INFO SetInfo;
+ EFI_FILE_FLUSH Flush;
+ VOID *Buffer;
+ UINT64 Position;
+ UINT64 BufferSize;
+ BOOLEAN Unicode;
+ UINT64 FileSize;
+} EFI_FILE_PROTOCOL_MEM;
+
+/**
+ File style interface for Mem (SetPosition).
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+ @param[out] Position The position to set.
+
+ @retval EFI_SUCCESS The position was successfully changed.
+ @retval EFI_INVALID_PARAMETER The Position was invalid.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceMemSetPosition(
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 Position
+ )
+{
+ if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize) {
+ ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position;
+ return (EFI_SUCCESS);
+ } else {
+ return (EFI_INVALID_PARAMETER);
+ }
+}
+
+/**
+ File style interface for Mem (GetPosition).
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+ @param[out] Position The pointer to the position.
+
+ @retval EFI_SUCCESS The position was retrieved.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceMemGetPosition(
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ )
+{
+ *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position;
+ return (EFI_SUCCESS);
+}
+
+/**
+ File style interface for Mem (GetInfo).
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information to return in Buffer.
+ @param BufferSize On input size of buffer, on output amount of data in buffer.
+ @param Buffer The buffer to return data.
+
+ @retval EFI_SUCCESS Data was returned.
+ @retval EFI_UNSUPPORT InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
+
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceMemGetInfo(
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_FILE_INFO *FileInfo;
+
+ if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
+ if (*BufferSize < sizeof (EFI_FILE_INFO)) {
+ *BufferSize = sizeof (EFI_FILE_INFO);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ FileInfo = (EFI_FILE_INFO *)Buffer;
+ FileInfo->Size = sizeof (*FileInfo);
+ ZeroMem (FileInfo, sizeof (*FileInfo));
+ FileInfo->FileSize = ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize;
+ FileInfo->PhysicalSize = FileInfo->FileSize;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ File style interface for Mem (Write).
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+ @param[in, out] BufferSize Size in bytes of Buffer.
+ @param[in] Buffer The pointer to the buffer to write.
+
+ @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.
+ @retval EFI_SUCCESS The data was written.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceMemWrite(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ CHAR8 *AsciiBuffer;
+ EFI_FILE_PROTOCOL_MEM *MemFile;
+
+ MemFile = (EFI_FILE_PROTOCOL_MEM *) This;
+ if (MemFile->Unicode) {
+ //
+ // Unicode
+ //
+ if ((UINTN)(MemFile->Position + (*BufferSize)) > (UINTN)(MemFile->BufferSize)) {
+ MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);
+ if (MemFile->Buffer == NULL){
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFile->BufferSize += (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD;
+ }
+ CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, Buffer, *BufferSize);
+ MemFile->Position += (*BufferSize);
+ MemFile->FileSize = MemFile->Position;
+ return (EFI_SUCCESS);
+ } else {
+ //
+ // Ascii
+ //
+ AsciiBuffer = AllocateZeroPool(*BufferSize);
+ if (AsciiBuffer == NULL) {
+ return (EFI_OUT_OF_RESOURCES);
+ }
+ AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);
+ if ((UINTN)(MemFile->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(MemFile->BufferSize)) {
+ MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);
+ if (MemFile->Buffer == NULL){
+ FreePool(AsciiBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFile->BufferSize += AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD;
+ }
+ CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer));
+ MemFile->Position += (*BufferSize / sizeof(CHAR16));
+ MemFile->FileSize = MemFile->Position;
+ FreePool(AsciiBuffer);
+ return (EFI_SUCCESS);
+ }
+}
+
+/**
+ File style interface for Mem (Read).
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+ @param[in, out] BufferSize Size in bytes of Buffer.
+ @param[in] Buffer The pointer to the buffer to fill.
+
+ @retval EFI_SUCCESS The data was read.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceMemRead(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_FILE_PROTOCOL_MEM *MemFile;
+
+ MemFile = (EFI_FILE_PROTOCOL_MEM *) This;
+ if (*BufferSize > (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position))) {
+ (*BufferSize) = (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position));
+ }
+ CopyMem(Buffer, ((UINT8*)MemFile->Buffer) + MemFile->Position, (*BufferSize));
+ MemFile->Position = MemFile->Position + (*BufferSize);
+ return (EFI_SUCCESS);
+}
+
+/**
+ File style interface for Mem (Close).
+
+ Frees all memory associated with this object.
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+
+ @retval EFI_SUCCESS The 'file' was closed.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceMemClose(
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);
+ SHELL_FREE_NON_NULL(This);
+ return (EFI_SUCCESS);
+}
+
+/**
+ Creates a EFI_FILE_PROTOCOL (almost) object for using to access
+ a file entirely in memory through file operations.
+
+ @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii.
+
+ @retval NULL Memory could not be allocated.
+ @return other A pointer to an EFI_FILE_PROTOCOL structure.
+**/
+EFI_FILE_PROTOCOL*
+CreateFileInterfaceMem(
+ IN CONST BOOLEAN Unicode
+ )
+{
+ EFI_FILE_PROTOCOL_MEM *FileInterface;
+
+ //
+ // Get some memory
+ //
+ FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM));
+ if (FileInterface == NULL){
+ return (NULL);
+ }
+
+ //
+ // Assign the generic members
+ //
+ FileInterface->Revision = EFI_FILE_REVISION;
+ FileInterface->Open = FileInterfaceOpenNotFound;
+ FileInterface->Close = FileInterfaceMemClose;
+ FileInterface->GetPosition = FileInterfaceMemGetPosition;
+ FileInterface->SetPosition = FileInterfaceMemSetPosition;
+ FileInterface->GetInfo = FileInterfaceMemGetInfo;
+ FileInterface->SetInfo = FileInterfaceNopSetInfo;
+ FileInterface->Flush = FileInterfaceNopGeneric;
+ FileInterface->Delete = FileInterfaceNopGeneric;
+ FileInterface->Read = FileInterfaceMemRead;
+ FileInterface->Write = FileInterfaceMemWrite;
+ FileInterface->Unicode = Unicode;
+
+ ASSERT(FileInterface->Buffer == NULL);
+ ASSERT(FileInterface->BufferSize == 0);
+ ASSERT(FileInterface->Position == 0);
+
+ if (Unicode) {
+ FileInterface->Buffer = AllocateZeroPool(sizeof(gUnicodeFileTag));
+ if (FileInterface->Buffer == NULL) {
+ FreePool (FileInterface);
+ return NULL;
+ }
+ *((CHAR16 *) (FileInterface->Buffer)) = EFI_UNICODE_BYTE_ORDER_MARK;
+ FileInterface->BufferSize = 2;
+ FileInterface->Position = 2;
+ }
+
+ return ((EFI_FILE_PROTOCOL *)FileInterface);
+}
+
+typedef struct {
+ UINT64 Revision;
+ EFI_FILE_OPEN Open;
+ EFI_FILE_CLOSE Close;
+ EFI_FILE_DELETE Delete;
+ EFI_FILE_READ Read;
+ EFI_FILE_WRITE Write;
+ EFI_FILE_GET_POSITION GetPosition;
+ EFI_FILE_SET_POSITION SetPosition;
+ EFI_FILE_GET_INFO GetInfo;
+ EFI_FILE_SET_INFO SetInfo;
+ EFI_FILE_FLUSH Flush;
+ BOOLEAN Unicode;
+ EFI_FILE_PROTOCOL *Orig;
+} EFI_FILE_PROTOCOL_FILE;
+
+/**
+ Set a files current position
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
+
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceFileSetPosition(
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ )
+{
+ return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);
+}
+
+/**
+ Get a file's current position
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
+
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceFileGetPosition(
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ )
+{
+ return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);
+}
+
+/**
+ Get information about a file.
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information to return in Buffer.
+ @param BufferSize On input size of buffer, on output amount of data in buffer.
+ @param Buffer The buffer to return data.
+
+ @retval EFI_SUCCESS Data was returned.
+ @retval EFI_UNSUPPORT InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
+
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceFileGetInfo(
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);
+}
+
+/**
+ Set information about a file
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information in Buffer.
+ @param BufferSize Size of buffer.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS Data was returned.
+ @retval EFI_UNSUPPORT InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceFileSetInfo(
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);
+}
+
+/**
+ Flush data back for the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORT Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceFileFlush(
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Flush(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
+}
+
+/**
+ Read data from the file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in buffer.
+ @param Buffer The buffer in which data is read.
+
+ @retval EFI_SUCCESS Data was read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
+
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceFileRead(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Position;
+ CHAR8 *AsciiStrBuffer;
+ CHAR16 *UscStrBuffer;
+ UINTN Size;
+ if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {
+ //
+ // Unicode
+ // There might be different file tag for the Unicode file. We cannot unconditionally insert the \xFEFF.
+ // So we choose to leave the file content as is.
+ //
+ return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));
+ } else {
+ //
+ // Ascii
+ //
+ *BufferSize = *BufferSize / sizeof (CHAR16) * sizeof (CHAR16);
+ if (*BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+ Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition (((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Position);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Position == 0) {
+ //
+ // First two bytes in Buffer is for the Unicode file tag.
+ //
+ *(CHAR16 *)Buffer = gUnicodeFileTag;
+ Buffer = (CHAR16 *)Buffer + 1;
+ Size = *BufferSize / sizeof (CHAR16) - 1;
+ } else {
+ Size = *BufferSize / sizeof (CHAR16);
+ }
+ AsciiStrBuffer = AllocateZeroPool (Size + 1);
+ if (AsciiStrBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UscStrBuffer = AllocateZeroPool ((Size + 1) * sizeof(CHAR16));
+ if (UscStrBuffer== NULL) {
+ SHELL_FREE_NON_NULL(AsciiStrBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read (((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiStrBuffer);
+ if (!EFI_ERROR(Status)) {
+ AsciiStrToUnicodeStrS (AsciiStrBuffer, UscStrBuffer, Size + 1);
+ *BufferSize = Size * sizeof (CHAR16);
+ CopyMem (Buffer, UscStrBuffer, *BufferSize);
+ }
+ SHELL_FREE_NON_NULL (AsciiStrBuffer);
+ SHELL_FREE_NON_NULL (UscStrBuffer);
+ return Status;
+ }
+}
+
+/**
+ Opens a new file relative to the source file's location.
+
+ @param[in] This The protocol instance pointer.
+ @param[out] NewHandle Returns File Handle for FileName.
+ @param[in] FileName Null terminated string. "\", ".", and ".." are supported.
+ @param[in] OpenMode Open mode for file.
+ @param[in] Attributes Only used for EFI_FILE_MODE_CREATE.
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_NOT_FOUND The specified file could not be found on the device.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_MEDIA_CHANGED The media has changed.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+ @retval EFI_VOLUME_FULL The volume is full.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceFileOpen (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+{
+ return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Open(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, NewHandle, FileName, OpenMode, Attributes);
+}
+
+/**
+ Close and delete the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
+
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceFileDelete(
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Delete(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
+ FreePool(This);
+ return (Status);
+}
+
+/**
+ File style interface for File (Close).
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+
+ @retval EFI_SUCCESS The file was closed.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceFileClose(
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
+ FreePool(This);
+ return (Status);
+}
+
+/**
+ File style interface for File (Write).
+
+ If the file was opened with ASCII mode the data will be processed through
+ AsciiSPrint before writing.
+
+ @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
+ @param[in, out] BufferSize Size in bytes of Buffer.
+ @param[in] Buffer The pointer to the buffer to write.
+
+ @retval EFI_SUCCESS The data was written.
+**/
+EFI_STATUS
+EFIAPI
+FileInterfaceFileWrite(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ CHAR8 *AsciiBuffer;
+ UINTN Size;
+ EFI_STATUS Status;
+ if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {
+ //
+ // Unicode
+ //
+ return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));
+ } else {
+ //
+ // Ascii
+ //
+ AsciiBuffer = AllocateZeroPool(*BufferSize);
+ AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);
+ Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator)
+ Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer));
+ FreePool(AsciiBuffer);
+ return (Status);
+ }
+}
+
+/**
+ Create a file interface with unicode information.
+
+ This will create a new EFI_FILE_PROTOCOL identical to the Templace
+ except that the new one has Unicode and Ascii knowledge.
+
+ @param[in] Template A pointer to the EFI_FILE_PROTOCOL object.
+ @param[in] Unicode TRUE for UCS-2, FALSE for ASCII.
+
+ @return a new EFI_FILE_PROTOCOL object to be used instead of the template.
+**/
+EFI_FILE_PROTOCOL*
+CreateFileInterfaceFile(
+ IN CONST EFI_FILE_PROTOCOL *Template,
+ IN CONST BOOLEAN Unicode
+ )
+{
+ EFI_FILE_PROTOCOL_FILE *NewOne;
+
+ NewOne = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_FILE));
+ if (NewOne == NULL) {
+ return (NULL);
+ }
+ CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE));
+ NewOne->Orig = (EFI_FILE_PROTOCOL *)Template;
+ NewOne->Unicode = Unicode;
+ NewOne->Open = FileInterfaceFileOpen;
+ NewOne->Close = FileInterfaceFileClose;
+ NewOne->Delete = FileInterfaceFileDelete;
+ NewOne->Read = FileInterfaceFileRead;
+ NewOne->Write = FileInterfaceFileWrite;
+ NewOne->GetPosition = FileInterfaceFileGetPosition;
+ NewOne->SetPosition = FileInterfaceFileSetPosition;
+ NewOne->GetInfo = FileInterfaceFileGetInfo;
+ NewOne->SetInfo = FileInterfaceFileSetInfo;
+ NewOne->Flush = FileInterfaceFileFlush;
+
+ return ((EFI_FILE_PROTOCOL *)NewOne);
+}