Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Dandan Bi <dandan.bi@intel.com> Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
		
			
				
	
	
		
			1974 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1974 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables,
 | |
|   StdIn, StdOut, StdErr, etc...).
 | |
| 
 | |
|   Copyright 2016 Dell Inc.
 | |
|   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
 | |
|   (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #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 minimun 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)) {
 | |
|         //
 | |
|         // Calulate 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 sytle 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;
 | |
| 
 | |
|   //
 | |
|   // 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;
 | |
| 
 | |
|   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) {
 | |
|     NewBuffer = AllocateZeroPool(NewSize + sizeof(CHAR16));
 | |
|     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 (StrSize(NewBuffer) > 6)
 | |
|     {
 | |
|       if ((((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 2] == CHAR_LINEFEED) 
 | |
|            && (((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] == CHAR_CARRIAGE_RETURN)) {
 | |
|         ((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] = CHAR_NULL;   
 | |
|       }
 | |
| 
 | |
|       if (Volatile) {
 | |
|         Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);
 | |
|       } else {
 | |
|         Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);
 | |
|       }
 | |
|     }
 | |
|   } 
 | |
|   
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   return (SHELL_GET_ENVIRONMENT_VARIABLE(
 | |
|     ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
 | |
|     BufferSize,
 | |
|     Buffer));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   File style interface for Volatile Environment Variable (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_SUCCESS   The data was read.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| FileInterfaceEnvVolWrite(
 | |
|   IN EFI_FILE_PROTOCOL *This,
 | |
|   IN OUT UINTN *BufferSize,
 | |
|   IN VOID *Buffer
 | |
|   )
 | |
| {
 | |
|   VOID*       NewBuffer;
 | |
|   UINTN       NewSize;
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   NewBuffer   = NULL;
 | |
|   NewSize     = 0;
 | |
| 
 | |
|   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL){
 | |
|     NewBuffer = AllocateZeroPool(NewSize + *BufferSize + sizeof(CHAR16));
 | |
|     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
 | |
|   }
 | |
|   if (!EFI_ERROR(Status) && NewBuffer != NULL) {
 | |
|     while (((CHAR16*)NewBuffer)[NewSize/2] == CHAR_NULL) {
 | |
|       //
 | |
|       // We want to overwrite the CHAR_NULL
 | |
|       //
 | |
|       NewSize -= 2;
 | |
|     }
 | |
|     CopyMem((UINT8*)NewBuffer + NewSize + 2, Buffer, *BufferSize);
 | |
|     Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);
 | |
|     FreePool(NewBuffer);
 | |
|     return (Status);
 | |
|   } else {
 | |
|     SHELL_FREE_NON_NULL(NewBuffer);
 | |
|     return (SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, *BufferSize, Buffer));
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   File style interface for Non Volatile Environment Variable (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_SUCCESS   The data was read.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| FileInterfaceEnvNonVolWrite(
 | |
|   IN EFI_FILE_PROTOCOL *This,
 | |
|   IN OUT UINTN *BufferSize,
 | |
|   IN VOID *Buffer
 | |
|   )
 | |
| {
 | |
|   VOID*       NewBuffer;
 | |
|   UINTN       NewSize;
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   NewBuffer   = NULL;
 | |
|   NewSize     = 0;
 | |
| 
 | |
|   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL){
 | |
|     NewBuffer = AllocateZeroPool(NewSize + *BufferSize);
 | |
|     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
 | |
|   }
 | |
|   if (!EFI_ERROR(Status)) {
 | |
|     CopyMem((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);
 | |
|     return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(
 | |
|     ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
 | |
|     NewSize + *BufferSize,
 | |
|     NewBuffer));
 | |
|   } else {
 | |
|     return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(
 | |
|     ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
 | |
|     *BufferSize,
 | |
|     Buffer));
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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 (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);
 | |
|       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);
 | |
|       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     = FileInterfaceNopGetInfo;
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   CHAR8       *AsciiStrBuffer;
 | |
|   CHAR16      *UscStrBuffer;
 | |
|   UINTN       Size;
 | |
|   UINTN       CharNum;
 | |
|   EFI_STATUS  Status;
 | |
|   if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {
 | |
|     //
 | |
|     // Unicode
 | |
|     //
 | |
|     return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));
 | |
|   } else {
 | |
|     //
 | |
|     // Ascii
 | |
|     //
 | |
|     Size  = (*BufferSize) / sizeof(CHAR16);
 | |
|     AsciiStrBuffer = AllocateZeroPool(Size + sizeof(CHAR8));
 | |
|     if (AsciiStrBuffer == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     UscStrBuffer = AllocateZeroPool(*BufferSize + 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)) {
 | |
|       CharNum = UnicodeSPrint(UscStrBuffer, *BufferSize + sizeof(CHAR16), L"%a", AsciiStrBuffer);
 | |
|       if (CharNum == Size) {
 | |
|         CopyMem (Buffer, UscStrBuffer, *BufferSize);
 | |
|       } else {
 | |
|         Status = EFI_UNSUPPORTED;
 | |
|       }
 | |
|     }
 | |
|     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);
 | |
| }
 |