add Edit and HexEdit commands.
authorjcarsey <jcarsey@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 25 Mar 2011 21:15:07 +0000 (21:15 +0000)
committerjcarsey <jcarsey@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 25 Mar 2011 21:15:07 +0000 (21:15 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11436 6f19259b-4bc3-4df7-8a09-765794883524

28 files changed:
ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEdit.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditor.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditorTypes.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexeditStrings.uni [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.h [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.c [new file with mode: 0644]
ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.h [new file with mode: 0644]

diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c
new file mode 100644 (file)
index 0000000..c4dbf80
--- /dev/null
@@ -0,0 +1,158 @@
+/** @file\r
+  Main file for Edit shell Debug1 function.\r
+\r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UefiShellDebug1CommandsLib.h"\r
+#include "TextEditor.h"\r
+\r
+/**\r
+  Function for 'edit' command.\r
+\r
+  @param[in] ImageHandle  Handle to the Image (NULL if Internal).\r
+  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).\r
+**/\r
+SHELL_STATUS\r
+EFIAPI\r
+ShellCommandRunEdit (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  CHAR16              *Buffer;\r
+  CHAR16              *ProblemParam;\r
+  SHELL_STATUS        ShellStatus;\r
+  LIST_ENTRY          *Package;\r
+  CONST CHAR16        *Cwd;\r
+  CHAR16              *Nfs;\r
+  CHAR16              *Spot;\r
+//  SHELL_FILE_HANDLE   TempHandle;\r
+\r
+  Buffer      = NULL;\r
+  ShellStatus = SHELL_SUCCESS;\r
+  Nfs         = NULL;\r
+\r
+  //\r
+  // initialize the shell lib (we must be in non-auto-init...)\r
+  //\r
+  Status = ShellInitialize();\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  Status = CommandInit();\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  //\r
+  // parse the command line\r
+  //\r
+  Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);\r
+  if (EFI_ERROR(Status)) {\r
+    if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, ProblemParam);\r
+      FreePool(ProblemParam);\r
+      ShellStatus = SHELL_INVALID_PARAMETER;\r
+    } else {\r
+      ASSERT(FALSE);\r
+    }\r
+  } else {\r
+    if (ShellCommandLineGetCount(Package) > 2) {\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle);\r
+      ShellStatus = SHELL_INVALID_PARAMETER;\r
+    } else {\r
+      Cwd = gEfiShellProtocol->GetCurDir(NULL);\r
+      if (Cwd == NULL) {\r
+        Cwd = ShellGetEnvironmentVariable(L"path");\r
+        if (Cwd != NULL) {\r
+          Nfs = StrnCatGrow(&Nfs, NULL, Cwd+3, 0);\r
+          if (Nfs != NULL) {\r
+            Spot = StrStr(Nfs, L";");\r
+            if (Spot != NULL) {\r
+              *Spot = CHAR_NULL;\r
+            }\r
+            Spot = StrStr(Nfs, L"\\");\r
+            if (Spot != NULL) {\r
+              Spot[1] = CHAR_NULL;\r
+            }\r
+            gEfiShellProtocol->SetCurDir(NULL, Nfs);\r
+            FreePool(Nfs);\r
+          } \r
+        }\r
+      }\r
+\r
+      Status = MainEditorInit ();\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        gST->ConOut->ClearScreen (gST->ConOut);\r
+        gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_INIT_FAILED), gShellDebug1HiiHandle);\r
+      } else {\r
+        MainEditorBackup ();\r
+\r
+        //\r
+        // if editor launched with file named\r
+        //\r
+        if (ShellCommandLineGetCount(Package) == 2) {\r
+          FileBufferSetFileName (ShellCommandLineGetRawValue(Package, 1));\r
+//          if (EFI_ERROR(ShellFileExists(MainEditor.FileBuffer->FileName))) {\r
+//            Status = ShellOpenFileByName(MainEditor.FileBuffer->FileName, &TempHandle, EFI_FILE_MODE_CREATE|EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);\r
+//            if (!EFI_ERROR(Status)) {\r
+//              ShellCloseFile(&TempHandle);\r
+//            }\r
+//          }\r
+        }\r
+\r
+        Status = FileBufferRead (MainEditor.FileBuffer->FileName, FALSE);\r
+        if (!EFI_ERROR (Status)) {\r
+          MainEditorRefresh ();\r
+\r
+          Status = MainEditorKeyInput ();\r
+        }\r
+\r
+        if (Status != EFI_OUT_OF_RESOURCES) {\r
+          //\r
+          // back up the status string\r
+          //\r
+          Buffer = CatSPrint (NULL, L"%s", StatusBarGetString());\r
+        }\r
+\r
+        MainEditorCleanup ();\r
+\r
+        //\r
+        // print editor exit code on screen\r
+        //\r
+        if (Status == EFI_SUCCESS) {\r
+        } else if (Status == EFI_OUT_OF_RESOURCES) {\r
+          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_GEN_OUT_MEM), gShellDebug1HiiHandle);\r
+        } else {\r
+          if (Buffer != NULL) {\r
+            if (StrCmp (Buffer, L"") != 0) {\r
+              //\r
+              // print out the status string\r
+              //\r
+              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_BUFFER), gShellDebug1HiiHandle, Buffer);\r
+            } else {\r
+              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_UNKNOWN_EDITOR_ERR), gShellDebug1HiiHandle);\r
+            }\r
+          } else {\r
+            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_UNKNOWN_EDITOR_ERR), gShellDebug1HiiHandle);\r
+          }\r
+        }\r
+\r
+        if (Status != EFI_OUT_OF_RESOURCES) {\r
+          SHELL_FREE_NON_NULL (Buffer);\r
+        }\r
+      }\r
+    }\r
+    ShellCommandLineFreeVarList (Package);\r
+  }\r
+  return ShellStatus;\r
+}\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c
new file mode 100644 (file)
index 0000000..5843c78
--- /dev/null
@@ -0,0 +1,3353 @@
+/** @file\r
+  Implements filebuffer interface functions.\r
+\r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TextEditor.h"\r
+#include <Guid/FileSystemInfo.h>\r
+#include <Library/FileHandleLib.h>\r
+\r
+EFI_EDITOR_FILE_BUFFER  FileBuffer;\r
+EFI_EDITOR_FILE_BUFFER  FileBufferBackupVar;\r
+\r
+//\r
+// for basic initialization of FileBuffer\r
+//\r
+EFI_EDITOR_FILE_BUFFER  FileBufferConst = {\r
+  NULL,\r
+  FileTypeUnicode,\r
+  NULL,\r
+  NULL,\r
+  0,\r
+  {\r
+    0,\r
+    0\r
+  },\r
+  {\r
+    0,\r
+    0\r
+  },\r
+  {\r
+    0,\r
+    0\r
+  },\r
+  {\r
+    0,\r
+    0\r
+  },\r
+  FALSE,\r
+  TRUE,\r
+  FALSE,\r
+  NULL\r
+};\r
+\r
+//\r
+// the whole edit area needs to be refreshed\r
+//\r
+STATIC BOOLEAN          FileBufferNeedRefresh;\r
+\r
+//\r
+// only the current line in edit area needs to be refresh\r
+//\r
+BOOLEAN                 FileBufferOnlyLineNeedRefresh;\r
+\r
+BOOLEAN                 FileBufferMouseNeedRefresh;\r
+\r
+extern BOOLEAN          EditorMouseAction;\r
+\r
+/**\r
+  Initialization function for FileBuffer.\r
+\r
+  @param EFI_SUCCESS            The initialization was successful.\r
+  @param EFI_LOAD_ERROR         A default name could not be created.\r
+  @param EFI_OUT_OF_RESOURCES   A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferInit (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // basically initialize the FileBuffer\r
+  //\r
+  CopyMem (&FileBuffer         , &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER));\r
+  CopyMem (&FileBufferBackupVar, &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER));\r
+\r
+  //\r
+  // set default FileName\r
+  //\r
+  FileBuffer.FileName = EditGetDefaultFileName (L"txt");\r
+  if (FileBuffer.FileName == NULL) {\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  FileBuffer.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY));\r
+  if (FileBuffer.ListHead == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  InitializeListHead (FileBuffer.ListHead);\r
+\r
+  FileBuffer.DisplayPosition.Row    = 2;\r
+  FileBuffer.DisplayPosition.Column = 1;\r
+  FileBuffer.LowVisibleRange.Row    = 2;\r
+  FileBuffer.LowVisibleRange.Column = 1;\r
+\r
+  FileBufferNeedRefresh             = FALSE;\r
+  FileBufferMouseNeedRefresh        = FALSE;\r
+  FileBufferOnlyLineNeedRefresh     = FALSE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Backup function for FileBuffer.  Only backup the following items:\r
+      Mouse/Cursor position\r
+      File Name, Type, ReadOnly, Modified\r
+      Insert Mode\r
+\r
+  This is for making the file buffer refresh as few as possible.\r
+\r
+  @retval EFI_SUCCESS           The backup operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferBackup (\r
+  VOID\r
+  )\r
+{\r
+  FileBufferBackupVar.MousePosition = FileBuffer.MousePosition;\r
+\r
+  SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName);\r
+  FileBufferBackupVar.FileName        = NULL;\r
+  FileBufferBackupVar.FileName        = StrnCatGrow (&FileBufferBackupVar.FileName, NULL, FileBuffer.FileName, 0);\r
+\r
+  FileBufferBackupVar.ModeInsert      = FileBuffer.ModeInsert;\r
+  FileBufferBackupVar.FileType        = FileBuffer.FileType;\r
+\r
+  FileBufferBackupVar.FilePosition    = FileBuffer.FilePosition;\r
+  FileBufferBackupVar.LowVisibleRange = FileBuffer.LowVisibleRange;\r
+\r
+  FileBufferBackupVar.FileModified    = FileBuffer.FileModified;\r
+  FileBufferBackupVar.ReadOnly        = FileBuffer.ReadOnly;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Advance to the next Count lines\r
+  \r
+  @param[in] Count              The line number to advance by.\r
+  @param[in] CurrentLine        The pointer to the current line structure.\r
+  @param[in] LineList           The pointer to the linked list of lines.\r
+\r
+  @retval NULL                  There was an error.\r
+  @return  The line structure after the advance.\r
+**/\r
+EFI_EDITOR_LINE *\r
+EFIAPI\r
+InternalEditorMiscLineAdvance (\r
+  IN CONST UINTN            Count,\r
+  IN CONST EFI_EDITOR_LINE  *CurrentLine,\r
+  IN CONST LIST_ENTRY       *LineList\r
+  )\r
+\r
+{\r
+  UINTN                 Index;\r
+  CONST EFI_EDITOR_LINE *Line;\r
+\r
+  if (CurrentLine == NULL || LineList == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  for (Line = CurrentLine, Index = 0; Index < Count; Index++) {\r
+    //\r
+    // if already last line\r
+    //\r
+    if (Line->Link.ForwardLink == LineList) {\r
+      return NULL;\r
+    }\r
+\r
+    Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+  }\r
+\r
+  return ((EFI_EDITOR_LINE *)Line);\r
+}\r
+\r
+/**\r
+  Retreat to the previous Count lines.\r
+  \r
+  @param[in] Count              The line number to retreat by.\r
+  @param[in] CurrentLine        The pointer to the current line structure.\r
+  @param[in] LineList           The pointer to the linked list of lines.\r
+\r
+  @retval NULL                  There was an error.\r
+  @return  The line structure after the retreat.\r
+**/\r
+EFI_EDITOR_LINE *\r
+EFIAPI\r
+InternalEditorMiscLineRetreat (\r
+  IN CONST UINTN            Count,\r
+  IN CONST EFI_EDITOR_LINE  *CurrentLine,\r
+  IN CONST LIST_ENTRY       *LineList\r
+  )\r
+\r
+{\r
+  UINTN                 Index;\r
+  CONST EFI_EDITOR_LINE *Line;\r
+\r
+  if (CurrentLine == NULL || LineList == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  for (Line = CurrentLine, Index = 0; Index < Count; Index++) {\r
+    //\r
+    // already the first line\r
+    //\r
+    if (Line->Link.BackLink == LineList) {\r
+      return NULL;\r
+    }\r
+\r
+    Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+  }\r
+\r
+  return ((EFI_EDITOR_LINE *)Line);\r
+}\r
+\r
+/**\r
+  Advance/Retreat lines\r
+  \r
+  @param[in] Count  line number to advance/retreat\r
+                       >0 : advance\r
+                       <0 : retreat\r
+\r
+  @retval NULL An error occured.\r
+  @return The line after advance/retreat.\r
+**/\r
+EFI_EDITOR_LINE *\r
+MoveLine (\r
+  IN CONST INTN Count\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           AbsCount;\r
+\r
+  //\r
+  // if < 0, then retreat\r
+  // if > 0, the advance\r
+  //\r
+  if (Count <= 0) {\r
+    AbsCount  = -Count;\r
+    Line      = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);\r
+  } else {\r
+    Line = InternalEditorMiscLineAdvance (Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);\r
+  }\r
+\r
+  return Line;\r
+}\r
+\r
+/**\r
+  Function to update the 'screen' to display the mouse position.\r
+\r
+  @retval EFI_SUCCESS           The backup operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferRestoreMousePosition (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_COLOR_UNION  Orig;\r
+  EFI_EDITOR_COLOR_UNION  New;\r
+  UINTN                   FRow;\r
+  UINTN                   FColumn;\r
+  BOOLEAN                 HasCharacter;\r
+  EFI_EDITOR_LINE         *CurrentLine;\r
+  EFI_EDITOR_LINE         *Line;\r
+  CHAR16                  Value;\r
+\r
+  //\r
+  // variable initialization\r
+  //\r
+  Line = NULL;\r
+\r
+  if (MainEditor.MouseSupported) {\r
+\r
+    if (FileBufferMouseNeedRefresh) {\r
+\r
+      FileBufferMouseNeedRefresh = FALSE;\r
+\r
+      //\r
+      // if mouse position not moved and only mouse action\r
+      // so do not need to refresh mouse position\r
+      //\r
+      if ((FileBuffer.MousePosition.Row == FileBufferBackupVar.MousePosition.Row &&\r
+          FileBuffer.MousePosition.Column == FileBufferBackupVar.MousePosition.Column)\r
+          && EditorMouseAction) {\r
+        return EFI_SUCCESS;\r
+      }\r
+      //\r
+      // backup the old screen attributes\r
+      //\r
+      Orig                  = MainEditor.ColorAttributes;\r
+      New.Colors.Foreground = Orig.Colors.Background;\r
+      New.Colors.Background = Orig.Colors.Foreground;\r
+\r
+      //\r
+      // clear the old mouse position\r
+      //\r
+      FRow          = FileBuffer.LowVisibleRange.Row + FileBufferBackupVar.MousePosition.Row - 2;\r
+\r
+      FColumn       = FileBuffer.LowVisibleRange.Column + FileBufferBackupVar.MousePosition.Column - 1;\r
+\r
+      HasCharacter  = TRUE;\r
+      if (FRow > FileBuffer.NumLines) {\r
+        HasCharacter = FALSE;\r
+      } else {\r
+        CurrentLine = FileBuffer.CurrentLine;\r
+        Line        = MoveLine (FRow - FileBuffer.FilePosition.Row);\r
+\r
+        if (FColumn > Line->Size) {\r
+          HasCharacter = FALSE;\r
+        }\r
+\r
+        FileBuffer.CurrentLine = CurrentLine;\r
+      }\r
+\r
+      ShellPrintEx (\r
+        (INT32)FileBufferBackupVar.MousePosition.Column - 1,\r
+        (INT32)FileBufferBackupVar.MousePosition.Row - 1,\r
+        L" "\r
+        );\r
+\r
+      if (HasCharacter) {\r
+        Value = (Line->Buffer[FColumn - 1]);\r
+        ShellPrintEx (\r
+          (INT32)FileBufferBackupVar.MousePosition.Column - 1,\r
+          (INT32)FileBufferBackupVar.MousePosition.Row - 1,\r
+          L"%c",\r
+          Value\r
+          );\r
+      }\r
+      //\r
+      // set the new mouse position\r
+      //\r
+      gST->ConOut->SetAttribute (gST->ConOut, New.Data);\r
+\r
+      //\r
+      // clear the old mouse position\r
+      //\r
+      FRow          = FileBuffer.LowVisibleRange.Row + FileBuffer.MousePosition.Row - 2;\r
+      FColumn       = FileBuffer.LowVisibleRange.Column + FileBuffer.MousePosition.Column - 1;\r
+\r
+      HasCharacter  = TRUE;\r
+      if (FRow > FileBuffer.NumLines) {\r
+        HasCharacter = FALSE;\r
+      } else {\r
+        CurrentLine = FileBuffer.CurrentLine;\r
+        Line        = MoveLine (FRow - FileBuffer.FilePosition.Row);\r
+\r
+        if (FColumn > Line->Size) {\r
+          HasCharacter = FALSE;\r
+        }\r
+\r
+        FileBuffer.CurrentLine = CurrentLine;\r
+      }\r
+\r
+      ShellPrintEx (\r
+        (INT32)FileBuffer.MousePosition.Column - 1,\r
+        (INT32)FileBuffer.MousePosition.Row - 1,\r
+        L" "\r
+        );\r
+\r
+      if (HasCharacter) {\r
+        Value = Line->Buffer[FColumn - 1];\r
+        ShellPrintEx (\r
+          (INT32)FileBuffer.MousePosition.Column - 1,\r
+          (INT32)FileBuffer.MousePosition.Row - 1,\r
+          L"%c",\r
+          Value\r
+          );\r
+      }\r
+      //\r
+      // end of HasCharacter\r
+      //\r
+      gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);\r
+    }\r
+    //\r
+    // end of MouseNeedRefresh\r
+    //\r
+  }\r
+  //\r
+  // end of MouseSupported\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Free all the lines in FileBuffer\r
+   Fields affected:\r
+     Lines\r
+     CurrentLine\r
+     NumLines\r
+     ListHead\r
+\r
+  @retval EFI_SUCCESS     The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferFreeLines (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY  *Link;\r
+  EFI_EDITOR_LINE *Line;\r
+\r
+  //\r
+  // free all the lines\r
+  //\r
+  if (FileBuffer.Lines != NULL) {\r
+\r
+    Line  = FileBuffer.Lines;\r
+    Link  = &(Line->Link);\r
+    do {\r
+      Line  = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+      Link  = Link->ForwardLink;\r
+\r
+      //\r
+      // free line's buffer and line itself\r
+      //\r
+      LineFree (Line);\r
+    } while (Link != FileBuffer.ListHead);\r
+  }\r
+  //\r
+  // clean the line list related structure\r
+  //\r
+  FileBuffer.Lines            = NULL;\r
+  FileBuffer.CurrentLine      = NULL;\r
+  FileBuffer.NumLines         = 0;\r
+\r
+  FileBuffer.ListHead->ForwardLink  = FileBuffer.ListHead;\r
+  FileBuffer.ListHead->BackLink  = FileBuffer.ListHead;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Cleanup function for FileBuffer.\r
+\r
+  @retval EFI_SUCCESS   The cleanup was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferCleanup (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  SHELL_FREE_NON_NULL (FileBuffer.FileName);\r
+\r
+  //\r
+  // free all the lines\r
+  //\r
+  Status = FileBufferFreeLines ();\r
+\r
+  SHELL_FREE_NON_NULL (FileBuffer.ListHead);\r
+  FileBuffer.ListHead = NULL;\r
+\r
+  SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName);\r
+  return Status;\r
+\r
+}\r
+\r
+/**\r
+  Print a line specified by Line on a row specified by Row of the screen.\r
+\r
+  @param[in] Line               The line to print.\r
+  @param[in] Row                The row on the screen to print onto (begin from 1).\r
+\r
+  @retval EFI_SUCCESS           The printing was successful.\r
+**/\r
+EFI_STATUS\r
+FileBufferPrintLine (\r
+  IN CONST EFI_EDITOR_LINE  *Line,\r
+  IN CONST UINTN            Row\r
+  )\r
+{\r
+\r
+  CHAR16  *Buffer;\r
+  UINTN   Limit;\r
+  CHAR16  PrintLine[200];\r
+\r
+  //\r
+  // print start from correct character\r
+  //\r
+  Buffer  = Line->Buffer + FileBuffer.LowVisibleRange.Column - 1;\r
+\r
+  Limit   = Line->Size - FileBuffer.LowVisibleRange.Column + 1;\r
+  if (Limit > Line->Size) {\r
+    Limit = 0;\r
+  }\r
+\r
+  StrnCpy (PrintLine, Buffer, Limit > MainEditor.ScreenSize.Column ? MainEditor.ScreenSize.Column : Limit);\r
+  for (; Limit < MainEditor.ScreenSize.Column; Limit++) {\r
+    PrintLine[Limit] = L' ';\r
+  }\r
+\r
+  PrintLine[MainEditor.ScreenSize.Column] = CHAR_NULL;\r
+\r
+  ShellPrintEx (\r
+    0,\r
+    (INT32)Row - 1,\r
+    L"%s",\r
+    PrintLine\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set the cursor position according to FileBuffer.DisplayPosition.\r
+\r
+  @retval EFI_SUCCESS           The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferRestorePosition (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // set cursor position\r
+  //\r
+  return (gST->ConOut->SetCursorPosition (\r
+        gST->ConOut,\r
+        FileBuffer.DisplayPosition.Column - 1,\r
+        FileBuffer.DisplayPosition.Row - 1\r
+        ));\r
+}\r
+\r
+/**\r
+  Refresh the screen with whats in the buffer.\r
+\r
+  @retval EFI_SUCCESS     The refresh was successful.\r
+  @retval EFI_LOAD_ERROR  There was an error finding what to write.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferRefresh (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY  *Link;\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           Row;\r
+\r
+  //\r
+  // if it's the first time after editor launch, so should refresh\r
+  //\r
+  if (!EditorFirst) {\r
+    //\r
+    // no definite required refresh\r
+    // and file position displayed on screen has not been changed\r
+    //\r
+    if (!FileBufferNeedRefresh &&\r
+        !FileBufferOnlyLineNeedRefresh &&\r
+        FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row &&\r
+        FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column\r
+        ) {\r
+\r
+      FileBufferRestoreMousePosition ();\r
+      FileBufferRestorePosition ();\r
+\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+\r
+  //\r
+  // only need to refresh current line\r
+  //\r
+  if (FileBufferOnlyLineNeedRefresh &&\r
+      FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row &&\r
+      FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column\r
+      ) {\r
+\r
+    EditorClearLine (FileBuffer.DisplayPosition.Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);\r
+    FileBufferPrintLine (\r
+      FileBuffer.CurrentLine,\r
+      FileBuffer.DisplayPosition.Row\r
+      );\r
+  } else {\r
+    //\r
+    // the whole edit area need refresh\r
+    //\r
+\r
+    //\r
+    // no line\r
+    //\r
+    if (FileBuffer.Lines == NULL) {\r
+      FileBufferRestoreMousePosition ();\r
+      FileBufferRestorePosition ();\r
+      gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // get the first line that will be displayed\r
+    //\r
+    Line = MoveLine (FileBuffer.LowVisibleRange.Row - FileBuffer.FilePosition.Row);\r
+    if (Line == NULL) {\r
+      gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+\r
+    Link  = &(Line->Link);\r
+    Row   = 2;\r
+    do {\r
+      Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+\r
+      //\r
+      // print line at row\r
+      //\r
+      FileBufferPrintLine (Line, Row);\r
+\r
+      Link = Link->ForwardLink;\r
+      Row++;\r
+    } while (Link != FileBuffer.ListHead && Row <= (MainEditor.ScreenSize.Row - 4));\r
+    //\r
+    // while not file end and not screen full\r
+    //\r
+    while (Row <= (MainEditor.ScreenSize.Row - 4)) {\r
+      EditorClearLine (Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);\r
+      Row++;\r
+    }\r
+  }\r
+\r
+  FileBufferRestoreMousePosition ();\r
+  FileBufferRestorePosition ();\r
+\r
+  FileBufferNeedRefresh         = FALSE;\r
+  FileBufferOnlyLineNeedRefresh = FALSE;\r
+\r
+  gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create a new line and append it to the line list.\r
+    Fields affected:\r
+      NumLines\r
+      Lines\r
+\r
+  @retval NULL    The create line failed.\r
+  @return         The line created.\r
+**/\r
+EFI_EDITOR_LINE *\r
+EFIAPI\r
+FileBufferCreateLine (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+\r
+  //\r
+  // allocate a line structure\r
+  //\r
+  Line = AllocateZeroPool (sizeof (EFI_EDITOR_LINE));\r
+  if (Line == NULL) {\r
+    return NULL;\r
+  }\r
+  //\r
+  // initialize the structure\r
+  //\r
+  Line->Signature = LINE_LIST_SIGNATURE;\r
+  Line->Size      = 0;\r
+  Line->TotalSize = 0;\r
+  Line->Type      = NewLineTypeDefault;\r
+\r
+  //\r
+  // initial buffer of the line is "\0"\r
+  //\r
+  ASSERT(CHAR_NULL == CHAR_NULL);\r
+  Line->Buffer = CatSPrint (NULL, L"\0");\r
+  if (Line->Buffer == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  FileBuffer.NumLines++;\r
+\r
+  //\r
+  // insert the line into line list\r
+  //\r
+  InsertTailList (FileBuffer.ListHead, &Line->Link);\r
+\r
+  if (FileBuffer.Lines == NULL) {\r
+    FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+  }\r
+\r
+  return Line;\r
+}\r
+\r
+/**\r
+  Set FileName field in FileBuffer.\r
+\r
+  @param Str                    The file name to set.\r
+  \r
+  @retval EFI_SUCCESS           The filename was successfully set.\r
+  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
+  @retval EFI_INVALID_PARAMETER Str is not a valid filename.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferSetFileName (\r
+  IN CONST CHAR16 *Str\r
+  )\r
+{\r
+  //\r
+  // Verify the parameters\r
+  //\r
+  if (!IsValidFileName(Str)) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+  //\r
+  // free the old file name\r
+  //\r
+  SHELL_FREE_NON_NULL (FileBuffer.FileName);\r
+\r
+  //\r
+  // Allocate and set the new name\r
+  //\r
+  FileBuffer.FileName = CatSPrint (NULL, L"%s", Str);\r
+  if (FileBuffer.FileName == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+/**\r
+  Free the existing file lines and reset the modified flag.\r
+\r
+  @retval EFI_SUCCESS           The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferFree (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // free all the lines\r
+  //\r
+  FileBufferFreeLines ();\r
+  FileBuffer.FileModified = FALSE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Read a file from disk into the FileBuffer.\r
+  \r
+  @param[in] FileName           The filename to read.\r
+  @param[in] Recover            TRUE if is for recover mode, no information printouts.\r
+  \r
+  @retval EFI_SUCCESS            The load was successful.\r
+  @retval EFI_LOAD_ERROR         The load failed.\r
+  @retval EFI_OUT_OF_RESOURCES   A memory allocation failed.\r
+  @retval EFI_INVALID_PARAMETER  FileName is a directory.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferRead (\r
+  IN CONST CHAR16  *FileName,\r
+  IN CONST BOOLEAN Recover\r
+  )\r
+{\r
+  EFI_EDITOR_LINE                 *Line;\r
+  EE_NEWLINE_TYPE                 Type;\r
+  UINTN                           LoopVar1;\r
+  UINTN                           LoopVar2;\r
+  UINTN                           LineSize;\r
+  VOID                            *Buffer;\r
+  CHAR16                          *UnicodeBuffer;\r
+  UINT8                           *AsciiBuffer;\r
+  UINTN                           FileSize;\r
+  SHELL_FILE_HANDLE               FileHandle;\r
+  BOOLEAN                         CreateFile;\r
+  EFI_STATUS                      Status;\r
+  UINTN                           LineSizeBackup;\r
+  EFI_FILE_INFO                   *Info;\r
+\r
+  Line          = NULL;\r
+  LoopVar1      = 0;\r
+  FileSize      = 0;\r
+  UnicodeBuffer = NULL;\r
+  Type          = NewLineTypeDefault;\r
+  FileHandle    = NULL;\r
+  CreateFile    = FALSE;\r
+\r
+  //\r
+  // in this function, when you return error ( except EFI_OUT_OF_RESOURCES )\r
+  // you should set status string via StatusBarSetStatusString(L"blah")\r
+  // since this function maybe called before the editorhandleinput loop\r
+  // so any error will cause editor return\r
+  // so if you want to print the error status\r
+  // you should set the status string\r
+  //\r
+\r
+  //\r
+  // try to open the file\r
+  //\r
+  Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0);\r
+\r
+  if (!EFI_ERROR(Status)) {\r
+    CreateFile = FALSE;\r
+    if (FileHandle == NULL) {\r
+      StatusBarSetStatusString (L"Disk Error");\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+\r
+    Info = ShellGetFileInfo(FileHandle);\r
+    \r
+    if (Info->Attribute & EFI_FILE_DIRECTORY) {\r
+      StatusBarSetStatusString (L"Directory Can Not Be Edited");\r
+      FreePool (Info);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (Info->Attribute & EFI_FILE_READ_ONLY) {\r
+      FileBuffer.ReadOnly = TRUE;\r
+    } else {\r
+      FileBuffer.ReadOnly = FALSE;\r
+    }\r
+    //\r
+    // get file size\r
+    //\r
+    FileSize = (UINTN) Info->FileSize;\r
+\r
+    FreePool (Info);\r
+  } else if (Status == EFI_NOT_FOUND) {\r
+    //\r
+    // file not exists.  add create and try again\r
+    //\r
+    Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);\r
+    if (EFI_ERROR (Status)) {\r
+      if (Status == EFI_WRITE_PROTECTED ||\r
+          Status == EFI_ACCESS_DENIED ||\r
+          Status == EFI_NO_MEDIA ||\r
+          Status == EFI_MEDIA_CHANGED\r
+          ) {\r
+        StatusBarSetStatusString (L"Access Denied");\r
+      } else if (Status == EFI_DEVICE_ERROR || Status == EFI_VOLUME_CORRUPTED || Status == EFI_VOLUME_FULL) {\r
+        StatusBarSetStatusString (L"Disk Error");\r
+      } else {\r
+        StatusBarSetStatusString (L"Invalid File Name or Current-working-directory");\r
+      }\r
+\r
+      return Status;\r
+    } else {\r
+      //\r
+      // it worked.  now delete it and move on with the name (now validated)\r
+      //\r
+      Status = ShellDeleteFile (&FileHandle);\r
+      if (Status == EFI_WARN_DELETE_FAILURE) {\r
+        Status = EFI_ACCESS_DENIED;\r
+      }\r
+      FileHandle = NULL;\r
+      if (EFI_ERROR (Status)) {\r
+        StatusBarSetStatusString (L"Access Denied");\r
+        return Status;\r
+      }\r
+    }\r
+    //\r
+    // file doesn't exist, so set CreateFile to TRUE\r
+    //\r
+    CreateFile          = TRUE;\r
+    FileBuffer.ReadOnly = FALSE;\r
+\r
+    //\r
+    // all the check ends\r
+    // so now begin to set file name, free lines\r
+    //\r
+    if (StrCmp (FileName, FileBuffer.FileName) != 0) {\r
+      FileBufferSetFileName (FileName);\r
+    }\r
+    //\r
+    // free the old lines\r
+    //\r
+    FileBufferFree ();\r
+\r
+  }\r
+  //\r
+  // the file exists\r
+  //\r
+  if (!CreateFile) {\r
+    //\r
+    // allocate buffer to read file\r
+    //\r
+    Buffer = AllocateZeroPool (FileSize);\r
+    if (Buffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // read file into Buffer\r
+    //\r
+    Status = ShellReadFile (FileHandle, &FileSize, Buffer);\r
+    ShellCloseFile(&FileHandle);\r
+    FileHandle = NULL;\r
+    if (EFI_ERROR (Status)) {\r
+      StatusBarSetStatusString (L"Read File Failed");\r
+      SHELL_FREE_NON_NULL (Buffer);\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+    //\r
+    // nothing in this file\r
+    //\r
+    if (FileSize == 0) {\r
+      SHELL_FREE_NON_NULL (Buffer);\r
+      //\r
+      // since has no head, so only can be an ASCII file\r
+      //\r
+      FileBuffer.FileType = FileTypeAscii;\r
+\r
+      goto Done;\r
+    }\r
+\r
+    AsciiBuffer = Buffer;\r
+\r
+    if (FileSize < 2) {\r
+      //\r
+      // size < Unicode file header, so only can be ASCII file\r
+      //\r
+      FileBuffer.FileType = FileTypeAscii;\r
+    } else {\r
+      //\r
+      // Unicode file\r
+      //\r
+      if (*(UINT16 *) Buffer == EFI_UNICODE_BYTE_ORDER_MARK) {\r
+        //\r
+        // Unicode file's size should be even\r
+        //\r
+        if ((FileSize % 2) != 0) {\r
+          StatusBarSetStatusString (L"File Format Wrong");\r
+          SHELL_FREE_NON_NULL (Buffer);\r
+          return EFI_LOAD_ERROR;\r
+        }\r
+\r
+        FileSize /= 2;\r
+\r
+        FileBuffer.FileType = FileTypeUnicode;\r
+        UnicodeBuffer       = Buffer;\r
+\r
+        //\r
+        // pass this 0xff and 0xfe\r
+        //\r
+        UnicodeBuffer++;\r
+        FileSize--;\r
+      } else {\r
+        FileBuffer.FileType = FileTypeAscii;\r
+      }\r
+      //\r
+      // end of AsciiBuffer ==\r
+      //\r
+    }\r
+    //\r
+    // end of FileSize < 2\r
+    // all the check ends\r
+    // so now begin to set file name, free lines\r
+    //\r
+    if (StrCmp (FileName, FileBuffer.FileName) != 0) {\r
+      FileBufferSetFileName (FileName);\r
+    }\r
+\r
+    //\r
+    // free the old lines\r
+    //\r
+    FileBufferFree ();\r
+\r
+    //\r
+    // parse file content line by line\r
+    //\r
+    for (LoopVar1 = 0; LoopVar1 < FileSize; LoopVar1++) {\r
+      Type = NewLineTypeUnknown;\r
+\r
+      for (LineSize = LoopVar1; LineSize < FileSize; LineSize++) {\r
+        if (FileBuffer.FileType == FileTypeAscii) {\r
+          if (AsciiBuffer[LineSize] == CHAR_CARRIAGE_RETURN) {\r
+            Type = NewLineTypeCarriageReturn;\r
+\r
+            //\r
+            // has LF following\r
+            //\r
+            if (LineSize < FileSize - 1) {\r
+              if (AsciiBuffer[LineSize + 1] == CHAR_LINEFEED) {\r
+                Type = NewLineTypeCarriageReturnLineFeed;\r
+              }\r
+            }\r
+\r
+            break;\r
+          } else if (AsciiBuffer[LineSize] == CHAR_LINEFEED) {\r
+            Type = NewLineTypeLineFeed;\r
+\r
+            //\r
+            // has CR following\r
+            //\r
+            if (LineSize < FileSize - 1) {\r
+              if (AsciiBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) {\r
+                Type = NewLineTypeLineFeedCarriageReturn;\r
+              }\r
+            }\r
+\r
+            break;\r
+          }\r
+        } else {\r
+          if (UnicodeBuffer[LineSize] == CHAR_CARRIAGE_RETURN) {\r
+            Type = NewLineTypeCarriageReturn;\r
+\r
+            //\r
+            // has LF following\r
+            //\r
+            if (LineSize < FileSize - 1) {\r
+              if (UnicodeBuffer[LineSize + 1] == CHAR_LINEFEED) {\r
+                Type = NewLineTypeCarriageReturnLineFeed;\r
+              }\r
+            }\r
+\r
+            break;\r
+          } else if (UnicodeBuffer[LineSize] == CHAR_LINEFEED) {\r
+            Type = NewLineTypeLineFeed;\r
+\r
+            //\r
+            // has CR following\r
+            //\r
+            if (LineSize < FileSize - 1) {\r
+              if (UnicodeBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) {\r
+                Type = NewLineTypeLineFeedCarriageReturn;\r
+              }\r
+            }\r
+\r
+            break;\r
+          }\r
+        }\r
+        //\r
+        // endif == ASCII\r
+        //\r
+      }\r
+      //\r
+      // end of for LineSize\r
+      //\r
+      // if the type is wrong, then exit\r
+      //\r
+      if (Type == NewLineTypeUnknown) {\r
+        //\r
+        // Now if Type is NewLineTypeUnknown, it should be file end\r
+        //\r
+        Type = NewLineTypeDefault;\r
+      }\r
+\r
+      LineSizeBackup = LineSize;\r
+\r
+      //\r
+      // create a new line\r
+      //\r
+      Line = FileBufferCreateLine ();\r
+      if (Line == NULL) {\r
+        SHELL_FREE_NON_NULL (Buffer);\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      //\r
+      // calculate file length\r
+      //\r
+      LineSize -= LoopVar1;\r
+\r
+      //\r
+      // Unicode and one CHAR_NULL\r
+      //\r
+      SHELL_FREE_NON_NULL (Line->Buffer);\r
+      Line->Buffer = AllocateZeroPool (LineSize * 2 + 2);\r
+\r
+      if (Line->Buffer == NULL) {\r
+        RemoveEntryList (&Line->Link);\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      //\r
+      // copy this line to Line->Buffer\r
+      //\r
+      for (LoopVar2 = 0; LoopVar2 < LineSize; LoopVar2++) {\r
+        if (FileBuffer.FileType == FileTypeAscii) {\r
+          Line->Buffer[LoopVar2] = (CHAR16) AsciiBuffer[LoopVar1];\r
+        } else {\r
+          Line->Buffer[LoopVar2] = UnicodeBuffer[LoopVar1];\r
+        }\r
+\r
+        LoopVar1++;\r
+      }\r
+      //\r
+      // LoopVar1 now points to where CHAR_CARRIAGE_RETURN or CHAR_LINEFEED;\r
+      //\r
+      Line->Buffer[LineSize]  = 0;\r
+\r
+      Line->Size              = LineSize;\r
+      Line->TotalSize         = LineSize;\r
+      Line->Type              = Type;\r
+\r
+      if (Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) {\r
+        LoopVar1++;\r
+      }\r
+\r
+      //\r
+      // last character is a return, SO create a new line\r
+      //\r
+      if (((Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) && LineSizeBackup == FileSize - 2) ||\r
+          ((Type == NewLineTypeLineFeed || Type == NewLineTypeCarriageReturn) && LineSizeBackup == FileSize - 1)\r
+          ) {\r
+        Line = FileBufferCreateLine ();\r
+        if (Line == NULL) {\r
+          SHELL_FREE_NON_NULL (Buffer);\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+      }\r
+      //\r
+      // end of if\r
+      //\r
+    }\r
+    //\r
+    // end of LoopVar1\r
+    //\r
+    SHELL_FREE_NON_NULL (Buffer);\r
+\r
+  }\r
+  //\r
+  // end of if CreateFile\r
+  //\r
+Done:\r
+\r
+  FileBuffer.DisplayPosition.Row    = 2;\r
+  FileBuffer.DisplayPosition.Column = 1;\r
+  FileBuffer.LowVisibleRange.Row    = 1;\r
+  FileBuffer.LowVisibleRange.Column = 1;\r
+  FileBuffer.FilePosition.Row       = 1;\r
+  FileBuffer.FilePosition.Column    = 1;\r
+  FileBuffer.MousePosition.Row      = 2;\r
+  FileBuffer.MousePosition.Column   = 1;\r
+\r
+  if (!Recover) {\r
+    UnicodeBuffer = CatSPrint (NULL, L"%d Lines Read", FileBuffer.NumLines);\r
+    if (UnicodeBuffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    StatusBarSetStatusString (UnicodeBuffer);\r
+    FreePool (UnicodeBuffer);\r
+  }\r
+/*\r
+    //\r
+    // check whether we have fs?: in filename\r
+    //\r
+    LoopVar1             = 0;\r
+    FSMappingPtr  = NULL;\r
+    while (FileName[LoopVar1] != 0) {\r
+      if (FileName[LoopVar1] == L':') {\r
+        FSMappingPtr = &FileName[LoopVar1];\r
+        break;\r
+      }\r
+\r
+      LoopVar1++;\r
+    }\r
+\r
+    if (FSMappingPtr == NULL) {\r
+      CurDir = ShellGetCurrentDir (NULL);\r
+    } else {\r
+      LoopVar1 = 0;\r
+      LoopVar2 = 0;\r
+      while (FileName[LoopVar1] != 0) {\r
+        if (FileName[LoopVar1] == L':') {\r
+          break;\r
+        }\r
+\r
+        FSMapping[LoopVar2++] = FileName[LoopVar1];\r
+\r
+        LoopVar1++;\r
+      }\r
+\r
+      FSMapping[LoopVar2]  = 0;\r
+      CurDir        = ShellGetCurrentDir (FSMapping);\r
+    }\r
+\r
+    if (CurDir != NULL) {\r
+      for (LoopVar1 = 0; LoopVar1 < StrLen (CurDir) && CurDir[LoopVar1] != ':'; LoopVar1++);\r
+\r
+      CurDir[LoopVar1]   = 0;\r
+      DevicePath  = (EFI_DEVICE_PATH_PROTOCOL *) ShellGetMap (CurDir);\r
+      FreePool (CurDir);\r
+    } else {\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+\r
+    Status = LibDevicePathToInterface (\r
+              &gEfiSimpleFileSystemProtocolGuid,\r
+              DevicePath,\r
+              (VOID **) &Vol\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+\r
+    Status = Vol->OpenVolume (Vol, &RootFs);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+    //\r
+    // Get volume information of file system\r
+    //\r
+    Size        = SIZE_OF_EFI_FILE_SYSTEM_INFO + 100;\r
+    VolumeInfo  = (EFI_FILE_SYSTEM_INFO *) AllocateZeroPool (Size);\r
+    Status      = RootFs->GetInfo (RootFs, &gEfiFileSystemInfoGuid, &Size, VolumeInfo);\r
+    if (EFI_ERROR (Status)) {\r
+      RootFs->Close (RootFs);\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+\r
+    if (VolumeInfo->ReadOnly) {\r
+      StatusBarSetStatusString (L"WARNING: Volume Read Only");\r
+    }\r
+\r
+    FreePool (VolumeInfo);\r
+    RootFs->Close (RootFs);\r
+  }\r
+//\r
+*/\r
+  //\r
+  // has line\r
+  //\r
+  if (FileBuffer.Lines != 0) {\r
+    FileBuffer.CurrentLine = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+  } else {\r
+    //\r
+    // create a dummy line\r
+    //\r
+    Line = FileBufferCreateLine ();\r
+    if (Line == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    FileBuffer.CurrentLine = Line;\r
+  }\r
+\r
+  FileBuffer.FileModified       = FALSE;\r
+  FileBufferNeedRefresh         = TRUE;\r
+  FileBufferOnlyLineNeedRefresh = FALSE;\r
+  FileBufferMouseNeedRefresh    = TRUE;\r
+\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  According to FileBuffer.NewLineType & FileBuffer.FileType,\r
+  get the return buffer and size.\r
+\r
+  @param[in] Type               The type of line.\r
+  @param[out] Buffer            The buffer to fill.\r
+  @param[out] Size              The amount of the buffer used on return.\r
+**/\r
+VOID\r
+EFIAPI\r
+GetNewLine (\r
+  IN CONST EE_NEWLINE_TYPE Type,\r
+  OUT CHAR8           *Buffer,\r
+  OUT UINT8           *Size\r
+  )\r
+{\r
+  UINT8 NewLineSize;\r
+\r
+  //\r
+  // give new line buffer,\r
+  // and will judge unicode or ascii\r
+  //\r
+  NewLineSize = 0;\r
+\r
+  //\r
+  // not legal new line type\r
+  //\r
+  if (Type != NewLineTypeLineFeed && Type != NewLineTypeCarriageReturn && Type != NewLineTypeCarriageReturnLineFeed && Type != NewLineTypeLineFeedCarriageReturn) {\r
+    *Size = 0;\r
+    return ;\r
+  }\r
+  //\r
+  // use_cr: give 0x0d\r
+  //\r
+  if (Type == NewLineTypeCarriageReturn) {\r
+    if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {\r
+      Buffer[0]   = 0x0d;\r
+      Buffer[1]   = 0;\r
+      NewLineSize = 2;\r
+    } else {\r
+      Buffer[0]   = 0x0d;\r
+      NewLineSize = 1;\r
+    }\r
+\r
+    *Size = NewLineSize;\r
+    return ;\r
+  }\r
+  //\r
+  // use_lf: give 0x0a\r
+  //\r
+  if (Type == NewLineTypeLineFeed) {\r
+    if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {\r
+      Buffer[0]   = 0x0a;\r
+      Buffer[1]   = 0;\r
+      NewLineSize = 2;\r
+    } else {\r
+      Buffer[0]   = 0x0a;\r
+      NewLineSize = 1;\r
+    }\r
+\r
+    *Size = NewLineSize;\r
+    return ;\r
+  }\r
+  //\r
+  // use_crlf: give 0x0d 0x0a\r
+  //\r
+  if (Type == NewLineTypeCarriageReturnLineFeed) {\r
+    if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {\r
+      Buffer[0]   = 0x0d;\r
+      Buffer[1]   = 0;\r
+      Buffer[2]   = 0x0a;\r
+      Buffer[3]   = 0;\r
+\r
+      NewLineSize = 4;\r
+    } else {\r
+      Buffer[0]   = 0x0d;\r
+      Buffer[1]   = 0x0a;\r
+      NewLineSize = 2;\r
+    }\r
+\r
+    *Size = NewLineSize;\r
+    return ;\r
+  }\r
+  //\r
+  // use_lfcr: give 0x0a 0x0d\r
+  //\r
+  if (Type == NewLineTypeLineFeedCarriageReturn) {\r
+    if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {\r
+      Buffer[0]   = 0x0a;\r
+      Buffer[1]   = 0;\r
+      Buffer[2]   = 0x0d;\r
+      Buffer[3]   = 0;\r
+\r
+      NewLineSize = 4;\r
+    } else {\r
+      Buffer[0]   = 0x0a;\r
+      Buffer[1]   = 0x0d;\r
+      NewLineSize = 2;\r
+    }\r
+\r
+    *Size = NewLineSize;\r
+    return ;\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Change a Unicode string to an ASCII string.\r
+\r
+  @param[in] UStr     The Unicode string.\r
+  @param[in] Lenght   The maximum size of AStr.\r
+  @param[out] AStr    ASCII string to pass out.\r
+\r
+  @return The actuall length.\r
+**/\r
+UINTN\r
+EFIAPI\r
+UnicodeToAscii (\r
+  IN CONST CHAR16  *UStr,\r
+  IN CONST UINTN   Length,\r
+  OUT CHAR8   *AStr\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  //\r
+  // just buffer copy, not character copy\r
+  //\r
+  for (Index = 0; Index < Length; Index++) {\r
+    *AStr++ = (CHAR8) *UStr++;\r
+  }\r
+\r
+  return Index;\r
+}\r
+\r
+/**\r
+  Save lines in FileBuffer to disk\r
+\r
+  @param[in] FileName           The file name for writing.\r
+\r
+  @retval EFI_SUCCESS           Data was written.\r
+  @retval EFI_LOAD_ERROR        \r
+  @retval EFI_OUT_OF_RESOURCES  There were not enough resources to write the file.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferSave (\r
+  IN CONST CHAR16 *FileName\r
+  )\r
+{\r
+  SHELL_FILE_HANDLE FileHandle;\r
+  LIST_ENTRY        *Link;\r
+  EFI_EDITOR_LINE   *Line;\r
+  CHAR16            *Str;\r
+\r
+  EFI_STATUS        Status;\r
+  UINTN             Length;\r
+  UINTN             NumLines;\r
+  CHAR8             NewLineBuffer[4];\r
+  UINT8             NewLineSize;\r
+\r
+  EFI_FILE_INFO     *Info;\r
+\r
+  UINT64            Attribute;\r
+\r
+  EE_NEWLINE_TYPE   Type;\r
+\r
+  UINTN             TotalSize;\r
+  //\r
+  // 2M\r
+  //\r
+  CHAR8             *Cache;\r
+  UINTN             LeftSize;\r
+  UINTN             Size;\r
+  CHAR8             *Ptr;\r
+\r
+  Length    = 0;\r
+  //\r
+  // 2M\r
+  //\r
+  TotalSize = 0x200000;\r
+\r
+  Attribute = 0;\r
+\r
+\r
+\r
+  //\r
+  // if is the old file\r
+  //\r
+  if (StrCmp (FileName, FileBuffer.FileName) == 0) {\r
+    //\r
+    // file has not been modified\r
+    //\r
+    if (!FileBuffer.FileModified) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // if file is read-only, set error\r
+    //\r
+    if (FileBuffer.ReadOnly) {\r
+      StatusBarSetStatusString (L"Read Only File Can Not Be Saved");\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Info = ShellGetFileInfo(FileHandle);\r
+\r
+    if (Info != NULL && Info->Attribute & EFI_FILE_DIRECTORY) {\r
+      StatusBarSetStatusString (L"Directory Can Not Be Saved");\r
+      ShellCloseFile(FileHandle);\r
+      FreePool(Info);\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+    \r
+    if (Info != NULL) {\r
+      Attribute = Info->Attribute & ~EFI_FILE_READ_ONLY;\r
+      FreePool(Info);\r
+    }\r
+\r
+    //\r
+    // if file exits, so delete it\r
+    //\r
+    Status = ShellDeleteFile (&FileHandle);\r
+    if (EFI_ERROR (Status) || Status == EFI_WARN_DELETE_FAILURE) {\r
+      StatusBarSetStatusString (L"Write File Failed");\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+ }\r
+\r
+  Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, Attribute);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    StatusBarSetStatusString (L"Create File Failed");\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  //\r
+  // if file is Unicode file, write Unicode header to it.\r
+  //\r
+  if (FileBuffer.FileType == FileTypeUnicode) {\r
+    Length  = 2;\r
+    Status  = ShellWriteFile (FileHandle, &Length, (VOID*)&gUnicodeFileTag);\r
+    if (EFI_ERROR (Status)) {\r
+      ShellDeleteFile (&FileHandle);\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+  }\r
+\r
+  Cache = AllocateZeroPool (TotalSize);\r
+  if (Cache == NULL) {\r
+    ShellDeleteFile (&FileHandle);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // write all the lines back to disk\r
+  //\r
+  NumLines  = 0;\r
+  Type      = NewLineTypeCarriageReturnLineFeed;\r
+\r
+  Ptr       = Cache;\r
+  LeftSize  = TotalSize;\r
+\r
+  for (Link = FileBuffer.ListHead->ForwardLink; Link != FileBuffer.ListHead; Link = Link->ForwardLink) {\r
+    Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+\r
+    if (Line->Type != NewLineTypeDefault) {\r
+      Type = Line->Type;\r
+    }\r
+    //\r
+    // newline character is at most 4 bytes ( two Unicode characters )\r
+    //\r
+    Length = 4;\r
+    if (Line->Buffer != NULL && Line->Size != 0) {\r
+      if (FileBuffer.FileType == FileTypeAscii) {\r
+        Length += Line->Size;\r
+      } else {\r
+        Length += (Line->Size * 2);\r
+      }\r
+      //\r
+      // end if FileTypeAscii\r
+      //\r
+    }\r
+\r
+    //\r
+    // no cache room left, so write cache to disk\r
+    //\r
+    if (LeftSize < Length) {\r
+      Size    = TotalSize - LeftSize;\r
+      Status  = ShellWriteFile (FileHandle, &Size, Cache);\r
+      if (EFI_ERROR (Status)) {\r
+        ShellDeleteFile (&FileHandle);        \r
+        FreePool (Cache);\r
+        return EFI_LOAD_ERROR;\r
+      }\r
+      Ptr       = Cache;\r
+      LeftSize  = TotalSize;\r
+    }\r
+\r
+    if (Line->Buffer != NULL && Line->Size != 0) {\r
+      if (FileBuffer.FileType == FileTypeAscii) {\r
+        UnicodeToAscii (Line->Buffer, Line->Size, Ptr);\r
+        Length = Line->Size;\r
+      } else {\r
+        Length = (Line->Size * 2);\r
+        CopyMem (Ptr, (CHAR8 *) Line->Buffer, Length);\r
+      }\r
+      //\r
+      // end if FileTypeAscii\r
+      //\r
+      Ptr += Length;\r
+      LeftSize -= Length;\r
+\r
+    }\r
+    //\r
+    // end of if Line -> Buffer != NULL && Line -> Size != 0\r
+    //\r
+    // if not the last line , write return buffer to disk\r
+    //\r
+    if (Link->ForwardLink != FileBuffer.ListHead) {\r
+      GetNewLine (Type, NewLineBuffer, &NewLineSize);\r
+      CopyMem (Ptr, (CHAR8 *) NewLineBuffer, NewLineSize);\r
+\r
+      Ptr += NewLineSize;\r
+      LeftSize -= NewLineSize;\r
+    }\r
+\r
+    NumLines++;\r
+  }\r
+\r
+  if (TotalSize != LeftSize) {\r
+    Size    = TotalSize - LeftSize;\r
+    Status  = ShellWriteFile (FileHandle, &Size, Cache);\r
+    if (EFI_ERROR (Status)) {\r
+      ShellDeleteFile (&FileHandle);\r
+      FreePool (Cache);\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+  }\r
+\r
+  FreePool (Cache);\r
+\r
+  ShellCloseFile(&FileHandle);\r
+\r
+  FileBuffer.FileModified = FALSE;\r
+\r
+  //\r
+  // set status string\r
+  //\r
+  Str = CatSPrint (NULL, L"%d Lines Wrote", NumLines);\r
+  if (Str == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  StatusBarSetStatusString (Str);\r
+  SHELL_FREE_NON_NULL (Str);\r
+\r
+  //\r
+  // now everything is ready , you can set the new file name to filebuffer\r
+  //\r
+  if (StrCmp (FileName, FileBuffer.FileName) != 0) {\r
+    //\r
+    // not the same\r
+    //\r
+    FileBufferSetFileName (FileName);\r
+    if (FileBuffer.FileName == NULL) {\r
+      ShellDeleteFile (&FileHandle);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  FileBuffer.ReadOnly = FALSE;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Scroll cursor to left 1 character position.\r
+\r
+  @retval EFI_SUCCESS     The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferScrollLeft (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           FRow;\r
+  UINTN           FCol;\r
+\r
+  Line  = FileBuffer.CurrentLine;\r
+\r
+  FRow  = FileBuffer.FilePosition.Row;\r
+  FCol  = FileBuffer.FilePosition.Column;\r
+\r
+  //\r
+  // if already at start of this line, so move to the end of previous line\r
+  //\r
+  if (FCol <= 1) {\r
+    //\r
+    // has previous line\r
+    //\r
+    if (Line->Link.BackLink != FileBuffer.ListHead) {\r
+      FRow--;\r
+      Line  = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+      FCol  = Line->Size + 1;\r
+    } else {\r
+      return EFI_SUCCESS;\r
+    }\r
+  } else {\r
+    //\r
+    // if not at start of this line, just move to previous column\r
+    //\r
+    FCol--;\r
+  }\r
+\r
+  FileBufferMovePosition (FRow, FCol);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Delete a char in line\r
+\r
+  @param[in,out] Line   The line to delete in.\r
+  @param[in] Pos        Position to delete the char at ( start from 0 ).\r
+**/\r
+VOID\r
+EFIAPI\r
+LineDeleteAt (\r
+  IN  OUT EFI_EDITOR_LINE       *Line,\r
+  IN      UINTN                 Pos\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  //\r
+  // move the latter characters front\r
+  //\r
+  for (Index = Pos - 1; Index < Line->Size; Index++) {\r
+    Line->Buffer[Index] = Line->Buffer[Index + 1];\r
+  }\r
+\r
+  Line->Size--;\r
+}\r
+\r
+/**\r
+  Concatenate Src into Dest.\r
+\r
+  @param[in,out] Dest   Destination string\r
+  @param[in] Src        Src String.\r
+**/\r
+VOID\r
+EFIAPI\r
+LineCat (\r
+  IN  OUT EFI_EDITOR_LINE *Dest,\r
+  IN      EFI_EDITOR_LINE *Src\r
+  )\r
+{\r
+  CHAR16  *Str;\r
+  UINTN   Size;\r
+\r
+  Size                = Dest->Size;\r
+\r
+  Dest->Buffer[Size]  = 0;\r
+\r
+  //\r
+  // concatenate the two strings\r
+  //\r
+  Str = CatSPrint (NULL, L"%s%s", Dest->Buffer, Src->Buffer);\r
+  if (Str == NULL) {\r
+    Dest->Buffer = NULL;\r
+    return ;\r
+  }\r
+\r
+  Dest->Size      = Size + Src->Size;\r
+  Dest->TotalSize = Dest->Size;\r
+\r
+  FreePool (Dest->Buffer);\r
+  FreePool (Src->Buffer);\r
+\r
+  //\r
+  // put str to dest->buffer\r
+  //\r
+  Dest->Buffer = Str;\r
+}\r
+\r
+/**\r
+  Delete the previous character.\r
+\r
+  @retval EFI_SUCCESS           The delete was successful.\r
+  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferDoBackspace (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  EFI_EDITOR_LINE *End;\r
+  LIST_ENTRY  *Link;\r
+  UINTN           FileColumn;\r
+\r
+  FileColumn  = FileBuffer.FilePosition.Column;\r
+\r
+  Line        = FileBuffer.CurrentLine;\r
+\r
+  //\r
+  // the first column\r
+  //\r
+  if (FileColumn == 1) {\r
+    //\r
+    // the first row\r
+    //\r
+    if (FileBuffer.FilePosition.Row == 1) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    FileBufferScrollLeft ();\r
+\r
+    Line  = FileBuffer.CurrentLine;\r
+    Link  = Line->Link.ForwardLink;\r
+    End   = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+\r
+    //\r
+    // concatenate this line with previous line\r
+    //\r
+    LineCat (Line, End);\r
+    if (Line->Buffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // remove End from line list\r
+    //\r
+    RemoveEntryList (&End->Link);\r
+    FreePool (End);\r
+\r
+    FileBuffer.NumLines--;\r
+\r
+    FileBufferNeedRefresh         = TRUE;\r
+    FileBufferOnlyLineNeedRefresh = FALSE;\r
+\r
+  } else {\r
+    //\r
+    // just delete the previous character\r
+    //\r
+    LineDeleteAt (Line, FileColumn - 1);\r
+    FileBufferScrollLeft ();\r
+    FileBufferOnlyLineNeedRefresh = TRUE;\r
+  }\r
+\r
+  if (!FileBuffer.FileModified) {\r
+    FileBuffer.FileModified = TRUE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Add a return into line at current position.\r
+\r
+  @retval EFI_SUCCESS           The insetrion of the character was successful.\r
+  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferDoReturn (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  EFI_EDITOR_LINE *NewLine;\r
+  UINTN           FileColumn;\r
+  UINTN           Index;\r
+  CHAR16          *Buffer;\r
+  UINTN           Row;\r
+  UINTN           Col;\r
+\r
+  FileBufferNeedRefresh         = TRUE;\r
+  FileBufferOnlyLineNeedRefresh = FALSE;\r
+\r
+  Line                          = FileBuffer.CurrentLine;\r
+\r
+  FileColumn                    = FileBuffer.FilePosition.Column;\r
+\r
+  NewLine                       = AllocateZeroPool (sizeof (EFI_EDITOR_LINE));\r
+  if (NewLine == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NewLine->Signature  = LINE_LIST_SIGNATURE;\r
+  NewLine->Size       = Line->Size - FileColumn + 1;\r
+  NewLine->TotalSize  = NewLine->Size;\r
+  NewLine->Buffer     = CatSPrint (NULL, L"\0");\r
+  if (NewLine->Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NewLine->Type = NewLineTypeDefault;\r
+\r
+  if (NewLine->Size > 0) {\r
+    //\r
+    // UNICODE + CHAR_NULL\r
+    //\r
+    Buffer = AllocateZeroPool (2 * (NewLine->Size + 1));\r
+    if (Buffer == NULL) {\r
+      FreePool (NewLine->Buffer);\r
+      FreePool (NewLine);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    FreePool (NewLine->Buffer);\r
+\r
+    NewLine->Buffer = Buffer;\r
+\r
+    for (Index = 0; Index < NewLine->Size; Index++) {\r
+      NewLine->Buffer[Index] = Line->Buffer[Index + FileColumn - 1];\r
+    }\r
+\r
+    NewLine->Buffer[NewLine->Size]  = CHAR_NULL;\r
+\r
+    Line->Buffer[FileColumn - 1]    = CHAR_NULL;\r
+    Line->Size                      = FileColumn - 1;\r
+  }\r
+  //\r
+  // increase NumLines\r
+  //\r
+  FileBuffer.NumLines++;\r
+\r
+  //\r
+  // insert it into the correct position of line list\r
+  //\r
+  NewLine->Link.BackLink     = &(Line->Link);\r
+  NewLine->Link.ForwardLink     = Line->Link.ForwardLink;\r
+  Line->Link.ForwardLink->BackLink = &(NewLine->Link);\r
+  Line->Link.ForwardLink        = &(NewLine->Link);\r
+\r
+  //\r
+  // move cursor to the start of next line\r
+  //\r
+  Row = FileBuffer.FilePosition.Row + 1;\r
+  Col = 1;\r
+\r
+  FileBufferMovePosition (Row, Col);\r
+\r
+  //\r
+  // set file is modified\r
+  //\r
+  if (!FileBuffer.FileModified) {\r
+    FileBuffer.FileModified = TRUE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Delete current character from current line.  This is the effect caused \r
+  by the 'del' key.\r
+\r
+  @retval EFI_SUCCESS\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferDoDelete (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  EFI_EDITOR_LINE *Next;\r
+  LIST_ENTRY  *Link;\r
+  UINTN           FileColumn;\r
+\r
+  Line        = FileBuffer.CurrentLine;\r
+  FileColumn  = FileBuffer.FilePosition.Column;\r
+\r
+  //\r
+  // the last column\r
+  //\r
+  if (FileColumn >= Line->Size + 1) {\r
+    //\r
+    // the last line\r
+    //\r
+    if (Line->Link.ForwardLink == FileBuffer.ListHead) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // since last character,\r
+    // so will add the next line to this line\r
+    //\r
+    Link  = Line->Link.ForwardLink;\r
+    Next  = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+    LineCat (Line, Next);\r
+    if (Line->Buffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    RemoveEntryList (&Next->Link);\r
+    FreePool (Next);\r
+\r
+    FileBuffer.NumLines--;\r
+\r
+    FileBufferNeedRefresh         = TRUE;\r
+    FileBufferOnlyLineNeedRefresh = FALSE;\r
+\r
+  } else {\r
+    //\r
+    // just delete current character\r
+    //\r
+    LineDeleteAt (Line, FileColumn);\r
+    FileBufferOnlyLineNeedRefresh = TRUE;\r
+  }\r
+\r
+  if (!FileBuffer.FileModified) {\r
+    FileBuffer.FileModified = TRUE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Scroll cursor to right 1 character.\r
+\r
+  @retval EFI_SUCCESS     The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferScrollRight (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           FRow;\r
+  UINTN           FCol;\r
+\r
+  Line = FileBuffer.CurrentLine;\r
+  if (Line->Buffer == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  FRow  = FileBuffer.FilePosition.Row;\r
+  FCol  = FileBuffer.FilePosition.Column;\r
+\r
+  //\r
+  // if already at end of this line, scroll it to the start of next line\r
+  //\r
+  if (FCol > Line->Size) {\r
+    //\r
+    // has next line\r
+    //\r
+    if (Line->Link.ForwardLink != FileBuffer.ListHead) {\r
+      FRow++;\r
+      FCol = 1;\r
+    } else {\r
+      return EFI_SUCCESS;\r
+    }\r
+  } else {\r
+    //\r
+    // if not at end of this line, just move to next column\r
+    //\r
+    FCol++;\r
+  }\r
+\r
+  FileBufferMovePosition (FRow, FCol);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Insert a char into line\r
+\r
+  \r
+  @param[in] Line     The line to insert into.\r
+  @param[in] Char     The char to insert.\r
+  @param[in] Pos      The position to insert the char at ( start from 0 ).\r
+  @param[in] StrSize  The current string size ( include CHAR_NULL ),unit is Unicode character.\r
+\r
+  @return The new string size ( include CHAR_NULL ) ( unit is Unicode character ).\r
+**/\r
+UINTN\r
+EFIAPI\r
+LineStrInsert (\r
+  IN      EFI_EDITOR_LINE  *Line,\r
+  IN      CHAR16           Char,\r
+  IN      UINTN            Pos,\r
+  IN      UINTN            StrSize\r
+  )\r
+{\r
+  UINTN   Index;\r
+  CHAR16  *TempStringPtr;\r
+  CHAR16  *Str;\r
+\r
+  Index = (StrSize) * 2;\r
+\r
+  Str   = Line->Buffer;\r
+\r
+  //\r
+  // do not have free space\r
+  //\r
+  if (Line->TotalSize <= Line->Size) {\r
+    Str = ReallocatePool (Index, Index + 16, Str);\r
+    if (Str == NULL) {\r
+      return 0;\r
+    }\r
+\r
+    Line->TotalSize += 8;\r
+  }\r
+  //\r
+  // move the later part of the string one character right\r
+  //\r
+  TempStringPtr = Str;\r
+  for (Index = StrSize; Index > Pos; Index--) {\r
+    TempStringPtr[Index] = TempStringPtr[Index - 1];\r
+  }\r
+  //\r
+  // insert char into it.\r
+  //\r
+  TempStringPtr[Index]      = Char;\r
+\r
+  Line->Buffer  = Str;\r
+  Line->Size++;\r
+\r
+  return StrSize + 1;\r
+}\r
+\r
+/**\r
+  Add a character to the current line.\r
+\r
+  @param[in] Char               The Character to input.\r
+\r
+  @retval EFI_SUCCESS           The input was succesful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferAddChar (\r
+  IN  CHAR16  Char\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           FilePos;\r
+\r
+  Line = FileBuffer.CurrentLine;\r
+\r
+  //\r
+  // only needs to refresh current line\r
+  //\r
+  FileBufferOnlyLineNeedRefresh = TRUE;\r
+\r
+  //\r
+  // when is insert mode, or cursor is at end of this line,\r
+  // so insert this character\r
+  // or replace the character.\r
+  //\r
+  FilePos = FileBuffer.FilePosition.Column - 1;\r
+  if (FileBuffer.ModeInsert || FilePos + 1 > Line->Size) {\r
+    LineStrInsert (Line, Char, FilePos, Line->Size + 1);\r
+  } else {\r
+    Line->Buffer[FilePos] = Char;\r
+  }\r
+  //\r
+  // move cursor to right\r
+  //\r
+  FileBufferScrollRight ();\r
+\r
+  if (!FileBuffer.FileModified) {\r
+    FileBuffer.FileModified = TRUE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Handles inputs from characters (ASCII key + Backspace + return)\r
+\r
+  @param[in] Char               The input character.\r
+\r
+  @retval EFI_SUCCESS           The operation was successful.\r
+  @retval EFI_LOAD_ERROR        There was an error.\r
+  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferDoCharInput (\r
+  IN CONST CHAR16 Char\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (Char) {\r
+  case CHAR_NULL:\r
+    break;\r
+\r
+  case CHAR_BACKSPACE:\r
+    Status = FileBufferDoBackspace ();\r
+    break;\r
+\r
+  case CHAR_TAB:\r
+    //\r
+    // Tabs are ignored\r
+    //\r
+    break;\r
+\r
+  case CHAR_LINEFEED:\r
+  case CHAR_CARRIAGE_RETURN:\r
+    Status = FileBufferDoReturn ();\r
+    break;\r
+\r
+  default:\r
+    //\r
+    // DEAL WITH ASCII CHAR, filter out thing like ctrl+f\r
+    //\r
+    if (Char > 127 || Char < 32) {\r
+      Status = StatusBarSetStatusString (L"Unknown Command");\r
+    } else {\r
+      Status = FileBufferAddChar (Char);\r
+    }\r
+\r
+    break;\r
+\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Scroll cursor to the next line.\r
+\r
+  @retval EFI_SUCCESS     The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferScrollDown (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           FRow;\r
+  UINTN           FCol;\r
+\r
+  Line = FileBuffer.CurrentLine;\r
+  if (Line->Buffer == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  FRow  = FileBuffer.FilePosition.Row;\r
+  FCol  = FileBuffer.FilePosition.Column;\r
+\r
+  //\r
+  // has next line\r
+  //\r
+  if (Line->Link.ForwardLink != FileBuffer.ListHead) {\r
+    FRow++;\r
+    Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+\r
+    //\r
+    // if the next line is not that long, so move to end of next line\r
+    //\r
+    if (FCol > Line->Size) {\r
+      FCol = Line->Size + 1;\r
+    }\r
+\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  FileBufferMovePosition (FRow, FCol);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Scroll the cursor to previous line.\r
+\r
+  @retval EFI_SUCCESS     The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferScrollUp (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           FRow;\r
+  UINTN           FCol;\r
+\r
+  Line  = FileBuffer.CurrentLine;\r
+\r
+  FRow  = FileBuffer.FilePosition.Row;\r
+  FCol  = FileBuffer.FilePosition.Column;\r
+\r
+  //\r
+  // has previous line\r
+  //\r
+  if (Line->Link.BackLink != FileBuffer.ListHead) {\r
+    FRow--;\r
+    Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+\r
+    //\r
+    // if previous line is not that long, so move to the end of previous line\r
+    //\r
+    if (FCol > Line->Size) {\r
+      FCol = Line->Size + 1;\r
+    }\r
+\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  FileBufferMovePosition (FRow, FCol);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Scroll cursor to next page.\r
+\r
+  @retval EFI_SUCCESS     The operation wa successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferPageDown (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           FRow;\r
+  UINTN           FCol;\r
+  UINTN           Gap;\r
+\r
+  Line  = FileBuffer.CurrentLine;\r
+\r
+  FRow  = FileBuffer.FilePosition.Row;\r
+  FCol  = FileBuffer.FilePosition.Column;\r
+\r
+  //\r
+  // has next page\r
+  //\r
+  if (FileBuffer.NumLines >= FRow + (MainEditor.ScreenSize.Row - 5)) {\r
+    Gap = (MainEditor.ScreenSize.Row - 5);\r
+  } else {\r
+    //\r
+    // MOVE CURSOR TO LAST LINE\r
+    //\r
+    Gap = FileBuffer.NumLines - FRow;\r
+  }\r
+  //\r
+  // get correct line\r
+  //\r
+  Line = MoveLine (Gap);\r
+\r
+  //\r
+  // if that line, is not that long, so move to the end of that line\r
+  //\r
+  if (FCol > Line->Size) {\r
+    FCol = Line->Size + 1;\r
+  }\r
+\r
+  FRow += Gap;\r
+\r
+  FileBufferMovePosition (FRow, FCol);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Scroll cursor to previous screen.\r
+\r
+  @retval EFI_SUCCESS     The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferPageUp (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           FRow;\r
+  UINTN           FCol;\r
+  UINTN           Gap;\r
+  INTN            Retreat;\r
+\r
+  Line  = FileBuffer.CurrentLine;\r
+\r
+  FRow  = FileBuffer.FilePosition.Row;\r
+  FCol  = FileBuffer.FilePosition.Column;\r
+\r
+  //\r
+  // has previous page\r
+  //\r
+  if (FRow > (MainEditor.ScreenSize.Row - 5)) {\r
+    Gap = (MainEditor.ScreenSize.Row - 5);\r
+  } else {\r
+    //\r
+    // the first line of file will displayed on the first line of screen\r
+    //\r
+    Gap = FRow - 1;\r
+  }\r
+\r
+  Retreat = Gap;\r
+  Retreat = -Retreat;\r
+\r
+  //\r
+  // get correct line\r
+  //\r
+  Line = MoveLine (Retreat);\r
+\r
+  //\r
+  // if that line is not that long, so move to the end of that line\r
+  //\r
+  if (FCol > Line->Size) {\r
+    FCol = Line->Size + 1;\r
+  }\r
+\r
+  FRow -= Gap;\r
+\r
+  FileBufferMovePosition (FRow, FCol);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Scroll cursor to end of the current line.\r
+\r
+  @retval EFI_SUCCESS       The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferEnd (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           FRow;\r
+  UINTN           FCol;\r
+\r
+  Line  = FileBuffer.CurrentLine;\r
+\r
+  FRow  = FileBuffer.FilePosition.Row;\r
+\r
+  //\r
+  // goto the last column of the line\r
+  //\r
+  FCol = Line->Size + 1;\r
+\r
+  FileBufferMovePosition (FRow, FCol);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/** \r
+  Dispatch input to different handler\r
+  @param[in] Key                The input key.  One of:\r
+                                    ASCII KEY\r
+                                    Backspace/Delete\r
+                                    Return\r
+                                    Direction key: up/down/left/right/pgup/pgdn\r
+                                    Home/End\r
+                                    INS\r
+\r
+  @retval EFI_SUCCESS           The dispatch was done successfully.\r
+  @retval EFI_LOAD_ERROR        The dispatch was not successful.\r
+  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferHandleInput (\r
+  IN CONST EFI_INPUT_KEY *Key\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (Key->ScanCode) {\r
+  //\r
+  // ordinary key input\r
+  //\r
+  case SCAN_NULL:\r
+    if (!FileBuffer.ReadOnly) {\r
+      Status = FileBufferDoCharInput (Key->UnicodeChar);\r
+    } else {\r
+      Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified");\r
+    }\r
+\r
+    break;\r
+\r
+  //\r
+  // up arrow\r
+  //\r
+  case SCAN_UP:\r
+    Status = FileBufferScrollUp ();\r
+    break;\r
+\r
+  //\r
+  // down arrow\r
+  //\r
+  case SCAN_DOWN:\r
+    Status = FileBufferScrollDown ();\r
+    break;\r
+\r
+  //\r
+  // right arrow\r
+  //\r
+  case SCAN_RIGHT:\r
+    Status = FileBufferScrollRight ();\r
+    break;\r
+\r
+  //\r
+  // left arrow\r
+  //\r
+  case SCAN_LEFT:\r
+    Status = FileBufferScrollLeft ();\r
+    break;\r
+\r
+  //\r
+  // page up\r
+  //\r
+  case SCAN_PAGE_UP:\r
+    Status = FileBufferPageUp ();\r
+    break;\r
+\r
+  //\r
+  // page down\r
+  //\r
+  case SCAN_PAGE_DOWN:\r
+    Status = FileBufferPageDown ();\r
+    break;\r
+\r
+  //\r
+  // delete\r
+  //\r
+  case SCAN_DELETE:\r
+    if (!FileBuffer.ReadOnly) {\r
+      Status = FileBufferDoDelete ();\r
+    } else {\r
+      Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified");\r
+    }\r
+\r
+    break;\r
+\r
+  //\r
+  // home\r
+  //\r
+  case SCAN_HOME:\r
+    FileBufferMovePosition (FileBuffer.FilePosition.Row, 1);\r
+    Status = EFI_SUCCESS;\r
+    break;\r
+\r
+  //\r
+  // end\r
+  //\r
+  case SCAN_END:\r
+    Status = FileBufferEnd ();\r
+    break;\r
+\r
+  //\r
+  // insert\r
+  //\r
+  case SCAN_INSERT:\r
+    FileBuffer.ModeInsert = (BOOLEAN)!FileBuffer.ModeInsert;\r
+    Status = EFI_SUCCESS;\r
+    break;\r
+\r
+  default:\r
+    Status = StatusBarSetStatusString (L"Unknown Command");\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check user specified FileRow is above current screen.\r
+\r
+  @param[in] FileRow    The row of file position ( start from 1 ).\r
+\r
+  @retval TRUE    It is above the current screen.\r
+  @retval FALSE   It is not above the current screen.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+AboveCurrentScreen (\r
+  IN UINTN FileRow\r
+  )\r
+{\r
+  //\r
+  // if is to the above of the screen\r
+  //\r
+  if (FileRow < FileBuffer.LowVisibleRange.Row) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check user specified FileRow is under current screen.\r
+\r
+  @param[in] FileRow    The row of file position ( start from 1 ).\r
+\r
+  @retval TRUE      It is under the current screen.\r
+  @retval FALSE     It is not under the current screen.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+UnderCurrentScreen (\r
+  IN UINTN FileRow\r
+  )\r
+{\r
+  //\r
+  // if is to the under of the screen\r
+  //\r
+  if (FileRow > FileBuffer.LowVisibleRange.Row + (MainEditor.ScreenSize.Row - 5) - 1) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check user specified FileCol is left to current screen.\r
+\r
+  @param[in] FileCol    The column of file position ( start from 1 ).\r
+\r
+  @retval TRUE    It is to the left.\r
+  @retval FALSE   It is not to the left.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+LeftCurrentScreen (\r
+  IN UINTN FileCol\r
+  )\r
+{\r
+  //\r
+  // if is to the left of the screen\r
+  //\r
+  if (FileCol < FileBuffer.LowVisibleRange.Column) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check user specified FileCol is right to current screen.\r
+\r
+  @param[in] FileCol    The column of file position ( start from 1 ).\r
+\r
+  @retval TRUE    It is to the right.\r
+  @retval FALSE   It is not to the right.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+RightCurrentScreen (\r
+  IN UINTN FileCol\r
+  )\r
+{\r
+  //\r
+  // if is to the right of the screen\r
+  //\r
+  if (FileCol > FileBuffer.LowVisibleRange.Column + MainEditor.ScreenSize.Column - 1) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Advance/Retreat lines and set CurrentLine in FileBuffer to it\r
+  \r
+  @param[in] Count The line number to advance/retreat\r
+                     >0 : advance\r
+                     <0: retreat\r
+\r
+  @retval NULL An error occured.\r
+  @return The line after advance/retreat.\r
+**/\r
+EFI_EDITOR_LINE *\r
+EFIAPI\r
+MoveCurrentLine (\r
+  IN  INTN Count\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  UINTN           AbsCount;\r
+\r
+  if (Count <= 0) {\r
+    AbsCount  = -Count;\r
+    Line      = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);\r
+  } else {\r
+    Line = InternalEditorMiscLineAdvance (Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);\r
+  }\r
+\r
+  if (Line == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  MainEditor.FileBuffer->CurrentLine = Line;\r
+\r
+  return Line;\r
+}\r
+\r
+/**\r
+  According to cursor's file position, adjust screen display\r
+\r
+  @param[in] NewFilePosRow    The row of file position ( start from 1 ).\r
+  @param[in] NewFilePosCol    The column of file position ( start from 1 ).\r
+**/\r
+VOID\r
+EFIAPI\r
+FileBufferMovePosition (\r
+  IN CONST UINTN NewFilePosRow,\r
+  IN CONST UINTN NewFilePosCol\r
+  )\r
+{\r
+  INTN    RowGap;\r
+  INTN    ColGap;\r
+  UINTN   Abs;\r
+  BOOLEAN Above;\r
+  BOOLEAN Under;\r
+  BOOLEAN Right;\r
+  BOOLEAN Left;\r
+\r
+  //\r
+  // CALCULATE gap between current file position and new file position\r
+  //\r
+  RowGap  = NewFilePosRow - FileBuffer.FilePosition.Row;\r
+  ColGap  = NewFilePosCol - FileBuffer.FilePosition.Column;\r
+\r
+  Under   = UnderCurrentScreen (NewFilePosRow);\r
+  Above   = AboveCurrentScreen (NewFilePosRow);\r
+  //\r
+  // if is below current screen\r
+  //\r
+  if (Under) {\r
+    //\r
+    // display row will be unchanged\r
+    //\r
+    FileBuffer.FilePosition.Row = NewFilePosRow;\r
+  } else {\r
+    if (Above) {\r
+      //\r
+      // has enough above line, so display row unchanged\r
+      // not has enough above lines, so the first line is at the\r
+      // first display line\r
+      //\r
+      if (NewFilePosRow < (FileBuffer.DisplayPosition.Row - 1)) {\r
+        FileBuffer.DisplayPosition.Row = NewFilePosRow + 1;\r
+      }\r
+\r
+      FileBuffer.FilePosition.Row = NewFilePosRow;\r
+    } else {\r
+      //\r
+      // in current screen\r
+      //\r
+      FileBuffer.FilePosition.Row = NewFilePosRow;\r
+      if (RowGap < 0) {\r
+        Abs = -RowGap;\r
+        FileBuffer.DisplayPosition.Row -= Abs;\r
+      } else {\r
+        FileBuffer.DisplayPosition.Row += RowGap;\r
+      }\r
+    }\r
+  }\r
+\r
+  FileBuffer.LowVisibleRange.Row  = FileBuffer.FilePosition.Row - (FileBuffer.DisplayPosition.Row - 2);\r
+\r
+  Right = RightCurrentScreen (NewFilePosCol);\r
+  Left = LeftCurrentScreen (NewFilePosCol);\r
+\r
+  //\r
+  // if right to current screen\r
+  //\r
+  if (Right) {\r
+    //\r
+    // display column will be changed to end\r
+    //\r
+    FileBuffer.DisplayPosition.Column = MainEditor.ScreenSize.Column;\r
+    FileBuffer.FilePosition.Column    = NewFilePosCol;\r
+  } else {\r
+    if (Left) {\r
+      //\r
+      // has enough left characters , so display row unchanged\r
+      // not has enough left characters,\r
+      // so the first character is at the first display column\r
+      //\r
+      if (NewFilePosCol < (FileBuffer.DisplayPosition.Column)) {\r
+        FileBuffer.DisplayPosition.Column = NewFilePosCol;\r
+      }\r
+\r
+      FileBuffer.FilePosition.Column = NewFilePosCol;\r
+    } else {\r
+      //\r
+      // in current screen\r
+      //\r
+      FileBuffer.FilePosition.Column = NewFilePosCol;\r
+      if (ColGap < 0) {\r
+        Abs = -ColGap;\r
+        FileBuffer.DisplayPosition.Column -= Abs;\r
+      } else {\r
+        FileBuffer.DisplayPosition.Column += ColGap;\r
+      }\r
+    }\r
+  }\r
+\r
+  FileBuffer.LowVisibleRange.Column = FileBuffer.FilePosition.Column - (FileBuffer.DisplayPosition.Column - 1);\r
+\r
+  //\r
+  // let CurrentLine point to correct line;\r
+  //\r
+  FileBuffer.CurrentLine = MoveCurrentLine (RowGap);\r
+\r
+}\r
+\r
+/**\r
+  Cut current line out and return a pointer to it.\r
+\r
+  @param[out] CutLine    Upon a successful return pointer to the pointer to \r
+                        the allocated cut line.\r
+\r
+  @retval EFI_SUCCESS             The cut was successful.\r
+  @retval EFI_NOT_FOUND           There was no selection to cut.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferCutLine (\r
+  OUT EFI_EDITOR_LINE **CutLine\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  EFI_EDITOR_LINE *NewLine;\r
+  UINTN           Row;\r
+  UINTN           Col;\r
+\r
+  if (FileBuffer.ReadOnly) {\r
+    StatusBarSetStatusString (L"Read Only File Can Not Be Modified");\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Line = FileBuffer.CurrentLine;\r
+\r
+  //\r
+  // if is the last dummy line, SO CAN not cut\r
+  //\r
+  if (StrCmp (Line->Buffer, L"\0") == 0 && Line->Link.ForwardLink == FileBuffer.ListHead\r
+  //\r
+  // last line\r
+  //\r
+  ) {\r
+    //\r
+    // LAST LINE AND NOTHING ON THIS LINE, SO CUT NOTHING\r
+    //\r
+    StatusBarSetStatusString (L"Nothing to Cut");\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // if is the last line, so create a dummy line\r
+  //\r
+  if (Line->Link.ForwardLink == FileBuffer.ListHead) {\r
+    //\r
+    // last line\r
+    // create a new line\r
+    //\r
+    NewLine = FileBufferCreateLine ();\r
+    if (NewLine == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  FileBuffer.NumLines--;\r
+  Row = FileBuffer.FilePosition.Row;\r
+  Col = 1;\r
+  //\r
+  // move home\r
+  //\r
+  FileBuffer.CurrentLine = CR (\r
+                            FileBuffer.CurrentLine->Link.ForwardLink,\r
+                            EFI_EDITOR_LINE,\r
+                            Link,\r
+                            LINE_LIST_SIGNATURE\r
+                            );\r
+\r
+  RemoveEntryList (&Line->Link);\r
+\r
+  FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+\r
+  FileBufferMovePosition (Row, Col);\r
+\r
+  FileBuffer.FileModified       = TRUE;\r
+  FileBufferNeedRefresh         = TRUE;\r
+  FileBufferOnlyLineNeedRefresh = FALSE;\r
+\r
+  *CutLine                      = Line;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Paste a line into line list.\r
+\r
+  @retval EFI_SUCCESS             The paste was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferPasteLine (\r
+  VOID\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Line;\r
+  EFI_EDITOR_LINE *NewLine;\r
+  UINTN           Row;\r
+  UINTN           Col;\r
+\r
+  //\r
+  // if nothing is on clip board\r
+  // then do nothing\r
+  //\r
+  if (MainEditor.CutLine == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // read only file can not be pasted on\r
+  //\r
+  if (FileBuffer.ReadOnly) {\r
+    StatusBarSetStatusString (L"Read Only File Can Not Be Modified");\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  NewLine = LineDup (MainEditor.CutLine);\r
+  if (NewLine == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // insert it above current line\r
+  //\r
+  Line                    = FileBuffer.CurrentLine;\r
+  NewLine->Link.BackLink     = Line->Link.BackLink;\r
+  NewLine->Link.ForwardLink     = &Line->Link;\r
+\r
+  Line->Link.BackLink->ForwardLink = &NewLine->Link;\r
+  Line->Link.BackLink        = &NewLine->Link;\r
+\r
+  FileBuffer.NumLines++;\r
+  FileBuffer.CurrentLine  = NewLine;\r
+\r
+  FileBuffer.Lines        = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+\r
+  Col                     = 1;\r
+  //\r
+  // move home\r
+  //\r
+  Row = FileBuffer.FilePosition.Row;\r
+\r
+  FileBufferMovePosition (Row, Col);\r
+\r
+  //\r
+  // after paste, set some value so that refresh knows to do something\r
+  //\r
+  FileBuffer.FileModified       = TRUE;\r
+  FileBufferNeedRefresh         = TRUE;\r
+  FileBufferOnlyLineNeedRefresh = FALSE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Search string from current position on in file\r
+\r
+  @param[in] Str    The search string.\r
+  @param[in] Offset The offset from current position.\r
+\r
+  @retval EFI_SUCCESS       The operation was successful.\r
+  @retval EFI_NOT_FOUND     The string Str was not found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferSearch (\r
+  IN CONST CHAR16  *Str,\r
+  IN CONST UINTN Offset\r
+  )\r
+{\r
+  CHAR16          *Current;\r
+  UINTN           Position;\r
+  UINTN           Row;\r
+  UINTN           Column;\r
+  EFI_EDITOR_LINE *Line;\r
+  CHAR16          *CharPos;\r
+  LIST_ENTRY      *Link;\r
+  BOOLEAN         Found;\r
+\r
+  Column = 0;\r
+\r
+  //\r
+  // search if in current line\r
+  //\r
+  Current = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1 + Offset;\r
+\r
+  if (Current >= (FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size)) {\r
+    //\r
+    // the end\r
+    //\r
+    Current = FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size;\r
+  }\r
+\r
+  CharPos  =  StrStr (Current, Str);\r
+  if (CharPos != NULL) {\r
+    Position = CharPos - Current;\r
+  } else {\r
+    Position = 0;\r
+  }\r
+\r
+  //\r
+  // found\r
+  //\r
+  if (Position != 0) {\r
+    Column  = (Position - 1) + FileBuffer.FilePosition.Column + Offset;\r
+    Row     = FileBuffer.FilePosition.Row;\r
+    Found   = TRUE;\r
+  } else {\r
+    //\r
+    // not found so find through next lines\r
+    //\r
+    Link  = FileBuffer.CurrentLine->Link.ForwardLink;\r
+\r
+    Row   = FileBuffer.FilePosition.Row + 1;\r
+    while (Link != FileBuffer.ListHead) {\r
+      Line      = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+//      Position  = StrStr (Line->Buffer, Str);\r
+      CharPos  =  StrStr (Line->Buffer, Str);\r
+      if (CharPos != NULL) {\r
+        Position = CharPos - Line->Buffer;\r
+      }\r
+      if (Position != 0) {\r
+        //\r
+        // found\r
+        //\r
+        Column = Position;\r
+        break;\r
+      }\r
+\r
+      Row++;\r
+      Link = Link->ForwardLink;\r
+    }\r
+\r
+    if (Link == FileBuffer.ListHead) {\r
+      Found = FALSE;\r
+    } else {\r
+      Found = TRUE;\r
+    }\r
+  }\r
+\r
+  if (!Found) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  FileBufferMovePosition (Row, Column);\r
+\r
+  //\r
+  // call refresh to fresh edit area,\r
+  // because the outer may loop to find multiply occurrence of this string\r
+  //\r
+  FileBufferRefresh ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Replace SearchLen characters from current position on with Replace.\r
+\r
+  This will modify the current buffer at the current position.\r
+\r
+  @param[in] Replace    The string to replace.\r
+  @param[in] SearchLen  Search string's length.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferReplace (\r
+  IN CONST CHAR16   *Replace,\r
+  IN CONST UINTN    SearchLen\r
+  )\r
+{\r
+  UINTN   ReplaceLen;\r
+  UINTN   Index;\r
+  CHAR16  *Buffer;\r
+  UINTN   NewSize;\r
+  UINTN   OldSize;\r
+  UINTN   Gap;\r
+\r
+  ReplaceLen  = StrLen (Replace);\r
+\r
+  OldSize     = FileBuffer.CurrentLine->Size + 1;\r
+  //\r
+  // include CHAR_NULL\r
+  //\r
+  NewSize = OldSize + (ReplaceLen - SearchLen);\r
+\r
+  if (ReplaceLen > SearchLen) {\r
+    //\r
+    // do not have the enough space\r
+    //\r
+    if (FileBuffer.CurrentLine->TotalSize + 1 <= NewSize) {\r
+      FileBuffer.CurrentLine->Buffer = ReallocatePool (\r
+                                        2 * OldSize,\r
+                                        2 * NewSize,\r
+                                        FileBuffer.CurrentLine->Buffer\r
+                                        );\r
+      FileBuffer.CurrentLine->TotalSize = NewSize - 1;\r
+    }\r
+\r
+    if (FileBuffer.CurrentLine->Buffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // the end CHAR_NULL character;\r
+    //\r
+    Buffer  = FileBuffer.CurrentLine->Buffer + (NewSize - 1);\r
+    Gap     = ReplaceLen - SearchLen;\r
+\r
+    //\r
+    // keep the latter part\r
+    //\r
+    for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - SearchLen + 2); Index++) {\r
+      *Buffer = *(Buffer - Gap);\r
+      Buffer--;\r
+    }\r
+    //\r
+    // set replace into it\r
+    //\r
+    Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column;\r
+    for (Index = 0; Index < ReplaceLen; Index++) {\r
+      Buffer[Index] = Replace[Index];\r
+    }\r
+  }\r
+\r
+  if (ReplaceLen < SearchLen) {\r
+    Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column;\r
+\r
+    for (Index = 0; Index < ReplaceLen; Index++) {\r
+      Buffer[Index] = Replace[Index];\r
+    }\r
+\r
+    Buffer += ReplaceLen;\r
+    Gap = SearchLen - ReplaceLen;\r
+\r
+    //\r
+    // set replace into it\r
+    //\r
+    for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - ReplaceLen + 2); Index++) {\r
+      *Buffer = *(Buffer + Gap);\r
+      Buffer++;\r
+    }\r
+  }\r
+\r
+  if (ReplaceLen == SearchLen) {\r
+    Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column;\r
+    for (Index = 0; Index < ReplaceLen; Index++) {\r
+      Buffer[Index] = Replace[Index];\r
+    }\r
+  }\r
+\r
+  FileBuffer.CurrentLine->Size += (ReplaceLen - SearchLen);\r
+\r
+  FileBufferOnlyLineNeedRefresh = TRUE;\r
+\r
+  FileBuffer.FileModified       = TRUE;\r
+\r
+  MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);\r
+  FileBufferRestorePosition ();\r
+  FileBufferRefresh ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Move the mouse cursor position.\r
+\r
+  @param[in] TextX      The new x-coordinate.\r
+  @param[in] TextY      The new y-coordinate.\r
+**/\r
+VOID\r
+EFIAPI\r
+FileBufferAdjustMousePosition (\r
+  IN CONST INT32 TextX,\r
+  IN CONST INT32 TextY\r
+  )\r
+{\r
+  UINTN CoordinateX;\r
+  UINTN CoordinateY;\r
+  UINTN AbsX;\r
+  UINTN AbsY;\r
+\r
+  //\r
+  // TextX and TextY is mouse movement data returned by mouse driver\r
+  // This function will change it to MousePosition\r
+  //\r
+  //\r
+  // get absolute value\r
+  //\r
+\r
+  AbsX = ABS(TextX);\r
+  AbsY = ABS(TextY);\r
+\r
+  CoordinateX = FileBuffer.MousePosition.Column;\r
+  CoordinateY = FileBuffer.MousePosition.Row;\r
+\r
+  if (TextX >= 0) {\r
+    CoordinateX += TextX;\r
+  } else {\r
+    if (CoordinateX >= AbsX) {\r
+      CoordinateX -= AbsX;\r
+    } else {\r
+      CoordinateX = 0;\r
+    }\r
+  }\r
+\r
+  if (TextY >= 0) {\r
+    CoordinateY += TextY;\r
+  } else {\r
+    if (CoordinateY >= AbsY) {\r
+      CoordinateY -= AbsY;\r
+    } else {\r
+      CoordinateY = 0;\r
+    }\r
+  }\r
+  //\r
+  // check whether new mouse column position is beyond screen\r
+  // if not, adjust it\r
+  //\r
+  if (CoordinateX >= 1 && CoordinateX <= MainEditor.ScreenSize.Column) {\r
+    FileBuffer.MousePosition.Column = CoordinateX;\r
+  } else if (CoordinateX < 1) {\r
+    FileBuffer.MousePosition.Column = 1;\r
+  } else if (CoordinateX > MainEditor.ScreenSize.Column) {\r
+    FileBuffer.MousePosition.Column = MainEditor.ScreenSize.Column;\r
+  }\r
+  //\r
+  // check whether new mouse row position is beyond screen\r
+  // if not, adjust it\r
+  //\r
+  if (CoordinateY >= 2 && CoordinateY <= (MainEditor.ScreenSize.Row - 4)) {\r
+    FileBuffer.MousePosition.Row = CoordinateY;\r
+  } else if (CoordinateY < 2) {\r
+    FileBuffer.MousePosition.Row = 2;\r
+  } else if (CoordinateY > (MainEditor.ScreenSize.Row - 4)) {\r
+    FileBuffer.MousePosition.Row = (MainEditor.ScreenSize.Row - 4);\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Search and replace operation.\r
+\r
+  @param[in] SearchStr    The string to search for.\r
+  @param[in] ReplaceStr   The string to replace with.\r
+  @param[in] Offset       The column to start at.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferReplaceAll (\r
+  IN CHAR16 *SearchStr,\r
+  IN CHAR16 *ReplaceStr,\r
+  IN UINTN  Offset\r
+  )\r
+{\r
+  CHAR16          *Buffer;\r
+  UINTN           Position;\r
+  UINTN           Column;\r
+  UINTN           ReplaceLen;\r
+  UINTN           SearchLen;\r
+  UINTN           Index;\r
+  UINTN           NewSize;\r
+  UINTN           OldSize;\r
+  UINTN           Gap;\r
+  EFI_EDITOR_LINE *Line;\r
+  LIST_ENTRY      *Link;\r
+  CHAR16          *CharPos;\r
+\r
+  SearchLen   = StrLen (SearchStr);\r
+  ReplaceLen  = StrLen (ReplaceStr);\r
+\r
+  Column      = FileBuffer.FilePosition.Column + Offset - 1;\r
+\r
+  if (Column > FileBuffer.CurrentLine->Size) {\r
+    Column = FileBuffer.CurrentLine->Size;\r
+  }\r
+\r
+  Link = &(FileBuffer.CurrentLine->Link);\r
+\r
+  while (Link != FileBuffer.ListHead) {\r
+    Line      = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+    CharPos  =  StrStr (Line->Buffer + Column, SearchStr);\r
+    if (CharPos != NULL) {\r
+      Position = CharPos - Line->Buffer;// + Column;\r
+      //\r
+      // found\r
+      //\r
+      if (ReplaceLen > SearchLen) {\r
+        OldSize = Line->Size + 1;\r
+        //\r
+        // include CHAR_NULL\r
+        //\r
+        NewSize = OldSize + (ReplaceLen - SearchLen);\r
+\r
+        //\r
+        // do not have the enough space\r
+        //\r
+        if (Line->TotalSize + 1 <= NewSize) {\r
+          Line->Buffer = ReallocatePool (\r
+                          2 * OldSize,\r
+                          2 * NewSize,\r
+                          Line->Buffer\r
+                          );\r
+          Line->TotalSize = NewSize - 1;\r
+        }\r
+\r
+        if (Line->Buffer == NULL) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+        //\r
+        // the end CHAR_NULL character;\r
+        //\r
+        Buffer  = Line->Buffer + (NewSize - 1);\r
+        Gap     = ReplaceLen - SearchLen;\r
+\r
+        //\r
+        // keep the latter part\r
+        //\r
+        for (Index = 0; Index < (Line->Size - Position - SearchLen + 1); Index++) {\r
+          *Buffer = *(Buffer - Gap);\r
+          Buffer--;\r
+        }\r
+\r
+      } else if (ReplaceLen < SearchLen){\r
+        Buffer  = Line->Buffer + Position + ReplaceLen;\r
+        Gap     = SearchLen - ReplaceLen;\r
+\r
+        for (Index = 0; Index < (Line->Size - Position - ReplaceLen + 1); Index++) {\r
+          *Buffer = *(Buffer + Gap);\r
+          Buffer++;\r
+        }\r
+      } else {\r
+        ASSERT(ReplaceLen == SearchLen);\r
+      }\r
+      //\r
+      // set replace into it\r
+      //\r
+      Buffer = Line->Buffer + Position;\r
+      for (Index = 0; Index < ReplaceLen; Index++) {\r
+        Buffer[Index] = ReplaceStr[Index];\r
+      }\r
+\r
+      Line->Size += (ReplaceLen - SearchLen);\r
+      Column += ReplaceLen;\r
+    } else {\r
+      //\r
+      // not found\r
+      //\r
+      Column  = 0;\r
+      Link    = Link->ForwardLink;\r
+    }\r
+  }\r
+  //\r
+  // call refresh to fresh edit area\r
+  //\r
+  FileBuffer.FileModified = TRUE;\r
+  FileBufferNeedRefresh   = TRUE;\r
+  FileBufferRefresh ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set the modified state to TRUE.\r
+**/\r
+VOID\r
+EFIAPI\r
+FileBufferSetModified (\r
+  VOID\r
+  )\r
+{\r
+  FileBuffer.FileModified = TRUE;\r
+}\r
+\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h
new file mode 100644 (file)
index 0000000..9d4a08d
--- /dev/null
@@ -0,0 +1,263 @@
+/** @file\r
+  Declares filebuffer interface functions.\r
+\r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _LIB_FILE_BUFFER_H_\r
+#define _LIB_FILE_BUFFER_H_\r
+\r
+#include "TextEditorTypes.h"\r
+\r
+/**\r
+  Initialization function for FileBuffer.\r
+\r
+  @param EFI_SUCCESS            The initialization was successful.\r
+  @param EFI_LOAD_ERROR         A default name could not be created.\r
+  @param EFI_OUT_OF_RESOURCES   A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferInit (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Cleanup function for FileBuffer.\r
+\r
+  @retval EFI_SUCCESS   The cleanup was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferCleanup (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Refresh the screen with whats in the buffer.\r
+\r
+  @retval EFI_SUCCESS     The refresh was successful.\r
+  @retval EFI_LOAD_ERROR  There was an error finding what to write.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferRefresh (\r
+  VOID\r
+  );\r
+\r
+/** \r
+  Dispatch input to different handler\r
+  @param[in] Key                The input key.  One of:\r
+                                    ASCII KEY\r
+                                    Backspace/Delete\r
+                                    Return\r
+                                    Direction key: up/down/left/right/pgup/pgdn\r
+                                    Home/End\r
+                                    INS\r
+\r
+  @retval EFI_SUCCESS           The dispatch was done successfully.\r
+  @retval EFI_LOAD_ERROR        The dispatch was not successful.\r
+  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferHandleInput (\r
+  IN CONST EFI_INPUT_KEY * Key\r
+  );\r
+\r
+/**\r
+  Backup function for FileBuffer.  Only backup the following items:\r
+      Mouse/Cursor position\r
+      File Name, Type, ReadOnly, Modified\r
+      Insert Mode\r
+\r
+  This is for making the file buffer refresh as few as possible.\r
+\r
+  @retval EFI_SUCCESS           The backup operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferBackup (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Set the cursor position according to FileBuffer.DisplayPosition.\r
+\r
+  @retval EFI_SUCCESS           The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferRestorePosition (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Set FileName field in FileBuffer.\r
+\r
+  @param Str                    The file name to set.\r
+  \r
+  @retval EFI_SUCCESS           The filename was successfully set.\r
+  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
+  @retval EFI_INVALID_PARAMETER Str is not a valid filename.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferSetFileName (\r
+  IN CONST CHAR16 *Str\r
+  );\r
+\r
+/**\r
+  Read a file from disk into the FileBuffer.\r
+  \r
+  @param[in] FileName           The filename to read.\r
+  @param[in] Recover            TRUE if is for recover mode, no information printouts.\r
+  \r
+  @retval EFI_SUCCESS            The load was successful.\r
+  @retval EFI_LOAD_ERROR         The load failed.\r
+  @retval EFI_OUT_OF_RESOURCES   A memory allocation failed.\r
+  @retval EFI_INVALID_PARAMETER  FileName is a directory.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferRead (\r
+  IN CONST CHAR16  *FileName,\r
+  IN CONST BOOLEAN Recover\r
+  );\r
+\r
+/**\r
+  Save lines in FileBuffer to disk\r
+\r
+  @param[in] FileName           The file name for writing.\r
+\r
+  @retval EFI_SUCCESS           Data was written.\r
+  @retval EFI_LOAD_ERROR        \r
+  @retval EFI_OUT_OF_RESOURCES  There were not enough resources to write the file.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferSave (\r
+  CONST CHAR16 *FileName\r
+  );\r
+\r
+/**\r
+  According to cursor's file position, adjust screen display\r
+\r
+  @param[in] NewFilePosRow    The row of file position ( start from 1 ).\r
+  @param[in] NewFilePosCol    The column of file position ( start from 1 ).\r
+**/\r
+VOID\r
+EFIAPI\r
+FileBufferMovePosition (\r
+  IN CONST UINTN NewFilePosRow,\r
+  IN CONST UINTN NewFilePosCol\r
+  );\r
+\r
+/**\r
+  Cut current line out and return a pointer to it.\r
+\r
+  @param[out] CutLine    Upon a successful return pointer to the pointer to \r
+                        the allocated cut line.\r
+\r
+  @retval EFI_SUCCESS             The cut was successful.\r
+  @retval EFI_NOT_FOUND           There was no selection to cut.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferCutLine (\r
+  OUT EFI_EDITOR_LINE **CutLine\r
+  );\r
+\r
+/**\r
+  Paste a line into line list.\r
+\r
+  @retval EFI_SUCCESS             The paste was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferPasteLine (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Search string from current position on in file\r
+\r
+  @param[in] Str    The search string.\r
+  @param[in] Offset The offset from current position.\r
+\r
+  @retval EFI_SUCCESS       The operation was successful.\r
+  @retval EFI_NOT_FOUND     The string Str was not found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferSearch (\r
+  IN CONST CHAR16  *Str,\r
+  IN CONST UINTN Offset\r
+  );\r
+\r
+/**\r
+  Replace SearchLen characters from current position on with Replace.\r
+\r
+  This will modify the current buffer at the current position.\r
+\r
+  @param[in] Replace    The string to replace.\r
+  @param[in] SearchLen  Search string's length.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferReplace (\r
+  IN CONST CHAR16   *Replace,\r
+  IN CONST UINTN    SearchLen\r
+  );\r
+\r
+/**\r
+  Search and replace operation.\r
+\r
+  @param[in] SearchStr    The string to search for.\r
+  @param[in] ReplaceStr   The string to replace with.\r
+  @param[in] Offset       The column to start at.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileBufferReplaceAll (\r
+  IN CHAR16 *SearchStr,\r
+  IN CHAR16 *ReplaceStr,\r
+  IN UINTN  Offset\r
+  );\r
+\r
+/**\r
+  Move the mouse cursor position.\r
+\r
+  @param[in] TextX      The new x-coordinate.\r
+  @param[in] TextY      The new y-coordinate.\r
+**/\r
+VOID\r
+EFIAPI\r
+FileBufferAdjustMousePosition (\r
+  IN CONST INT32 TextX,\r
+  IN CONST INT32 TextY\r
+  );\r
+\r
+/**\r
+  Set the modified state to TRUE.\r
+**/\r
+VOID\r
+EFIAPI\r
+FileBufferSetModified (\r
+  VOID\r
+  );\r
+\r
+#endif\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c
new file mode 100644 (file)
index 0000000..7749bdc
--- /dev/null
@@ -0,0 +1,1830 @@
+/** @file\r
+  Implements editor interface functions.\r
+\r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TextEditor.h"\r
+#include "EditStatusBar.h"\r
+#include "EditInputBar.h"\r
+\r
+/**\r
+  Load a file from disk to editor\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandOpenFile (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Switch a file from ASCII to UNICODE or vise-versa.\r
+\r
+  @retval EFI_SUCCESS           The switch was ok or a warning was presented.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandSwitchFileType (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  move cursor to specified lines\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandGotoLine (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Save current file to disk, you can save to current file name or\r
+  save to another file name.\r
+  \r
+  @retval EFI_SUCCESS           The file was saved correctly.\r
+  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A file access error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandSaveFile (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  exit editor\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandExit (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  search string in file buffer\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandSearch (\r
+  VOID\r
+  );\r
+\r
+/*\r
+  search string in file buffer, and replace it with another str\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandSearchReplace (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  cut current line to clipboard\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandCutLine (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  paste line to file buffer.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandPasteLine (\r
+  VOID\r
+  );\r
+\r
+EDITOR_MENU_ITEM  MainMenuItems[] = {\r
+  {\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_GO_TO_LINE),\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_F1),\r
+    MainCommandGotoLine\r
+  },\r
+  {\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_SAVE_FILE),\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_F2),\r
+    MainCommandSaveFile\r
+  },\r
+  {\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_EXIT),\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_F3),\r
+    MainCommandExit\r
+  },\r
+\r
+  {\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH),\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_F4),\r
+    MainCommandSearch\r
+  },\r
+  {\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH_REPLACE),\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_F5),\r
+    MainCommandSearchReplace\r
+  },\r
+  {\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_CUT_LINE),\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_F6),\r
+    MainCommandCutLine\r
+  },\r
+  {\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_PASTE_LINE),\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_F7),\r
+    MainCommandPasteLine\r
+  },\r
+\r
+  {\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_OPEN_FILE),\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_F8),\r
+    MainCommandOpenFile\r
+  },\r
+  {\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_FILE_TYPE),\r
+    STRING_TOKEN(STR_EDIT_LIBMENUBAR_F9),\r
+    MainCommandSwitchFileType\r
+  },\r
+\r
+  {\r
+    0,\r
+    0,\r
+    NULL\r
+  }\r
+};\r
+\r
+\r
+/**\r
+  Load a file from disk to editor\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandOpenFile (\r
+  VOID\r
+  )\r
+{\r
+  BOOLEAN     Done;\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  //  This command will open a file from current working directory.\r
+  //   Read-only file can also be opened. But it can not be modified.\r
+  // Below is the scenario of Open File command:\r
+  // 1.IF currently opened file has not been modIFied, directly go to step .\r
+  //   IF currently opened file has been modified,\r
+  //     an Input Bar will be prompted as :\r
+  //       "File Modified. Save ( Yes/No/Cancel) ?"\r
+  //           IF user press 'y' or 'Y', currently opened file will be saved.\r
+  //           IF user press 'n' or 'N', currently opened file will\r
+  //              not be saved.\r
+  //           IF user press 'c' or 'C' or ESC, Open File command ends and\r
+  //              currently opened file is still opened.\r
+  //\r
+  // 2.  An Input Bar will be prompted as :  "File Name to Open: "\r
+  //       IF user press ESC, Open File command ends and\r
+  //          currently opened file is still opened.\r
+  //       Any other inputs with a Return will\r
+  //          cause currently opened file close.\r
+  //\r
+  // 3.  IF user input file name is an existing file , this file will be read\r
+  //        and opened.\r
+  //    IF user input file name is a new file, this file will be created\r
+  //        and opened. This file's type ( UNICODE or ASCII ) is the same\r
+  //        with the old file.\r
+  // if current file is modified, so you need to choose\r
+  // whether to save it first.\r
+  //\r
+  if (MainEditor.FileBuffer->FileModified) {\r
+\r
+    Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? ");\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // the answer is just one character\r
+    //\r
+    Status = InputBarSetStringSize (1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // loop for user's answer\r
+    // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C'\r
+    //\r
+    Done = FALSE;\r
+    while (!Done) {\r
+      Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+      StatusBarSetRefresh();\r
+\r
+      //\r
+      // ESC pressed\r
+      //\r
+      if (Status == EFI_NOT_READY) {\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      switch (InputBarGetString()[0]) {\r
+      case L'y':\r
+      case L'Y':\r
+        //\r
+        // want to save this file first\r
+        //\r
+        Status = FileBufferSave (MainEditor.FileBuffer->FileName);\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+\r
+        MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);\r
+        FileBufferRestorePosition ();\r
+        Done = TRUE;\r
+        break;\r
+\r
+      case L'n':\r
+      case L'N':\r
+        //\r
+        // the file won't be saved\r
+        //\r
+        Done = TRUE;\r
+        break;\r
+\r
+      case L'c':\r
+      case L'C':\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // TO get the open file name\r
+  //\r
+  Status = InputBarSetPrompt (L"File Name to Open: ");\r
+  if (EFI_ERROR (Status)) {\r
+    FileBufferRead (MainEditor.FileBuffer->FileName, TRUE);\r
+    return Status;\r
+  }\r
+\r
+  Status = InputBarSetStringSize (100);\r
+  if (EFI_ERROR (Status)) {\r
+    FileBufferRead (MainEditor.FileBuffer->FileName, TRUE);\r
+    return Status;\r
+  }\r
+\r
+  while (1) {\r
+    Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+    StatusBarSetRefresh();\r
+\r
+    //\r
+    // ESC pressed\r
+    //\r
+    if (Status == EFI_NOT_READY) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // The input string length should > 0\r
+    //\r
+    if (StrLen (InputBarGetString()) > 0) {\r
+      //\r
+      // CHECK if filename is valid\r
+      //\r
+      if (!IsValidFileName (InputBarGetString())) {\r
+        FileBufferRead (MainEditor.FileBuffer->FileName, TRUE);\r
+        StatusBarSetStatusString (L"Invalid File Name");\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      break;\r
+    }\r
+  }\r
+  //\r
+  // read from disk\r
+  //\r
+  Status = FileBufferRead (InputBarGetString(), FALSE);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FileBufferRead (MainEditor.FileBuffer->FileName, TRUE);\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Switch a file from ASCII to UNICODE or vise-versa.\r
+\r
+  @retval EFI_SUCCESS           The switch was ok or a warning was presented.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandSwitchFileType (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // Below is the scenario of File Type command:\r
+  // After File Type is executed, file type will be changed to another type\r
+  // if file is read-only, can not be modified\r
+  //\r
+  if (MainEditor.FileBuffer->ReadOnly) {\r
+    StatusBarSetStatusString (L"Read Only File Can Not Be Modified");\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {\r
+    MainEditor.FileBuffer->FileType = FileTypeAscii;\r
+  } else {\r
+    MainEditor.FileBuffer->FileType = FileTypeUnicode;\r
+  }\r
+\r
+  MainEditor.FileBuffer->FileModified = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  cut current line to clipboard\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandCutLine (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  EFI_EDITOR_LINE *Line;\r
+\r
+  //\r
+  // This command will cut current line ( where cursor is on ) to clip board.\r
+  //      And cursor will move to the beginning of next line.\r
+  // Below is the scenario of Cut Line command:\r
+  // 1.  IF cursor is on valid line, current line will be cut to clip board.\r
+  //     IF cursor is not on valid line, an Status String will be prompted :\r
+  //        "Nothing to Cut".\r
+  //\r
+  Status = FileBufferCutLine (&Line);\r
+  if (Status == EFI_NOT_FOUND) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  MainEditor.CutLine = Line;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  paste line to file buffer.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandPasteLine (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Below is the scenario of Paste Line command:\r
+  // 1.  IF nothing is on clipboard, a Status String will be prompted :\r
+  //        "No Line to Paste" and Paste Line command ends.\r
+  //     IF something is on clipboard, insert it above current line.\r
+  // nothing on clipboard\r
+  //\r
+  if (MainEditor.CutLine == NULL) {\r
+    StatusBarSetStatusString (L"No Line to Paste");\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = FileBufferPasteLine ();\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  search string in file buffer\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandSearch (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  CHAR16      *Buffer;\r
+  BOOLEAN     Done;\r
+  UINTN       Offset;\r
+\r
+  //\r
+  // Below is the scenario of Search command:\r
+  // 1.  An Input Bar will be prompted : "Enter Search String:".\r
+  //       IF user press ESC, Search command ends.\r
+  //       IF user just press Enter, Search command ends.\r
+  //       IF user inputs the search string,  do Step 2.\r
+  //\r
+  // 2.  IF input search string is found, cursor will move to the first\r
+  //        occurrence and do Step 3.\r
+  //     IF input search string is not found, a Status String\r
+  //        "Search String Not Found" will be prompted and Search command ends.\r
+  //\r
+  // 3.  An Input Bar will be prompted: "Find Next (Yes/No/Cancel ) ?".\r
+  //      IF user press ESC, Search command ends.\r
+  //       IF user press 'y' or 'Y', do Step 2.\r
+  //       IF user press 'n' or 'N', Search command ends.\r
+  //       IF user press 'c' or 'C', Search command ends.\r
+  //\r
+  Status = InputBarSetPrompt (L"Enter Search String: ");\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = InputBarSetStringSize (40);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+  StatusBarSetRefresh();\r
+\r
+  //\r
+  // ESC\r
+  //\r
+  if (Status == EFI_NOT_READY) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // just enter pressed\r
+  //\r
+  if (StrLen (InputBarGetString()) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Buffer = CatSPrint (NULL, L"%s", InputBarGetString());\r
+  if (Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // the first time , search from current position\r
+  //\r
+  Offset = 0;\r
+  do {\r
+    //\r
+    // since search may be continued to search multiple times\r
+    // so we need to backup editor each time\r
+    //\r
+    MainEditorBackup ();\r
+\r
+    Status = FileBufferSearch (Buffer, Offset);\r
+\r
+    if (Status == EFI_NOT_FOUND) {\r
+      break;\r
+    }\r
+    //\r
+    // Find next\r
+    //\r
+    Status = InputBarSetPrompt (L"Find Next (Yes/No) ?");\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Buffer);\r
+      return Status;\r
+    }\r
+\r
+    Status = InputBarSetStringSize (1);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Buffer);\r
+      return Status;\r
+    }\r
+\r
+    Done = FALSE;\r
+    while (!Done) {\r
+      Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+      StatusBarSetRefresh();\r
+\r
+      //\r
+      // ESC pressed\r
+      //\r
+      if (Status == EFI_NOT_READY) {\r
+        FreePool (Buffer);\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      switch (InputBarGetString()[0]) {\r
+      case L'y':\r
+      case L'Y':\r
+        Done = TRUE;\r
+        break;\r
+\r
+      case L'n':\r
+      case L'N':\r
+        FreePool (Buffer);\r
+        return EFI_SUCCESS;\r
+\r
+      }\r
+      //\r
+      // end of which\r
+      //\r
+    }\r
+    //\r
+    // end of while !Done\r
+    // for search second, third time, search from current position + strlen\r
+    //\r
+    Offset = StrLen (Buffer);\r
+\r
+  } while (1);\r
+  //\r
+  // end of do\r
+  //\r
+  FreePool (Buffer);\r
+  StatusBarSetStatusString (L"Search String Not Found");\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/*\r
+  search string in file buffer, and replace it with another str\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandSearchReplace (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  CHAR16      *Search;\r
+  CHAR16      *Replace;\r
+  BOOLEAN     Done;\r
+  BOOLEAN     First;\r
+  BOOLEAN     ReplaceOption;\r
+  UINTN       SearchLen;\r
+  UINTN       ReplaceLen;\r
+  BOOLEAN     ReplaceAll;\r
+\r
+  ReplaceOption = FALSE;\r
+\r
+  //\r
+  // Below is the scenario of Search/Replace command:\r
+  // 1.  An Input Bar is prompted : "Enter Search String:".\r
+  //       IF user press ESC, Search/Replace command ends.\r
+  //       IF user just press Enter, Search/Replace command ends.\r
+  //       IF user inputs the search string S, do Step 2.\r
+  //\r
+  // 2.  An Input Bar is prompted: "Replace With:".\r
+  //       IF user press ESC, Search/Replace command ends.\r
+  //      IF user inputs the replace string R, do Step 3.\r
+  //\r
+  // 3.  IF input search string is not found, an Status String\r
+  //        "Search String Not Found" will be prompted\r
+  //        and Search/Replace command ends\r
+  //     IF input search string is found, do Step 4.\r
+  //\r
+  // 4.  An Input Bar will be prompted: "Replace ( Yes/No/All/Cancel )?"\r
+  //       IF user press 'y' or 'Y', S will be replaced with R and do Step 5\r
+  //       IF user press 'n' or 'N', S will not be replaced and do Step 5.\r
+  //       IF user press 'a' or 'A', all the S from file current position on\r
+  //          will be replaced with R and Search/Replace command ends.\r
+  //       IF user press 'c' or 'C' or ESC, Search/Replace command ends.\r
+  //\r
+  // 5.  An Input Bar will be prompted: "Find Next (Yes/No/Cancel) ?".\r
+  //       IF user press ESC, Search/Replace command ends.\r
+  //       IF user press 'y' or 'Y', do Step 3.\r
+  //       IF user press 'n' or 'N', Search/Replace command ends.\r
+  //       IF user press 'c' or 'C', Search/Replace command ends.\r
+  // input search string\r
+  //\r
+  Status = InputBarSetPrompt (L"Enter Search String: ");\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = InputBarSetStringSize (40);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+  StatusBarSetRefresh();\r
+\r
+  //\r
+  // ESC\r
+  //\r
+  if (Status == EFI_NOT_READY) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // if just pressed enter\r
+  //\r
+  if (StrLen (InputBarGetString()) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Search = CatSPrint (NULL, L"%s", InputBarGetString());\r
+  if (Search == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  SearchLen = StrLen (Search);\r
+\r
+  //\r
+  // input replace string\r
+  //\r
+  Status = InputBarSetPrompt (L"Replace With: ");\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = InputBarSetStringSize (40);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+  StatusBarSetRefresh();\r
+\r
+  //\r
+  // ESC\r
+  //\r
+  if (Status == EFI_NOT_READY) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Replace = CatSPrint (NULL, L"%s", InputBarGetString());\r
+  if (Replace == NULL) {\r
+    FreePool (Search);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ReplaceLen  = StrLen (Replace);\r
+\r
+  First       = TRUE;\r
+  ReplaceAll  = FALSE;\r
+  do {\r
+    //\r
+    // since search may be continued to search multiple times\r
+    // so we need to backup editor each time\r
+    //\r
+    MainEditorBackup ();\r
+\r
+    if (First) {\r
+      Status = FileBufferSearch (Search, 0);\r
+    } else {\r
+      //\r
+      // if just replace, so skip this replace string\r
+      // if replace string is an empty string, so skip to next character\r
+      //\r
+      if (ReplaceOption) {\r
+        Status = FileBufferSearch (Search, (ReplaceLen == 0) ? 1 : ReplaceLen);\r
+      } else {\r
+        Status = FileBufferSearch (Search, SearchLen);\r
+      }\r
+    }\r
+\r
+    if (Status == EFI_NOT_FOUND) {\r
+      break;\r
+    }\r
+    //\r
+    // replace or not?\r
+    //\r
+    Status = InputBarSetPrompt (L"Replace (Yes/No/All/Cancel) ?");\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Search);\r
+      FreePool (Replace);\r
+      return Status;\r
+    }\r
+\r
+    Status = InputBarSetStringSize (1);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Search);\r
+      FreePool (Replace);\r
+      return Status;\r
+    }\r
+\r
+    Done = FALSE;\r
+    while (!Done) {\r
+      Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+      StatusBarSetRefresh();\r
+\r
+      //\r
+      // ESC pressed\r
+      //\r
+      if (Status == EFI_NOT_READY) {\r
+        FreePool (Search);\r
+        FreePool (Replace);\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      switch (InputBarGetString()[0]) {\r
+      case L'y':\r
+      case L'Y':\r
+        Done          = TRUE;\r
+        ReplaceOption = TRUE;\r
+        break;\r
+\r
+      case L'n':\r
+      case L'N':\r
+        Done          = TRUE;\r
+        ReplaceOption = FALSE;\r
+        break;\r
+\r
+      case L'a':\r
+      case L'A':\r
+        Done          = TRUE;\r
+        ReplaceOption = TRUE;\r
+        ReplaceAll    = TRUE;\r
+        break;\r
+\r
+      case L'c':\r
+      case L'C':\r
+        FreePool (Search);\r
+        FreePool (Replace);\r
+        return EFI_SUCCESS;\r
+\r
+      }\r
+      //\r
+      // end of which\r
+      //\r
+    }\r
+    //\r
+    // end of while !Done\r
+    // Decide to Replace\r
+    //\r
+    if (ReplaceOption) {\r
+      //\r
+      // file is read-only\r
+      //\r
+      if (MainEditor.FileBuffer->ReadOnly) {\r
+        StatusBarSetStatusString (L"Read Only File Can Not Be Modified");\r
+        return EFI_SUCCESS;\r
+      }\r
+      //\r
+      // replace all\r
+      //\r
+      if (ReplaceAll) {\r
+        Status = FileBufferReplaceAll (Search, Replace, 0);\r
+        FreePool (Search);\r
+        FreePool (Replace);\r
+        return Status;\r
+      }\r
+      //\r
+      // replace\r
+      //\r
+      Status = FileBufferReplace (Replace, SearchLen);\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (Search);\r
+        FreePool (Replace);\r
+        return Status;\r
+      }\r
+    }\r
+    //\r
+    // Find next\r
+    //\r
+    Status = InputBarSetPrompt (L"Find Next (Yes/No) ?");\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Search);\r
+      FreePool (Replace);\r
+      return Status;\r
+    }\r
+\r
+    Status = InputBarSetStringSize (1);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Search);\r
+      FreePool (Replace);\r
+      return Status;\r
+    }\r
+\r
+    Done = FALSE;\r
+    while (!Done) {\r
+      Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+      StatusBarSetRefresh();\r
+\r
+      //\r
+      // ESC pressed\r
+      //\r
+      if (Status == EFI_NOT_READY) {\r
+        FreePool (Search);\r
+        FreePool (Replace);\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      switch (InputBarGetString()[0]) {\r
+      case L'y':\r
+      case L'Y':\r
+        Done = TRUE;\r
+        break;\r
+\r
+      case L'n':\r
+      case L'N':\r
+        FreePool (Search);\r
+        FreePool (Replace);\r
+        return EFI_SUCCESS;\r
+\r
+      }\r
+      //\r
+      // end of which\r
+      //\r
+    }\r
+    //\r
+    // end of while !Done\r
+    //\r
+    First = FALSE;\r
+\r
+  } while (1);\r
+  //\r
+  // end of do\r
+  //\r
+  FreePool (Search);\r
+  FreePool (Replace);\r
+\r
+  StatusBarSetStatusString (L"Search String Not Found");\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  exit editor\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandExit (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Below is the scenario of Exit command:\r
+  // 1.  IF currently opened file is not modified, exit the editor and\r
+  //        Exit command ends.\r
+  //     IF currently opened file is modified, do Step 2\r
+  //\r
+  // 2.  An Input Bar will be prompted:\r
+  //        "File modified. Save ( Yes/No/Cancel )?"\r
+  //       IF user press 'y' or 'Y', currently opened file will be saved\r
+  //          and Editor exits\r
+  //       IF user press 'n' or 'N', currently opened file will not be saved\r
+  //          and Editor exits.\r
+  //       IF user press 'c' or 'C' or ESC, Exit command ends.\r
+  // if file has been modified, so will prompt user whether to save the changes\r
+  //\r
+  if (MainEditor.FileBuffer->FileModified) {\r
+\r
+    Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? ");\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = InputBarSetStringSize (1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    while (1) {\r
+      Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+      StatusBarSetRefresh();\r
+\r
+      //\r
+      // ESC pressed\r
+      //\r
+      if (Status == EFI_NOT_READY) {\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      switch (InputBarGetString()[0]) {\r
+      case L'y':\r
+      case L'Y':\r
+        //\r
+        // write file back to disk\r
+        //\r
+        Status = FileBufferSave (MainEditor.FileBuffer->FileName);\r
+        if (!EFI_ERROR (Status)) {\r
+          EditorExit = TRUE;\r
+        }\r
+\r
+        return Status;\r
+\r
+      case L'n':\r
+      case L'N':\r
+        EditorExit = TRUE;\r
+        return EFI_SUCCESS;\r
+\r
+      case L'c':\r
+      case L'C':\r
+        return EFI_SUCCESS;\r
+\r
+      }\r
+    }\r
+  }\r
+\r
+  EditorExit = TRUE;\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+  move cursor to specified lines\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandGotoLine (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Row;\r
+\r
+  //\r
+  // Below is the scenario of Go To Line command:\r
+  // 1.  An Input Bar will be prompted : "Go To Line:".\r
+  //       IF user press ESC, Go To Line command ends.\r
+  //       IF user just press Enter, cursor remains unchanged.\r
+  //       IF user inputs line number, do Step 2.\r
+  //\r
+  // 2.  IF input line number is valid, move cursor to the beginning\r
+  //        of specified line and Go To Line command ends.\r
+  //    IF input line number is invalid, a Status String will be prompted:\r
+  //        "No Such Line" and Go To Line command ends.\r
+  //\r
+  Status = InputBarSetPrompt (L"Go To Line: ");\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // line number's digit <= 6\r
+  //\r
+  Status = InputBarSetStringSize (6);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+  StatusBarSetRefresh();\r
+\r
+  //\r
+  // press ESC\r
+  //\r
+  if (Status == EFI_NOT_READY) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // if JUST press enter\r
+  //\r
+  if (StrLen (InputBarGetString()) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Row = ShellStrToUintn (InputBarGetString());\r
+\r
+  //\r
+  // invalid line number\r
+  //\r
+  if (Row > MainEditor.FileBuffer->NumLines || Row <= 0) {\r
+    StatusBarSetStatusString (L"No Such Line");\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // move cursor to that line's start\r
+  //\r
+  FileBufferMovePosition (Row, 1);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Save current file to disk, you can save to current file name or\r
+  save to another file name.\r
+  \r
+  @retval EFI_SUCCESS           The file was saved correctly.\r
+  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
+  @retval EFI_LOAD_ERROR          A file access error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainCommandSaveFile (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  CHAR16            *FileName;\r
+  BOOLEAN           OldFile;\r
+  CHAR16            *Str;\r
+  SHELL_FILE_HANDLE FileHandle;  \r
+  EFI_FILE_INFO     *Info;\r
+\r
+  //\r
+  // This command will save currently opened file to disk.\r
+  // You can choose save to another file name or just save to\r
+  //    current file name.\r
+  // Below is the scenario of Save File command:\r
+  //    ( Suppose the old file name is A )\r
+  // 1.  An Input Bar will be prompted:    "File To Save: [ old file name]"\r
+  //     IF user press ESC, Save File command ends .\r
+  //     IF user press Enter, input file name will be A.\r
+  //     IF user inputs a new file name B,  input file name will be B.\r
+  //\r
+  // 2.  IF input file name is A, go to do Step 3.\r
+  //     IF input file name is B, go to do Step 4.\r
+  //\r
+  // 3.  IF A is read only, Status Bar will show "Access Denied" and\r
+  //       Save File commands ends.\r
+  //     IF A is not read only, save file buffer to disk and remove modified\r
+  //       flag in Title Bar , then Save File command ends.\r
+  //\r
+  // 4.  IF B does not exist, create this file and save file buffer to it.\r
+  //       Go to do Step 7.\r
+  //     IF B exits, do Step 5.\r
+  //\r
+  // 5.An Input Bar will be prompted:\r
+  //      "File Exists. Overwrite ( Yes/No/Cancel )?"\r
+  //       IF user press 'y' or 'Y', do Step 6.\r
+  //       IF user press 'n' or 'N', Save File commands ends.\r
+  //       IF user press 'c' or 'C' or ESC, Save File commands ends.\r
+  //\r
+  // 6. IF B is a read-only file, Status Bar will show "Access Denied" and\r
+  //       Save File commands ends.\r
+  //    IF B can be read and write, save file buffer to B.\r
+  //\r
+  // 7.  Update File Name field in Title Bar to B and remove the modified\r
+  //       flag in Title Bar.\r
+  //\r
+  Str = CatSPrint (NULL, L"File to Save: [%s]", MainEditor.FileBuffer->FileName);\r
+  if (Str == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (StrLen (Str) >= 50) {\r
+    //\r
+    // replace the long file name with "..."\r
+    //\r
+    Str[46] = L'.';\r
+    Str[47] = L'.';\r
+    Str[48] = L'.';\r
+    Str[49] = L']';\r
+    Str[50] = CHAR_NULL;\r
+  }\r
+\r
+  Status = InputBarSetPrompt (Str);\r
+  FreePool(Str);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+\r
+  Status = InputBarSetStringSize (100);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // get new file name\r
+  //\r
+  Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+  StatusBarSetRefresh();\r
+\r
+  //\r
+  // if user pressed ESC\r
+  //\r
+  if (Status == EFI_NOT_READY) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // if just enter pressed, so think save to current file name\r
+  //\r
+  if (StrLen (InputBarGetString()) == 0) {\r
+    FileName = CatSPrint (NULL, L"%s", MainEditor.FileBuffer->FileName);\r
+  } else {\r
+    FileName = CatSPrint (NULL, L"%s", InputBarGetString());\r
+  }\r
+\r
+  if (FileName == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (!IsValidFileName (FileName)) {\r
+    StatusBarSetStatusString (L"Invalid File Name");\r
+    FreePool (FileName);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  OldFile = FALSE;\r
+\r
+  //\r
+  // save to the old file\r
+  //\r
+  if (StringNoCaseCompare (&FileName, &MainEditor.FileBuffer->FileName) == 0) {\r
+    OldFile = TRUE;\r
+  }\r
+\r
+  if (OldFile) {\r
+    //\r
+    // if the file is read only, so can not write back to it.\r
+    //\r
+    if (MainEditor.FileBuffer->ReadOnly == TRUE) {\r
+      StatusBarSetStatusString (L"Access Denied");\r
+      FreePool (FileName);\r
+      return EFI_SUCCESS;\r
+    }\r
+  } else {\r
+    //\r
+    // if the file exists\r
+    //\r
+    if (ShellFileExists(FileName) != EFI_NOT_FOUND) {\r
+      //\r
+      // check for read only\r
+      //\r
+      Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0);\r
+      if (EFI_ERROR(Status)) {\r
+        StatusBarSetStatusString (L"Open Failed");\r
+        FreePool (FileName);\r
+        return EFI_SUCCESS;\r
+      } \r
+\r
+      Info = ShellGetFileInfo(FileHandle);\r
+      if (Info == NULL) {\r
+        StatusBarSetStatusString (L"Access Denied");\r
+        FreePool (FileName);\r
+        return (EFI_SUCCESS);\r
+      } \r
+      \r
+      if (Info->Attribute & EFI_FILE_READ_ONLY) {\r
+        StatusBarSetStatusString (L"Access Denied - Read Only");\r
+        FreePool (Info);\r
+        FreePool (FileName);\r
+        return (EFI_SUCCESS);\r
+      }\r
+      FreePool (Info);\r
+\r
+      //\r
+      // ask user whether to overwrite this file\r
+      //\r
+      Status = InputBarSetPrompt (L"File exists. Overwrite (Yes/No/Cancel) ? ");\r
+      if (EFI_ERROR (Status)) {\r
+        SHELL_FREE_NON_NULL (FileName);\r
+        return Status;\r
+      }\r
+\r
+      Status = InputBarSetStringSize (1);\r
+      if (EFI_ERROR (Status)) {\r
+        SHELL_FREE_NON_NULL (FileName);\r
+        return Status;\r
+      }\r
+\r
+      while (TRUE) {\r
+        Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+        StatusBarSetRefresh();\r
+\r
+        //\r
+        // ESC pressed\r
+        //\r
+        if (Status == EFI_NOT_READY) {\r
+          SHELL_FREE_NON_NULL (FileName);\r
+          return EFI_SUCCESS;\r
+        }\r
+\r
+        switch (InputBarGetString()[0]) {\r
+        case L'y':\r
+        case L'Y':\r
+          break;\r
+\r
+        case L'n':\r
+        case L'N':\r
+        case L'c':\r
+        case L'C':\r
+          SHELL_FREE_NON_NULL (FileName);\r
+          return EFI_SUCCESS;\r
+        } // end switch\r
+      } // while (!done)\r
+    } // file does exist\r
+  } // if old file name same\r
+\r
+  //\r
+  // save file to disk with specified name\r
+  //\r
+  FileBufferSetModified();\r
+  Status = FileBufferSave (FileName);\r
+  SHELL_FREE_NON_NULL (FileName);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_EDITOR_COLOR_ATTRIBUTES   OriginalColors;\r
+INTN                          OriginalMode;\r
+\r
+//\r
+// the first time editor launch\r
+//\r
+BOOLEAN                       EditorFirst;\r
+\r
+//\r
+// it's time editor should exit\r
+//\r
+BOOLEAN                       EditorExit;\r
+\r
+BOOLEAN                       EditorMouseAction;\r
+\r
+extern EFI_EDITOR_FILE_BUFFER FileBuffer;\r
+\r
+extern BOOLEAN                FileBufferMouseNeedRefresh;\r
+\r
+extern EFI_EDITOR_FILE_BUFFER FileBufferBackupVar;\r
+\r
+EFI_EDITOR_GLOBAL_EDITOR      MainEditor;\r
+\r
+//\r
+// basic initialization for MainEditor\r
+//\r
+EFI_EDITOR_GLOBAL_EDITOR      MainEditorConst = {\r
+  &FileBuffer,\r
+  {\r
+    0,\r
+    0\r
+  },\r
+  {\r
+    0,\r
+    0\r
+  },\r
+  NULL,\r
+  FALSE,\r
+  NULL\r
+};\r
+\r
+/**\r
+  The initialization function for MainEditor.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainEditorInit (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_HANDLE  *HandleBuffer;\r
+  UINTN       HandleCount;\r
+  UINTN       Index;\r
+\r
+  //\r
+  // basic initialization\r
+  //\r
+  CopyMem (&MainEditor, &MainEditorConst, sizeof (MainEditor));\r
+\r
+  //\r
+  // set screen attributes\r
+  //\r
+  MainEditor.ColorAttributes.Colors.Foreground  = gST->ConOut->Mode->Attribute & 0x000000ff;\r
+\r
+  MainEditor.ColorAttributes.Colors.Background  = (UINT8) (gST->ConOut->Mode->Attribute >> 4);\r
+  OriginalColors = MainEditor.ColorAttributes.Colors;\r
+\r
+  OriginalMode = gST->ConOut->Mode->Mode;\r
+\r
+  //\r
+  // query screen size\r
+  //\r
+  gST->ConOut->QueryMode (\r
+        gST->ConOut,\r
+        gST->ConOut->Mode->Mode,\r
+        &(MainEditor.ScreenSize.Column),\r
+        &(MainEditor.ScreenSize.Row)\r
+        );\r
+\r
+  //\r
+  // Find mouse in System Table ConsoleInHandle\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                gST->ConIn,\r
+                &gEfiSimplePointerProtocolGuid,\r
+                (VOID**)&MainEditor.MouseInterface\r
+                );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // If there is no Simple Pointer Protocol on System Table\r
+    //\r
+    HandleBuffer = NULL;\r
+    MainEditor.MouseInterface = NULL;\r
+    Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiSimplePointerProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+    if (!EFI_ERROR (Status) && HandleCount > 0) {\r
+      //\r
+      // Try to find the first available mouse device\r
+      //\r
+      for (Index = 0; Index < HandleCount; Index++) {\r
+        Status = gBS->HandleProtocol (\r
+                      HandleBuffer[Index],\r
+                      &gEfiSimplePointerProtocolGuid,\r
+                      (VOID**)&MainEditor.MouseInterface\r
+                      );\r
+        if (!EFI_ERROR (Status)) {\r
+          break;\r
+        }\r
+      }\r
+    }\r
+    if (HandleBuffer != NULL) {\r
+      FreePool (HandleBuffer);\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status) && MainEditor.MouseInterface != NULL) {\r
+    MainEditor.MouseAccumulatorX  = 0;\r
+    MainEditor.MouseAccumulatorY  = 0;\r
+    MainEditor.MouseSupported     = TRUE;\r
+  }\r
+\r
+  //\r
+  // below will call the five components' init function\r
+  //\r
+  Status = MainTitleBarInit (L"UEFI EDIT 2.0");\r
+  if (EFI_ERROR (Status)) {\r
+    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_TITLEBAR), gShellDebug1HiiHandle);\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  Status = MenuBarInit (MainMenuItems);\r
+  if (EFI_ERROR (Status)) {\r
+    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_MAINMENU), gShellDebug1HiiHandle);\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  Status = StatusBarInit ();\r
+  if (EFI_ERROR (Status)) {\r
+    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_STATUSBAR), gShellDebug1HiiHandle);\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  InputBarInit ();\r
+\r
+  Status = FileBufferInit ();\r
+  if (EFI_ERROR (Status)) {\r
+    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER), gShellDebug1HiiHandle);\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+  //\r
+  // clear whole screen and enable cursor\r
+  //\r
+  gST->ConOut->ClearScreen (gST->ConOut);\r
+  gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+\r
+  //\r
+  // initialize EditorFirst and EditorExit\r
+  //\r
+  EditorFirst       = TRUE;\r
+  EditorExit        = FALSE;\r
+  EditorMouseAction = FALSE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The cleanup function for MainEditor.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainEditorCleanup (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // call the five components' cleanup function\r
+  // if error, do not exit\r
+  // just print some warning\r
+  //\r
+  MainTitleBarCleanup();\r
+  StatusBarCleanup();\r
+  InputBarCleanup();\r
+  MenuBarCleanup ();\r
+\r
+  Status = FileBufferCleanup ();\r
+  if (EFI_ERROR (Status)) {\r
+    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP), gShellDebug1HiiHandle);\r
+  }\r
+  //\r
+  // restore old mode\r
+  //\r
+  if (OriginalMode != gST->ConOut->Mode->Mode) {\r
+    gST->ConOut->SetMode (gST->ConOut, OriginalMode);\r
+  }\r
+  //\r
+  // restore old screen color\r
+  //\r
+  gST->ConOut->SetAttribute (\r
+        gST->ConOut,\r
+        EFI_TEXT_ATTR (OriginalColors.Foreground, OriginalColors.Background)\r
+        );\r
+\r
+  gST->ConOut->ClearScreen (gST->ConOut);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Refresh the main editor component.\r
+**/\r
+VOID\r
+EFIAPI\r
+MainEditorRefresh (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // The Stall value is from experience. NOT from spec.  avoids 'flicker'\r
+  //\r
+  gBS->Stall (50);\r
+\r
+  //\r
+  // call the components refresh function\r
+  //\r
+  if (EditorFirst \r
+    || StrCmp (FileBufferBackupVar.FileName, FileBuffer.FileName) != 0 \r
+    || FileBufferBackupVar.FileType != FileBuffer.FileType \r
+    || FileBufferBackupVar.FileModified != FileBuffer.FileModified \r
+    || FileBufferBackupVar.ReadOnly != FileBuffer.ReadOnly) {\r
+\r
+    MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);\r
+    FileBufferRestorePosition ();\r
+    FileBufferRefresh ();\r
+  }\r
+  if (EditorFirst\r
+    || FileBufferBackupVar.FilePosition.Row != FileBuffer.FilePosition.Row \r
+    || FileBufferBackupVar.FilePosition.Column != FileBuffer.FilePosition.Column \r
+    || FileBufferBackupVar.ModeInsert != FileBuffer.ModeInsert\r
+    || StatusBarGetRefresh()) {\r
+\r
+    StatusBarRefresh (EditorFirst, MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column, MainEditor.FileBuffer->FilePosition.Row, MainEditor.FileBuffer->FilePosition.Column, MainEditor.FileBuffer->ModeInsert);\r
+    FileBufferRestorePosition ();\r
+    FileBufferRefresh ();\r
+  }\r
+\r
+  if (EditorFirst) {\r
+    MenuBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);\r
+    FileBufferRestorePosition ();\r
+  }\r
+\r
+  //\r
+  // EditorFirst is now set to FALSE\r
+  //\r
+  EditorFirst = FALSE;\r
+}\r
+\r
+/**\r
+  Get's the resultant location of the cursor based on the relative movement of the Mouse.\r
+\r
+  @param[in] GuidX    The relative mouse movement.\r
+\r
+  @return The X location of the mouse.\r
+**/\r
+INT32\r
+EFIAPI\r
+GetTextX (\r
+  IN INT32 GuidX\r
+  )\r
+{\r
+  INT32 Gap;\r
+\r
+  MainEditor.MouseAccumulatorX += GuidX;\r
+  Gap = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX);\r
+  MainEditor.MouseAccumulatorX = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX);\r
+  MainEditor.MouseAccumulatorX = MainEditor.MouseAccumulatorX / (INT32) MainEditor.ScreenSize.Column;\r
+  return Gap;\r
+}\r
+\r
+/**\r
+  Get's the resultant location of the cursor based on the relative movement of the Mouse.\r
+\r
+  @param[in] GuidY    The relative mouse movement.\r
+\r
+  @return The Y location of the mouse.\r
+**/\r
+INT32\r
+EFIAPI\r
+GetTextY (\r
+  IN INT32 GuidY\r
+  )\r
+{\r
+  INT32 Gap;\r
+\r
+  MainEditor.MouseAccumulatorY += GuidY;\r
+  Gap = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY);\r
+  MainEditor.MouseAccumulatorY = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY);\r
+  MainEditor.MouseAccumulatorY = MainEditor.MouseAccumulatorY / (INT32) MainEditor.ScreenSize.Row;\r
+\r
+  return Gap;\r
+}\r
+\r
+/**\r
+  Support mouse movement.  Move the cursor.\r
+\r
+  @param[in] MouseState     The current mouse state.\r
+\r
+  @retval EFI_SUCCESS       The operation was successful.\r
+  @retval EFI_NOT_FOUND     There was no mouse support found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+MainEditorHandleMouseInput (\r
+  IN EFI_SIMPLE_POINTER_STATE       MouseState\r
+  )\r
+{\r
+\r
+  INT32           TextX;\r
+  INT32           TextY;\r
+  UINTN           FRow;\r
+  UINTN           FCol;\r
+\r
+  LIST_ENTRY  *Link;\r
+  EFI_EDITOR_LINE *Line;\r
+\r
+  UINTN           Index;\r
+  BOOLEAN         Action;\r
+\r
+  //\r
+  // mouse action means:\r
+  //    mouse movement\r
+  //    mouse left button\r
+  //\r
+  Action = FALSE;\r
+\r
+  //\r
+  // have mouse movement\r
+  //\r
+  if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) {\r
+    //\r
+    // handle\r
+    //\r
+    TextX = GetTextX (MouseState.RelativeMovementX);\r
+    TextY = GetTextY (MouseState.RelativeMovementY);\r
+\r
+    FileBufferAdjustMousePosition (TextX, TextY);\r
+\r
+    Action = TRUE;\r
+\r
+  }\r
+\r
+  //\r
+  // if left button pushed down\r
+  //\r
+  if (MouseState.LeftButton) {\r
+\r
+    FCol = MainEditor.FileBuffer->MousePosition.Column - 1 + 1;\r
+\r
+    FRow = MainEditor.FileBuffer->FilePosition.Row +\r
+      MainEditor.FileBuffer->MousePosition.Row -\r
+      MainEditor.FileBuffer->DisplayPosition.Row;\r
+\r
+    //\r
+    // beyond the file line length\r
+    //\r
+    if (MainEditor.FileBuffer->NumLines < FRow) {\r
+      FRow = MainEditor.FileBuffer->NumLines;\r
+    }\r
+\r
+    Link = MainEditor.FileBuffer->ListHead->ForwardLink;\r
+    for (Index = 0; Index < FRow - 1; Index++) {\r
+      Link = Link->ForwardLink;\r
+    }\r
+\r
+    Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);\r
+\r
+    //\r
+    // beyond the line's column length\r
+    //\r
+    if (FCol > Line->Size + 1) {\r
+      FCol = Line->Size + 1;\r
+    }\r
+\r
+    FileBufferMovePosition (FRow, FCol);\r
+\r
+    MainEditor.FileBuffer->MousePosition.Row    = MainEditor.FileBuffer->DisplayPosition.Row;\r
+\r
+    MainEditor.FileBuffer->MousePosition.Column = MainEditor.FileBuffer->DisplayPosition.Column;\r
+\r
+    Action = TRUE;\r
+  }\r
+  //\r
+  // mouse has action\r
+  //\r
+  if (Action) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // no mouse action\r
+  //\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Handle user key input. This routes to other functions for the actions.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainEditorKeyInput (\r
+  VOID\r
+  )\r
+{\r
+  EFI_INPUT_KEY             Key;\r
+  EFI_STATUS                Status;\r
+  EFI_SIMPLE_POINTER_STATE  MouseState;\r
+\r
+  do {\r
+\r
+    Status            = EFI_SUCCESS;\r
+    EditorMouseAction = FALSE;\r
+\r
+    //\r
+    // backup some key elements, so that can aVOID some refresh work\r
+    //\r
+    MainEditorBackup ();\r
+\r
+    //\r
+    // change priority of checking mouse/keyboard activity dynamically\r
+    // so prevent starvation of keyboard.\r
+    // if last time, mouse moves then this time check keyboard\r
+    //\r
+    if (MainEditor.MouseSupported) {\r
+      Status = MainEditor.MouseInterface->GetState (\r
+                                            MainEditor.MouseInterface,\r
+                                            &MouseState\r
+                                            );\r
+      if (!EFI_ERROR (Status)) {\r
+\r
+        Status = MainEditorHandleMouseInput (MouseState);\r
+\r
+        if (!EFI_ERROR (Status)) {\r
+          EditorMouseAction           = TRUE;\r
+          FileBufferMouseNeedRefresh  = TRUE;\r
+        } else if (Status == EFI_LOAD_ERROR) {\r
+          StatusBarSetStatusString (L"Invalid Mouse Movement ");\r
+        }\r
+      }\r
+    }\r
+\r
+    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // dispatch to different components' key handling function\r
+      // so not everywhere has to set this variable\r
+      //\r
+      FileBufferMouseNeedRefresh = TRUE;\r
+      //\r
+      // clear previous status string\r
+      //\r
+      StatusBarSetRefresh();\r
+\r
+      //\r
+      // dispatch to different components' key handling function\r
+      //\r
+      if ((Key.ScanCode == SCAN_NULL) || ((Key.ScanCode >= SCAN_UP) && (Key.ScanCode <= SCAN_PAGE_DOWN))) {\r
+        Status = FileBufferHandleInput (&Key);\r
+      } else if ((Key.ScanCode >= SCAN_F1) && (Key.ScanCode <= SCAN_F12)) {\r
+        Status = MenuBarDispatchFunctionKey (&Key);\r
+      } else {\r
+        StatusBarSetStatusString (L"Unknown Command");\r
+        FileBufferMouseNeedRefresh = FALSE;\r
+      }\r
+\r
+      if (Status != EFI_SUCCESS && Status != EFI_OUT_OF_RESOURCES) {\r
+        //\r
+        // not already has some error status\r
+        //\r
+        if (StatusBarGetString() != NULL && StrCmp (L"", StatusBarGetString()) == 0) {\r
+          StatusBarSetStatusString (L"Disk Error. Try Again");\r
+        }\r
+      }\r
+\r
+    }\r
+    //\r
+    // after handling, refresh editor\r
+    //\r
+    MainEditorRefresh ();\r
+\r
+  } while (Status != EFI_OUT_OF_RESOURCES && !EditorExit);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set clipboard\r
+\r
+  @param[in] Line   A pointer to the line to be set to clipboard\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainEditorSetCutLine (\r
+  EFI_EDITOR_LINE *Line\r
+  )\r
+{\r
+  if (Line == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (MainEditor.CutLine != NULL) {\r
+    //\r
+    // free the old clipboard\r
+    //\r
+    LineFree (MainEditor.CutLine);\r
+  }\r
+  //\r
+  // duplicate the line to clipboard\r
+  //\r
+  MainEditor.CutLine = LineDup (Line);\r
+  if (MainEditor.CutLine == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Backup function for MainEditor\r
+\r
+  @retval EFI_SUCCESS The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainEditorBackup (\r
+  VOID\r
+  )\r
+{\r
+  FileBufferBackup ();\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h
new file mode 100644 (file)
index 0000000..c45859d
--- /dev/null
@@ -0,0 +1,77 @@
+/** @file\r
+  Declares editor interface functions.\r
+\r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _LIB_EDITOR_H_\r
+#define _LIB_EDITOR_H_\r
+\r
+#include "TextEditorTypes.h"\r
+\r
+/**\r
+  The initialization function for MainEditor.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainEditorInit (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  The cleanup function for MainEditor.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainEditorCleanup (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Refresh the main editor component.\r
+**/\r
+VOID\r
+EFIAPI\r
+MainEditorRefresh (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Handle user key input. This routes to other functions for the actions.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_LOAD_ERROR          A load error occured.\r
+  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainEditorKeyInput (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Backup function for MainEditor\r
+\r
+  @retval EFI_SUCCESS The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MainEditorBackup (\r
+  VOID\r
+  );\r
+\r
+#endif\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c
new file mode 100644 (file)
index 0000000..ade78b8
--- /dev/null
@@ -0,0 +1,92 @@
+/** @file\r
+  Implementation of various string and line routines.\r
+\r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TextEditor.h"\r
+#include "Misc.h"\r
+\r
+/**\r
+  Duplicate a EFI_EDITOR_LINE structure.\r
+\r
+  @param Src                    The line structure to copy from.\r
+\r
+  @retval NULL                  A memory allocation failed.\r
+  @return                       a pointer to the newly allcoated line.\r
+**/\r
+EFI_EDITOR_LINE *\r
+EFIAPI\r
+LineDup (\r
+  IN  EFI_EDITOR_LINE *Src\r
+  )\r
+{\r
+  EFI_EDITOR_LINE *Dest;\r
+\r
+  //\r
+  // allocate for the line structure\r
+  //\r
+  Dest = AllocateZeroPool (sizeof (EFI_EDITOR_LINE));\r
+  if (Dest == NULL) {\r
+    return NULL;\r
+  }\r
+  //\r
+  // allocate and set the line buffer\r
+  //\r
+  Dest->Buffer = CatSPrint (NULL, L"%s", Src->Buffer);\r
+  if (Dest->Buffer == NULL) {\r
+    FreePool (Dest);\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // set the other structure members\r
+  //\r
+  Dest->Signature = LINE_LIST_SIGNATURE;\r
+  Dest->Size      = Src->Size;\r
+  Dest->TotalSize = Dest->Size;\r
+  Dest->Type      = Src->Type;\r
+  Dest->Link      = Src->Link;\r
+\r
+  return Dest;\r
+}\r
+\r
+/**\r
+  Free a EFI_EDITOR_LINE structure.\r
+\r
+  @param Src                    The line structure to free.\r
+**/\r
+VOID\r
+EFIAPI\r
+LineFree (\r
+  IN  EFI_EDITOR_LINE *Src\r
+  )\r
+{\r
+  if (Src == NULL) {\r
+    return ;\r
+  }\r
+  //\r
+  // free the line buffer and then the line structure itself\r
+  //\r
+  SHELL_FREE_NON_NULL (Src->Buffer);\r
+  SHELL_FREE_NON_NULL (Src);\r
+\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h
new file mode 100644 (file)
index 0000000..583de3b
--- /dev/null
@@ -0,0 +1,52 @@
+/** @file\r
+  Declares generic editor helper functions.\r
+\r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _LIB_MISC_H_\r
+#define _LIB_MISC_H_\r
+\r
+#include "TextEditorTypes.h"\r
+\r
+\r
+\r
+/**\r
+  Free a EFI_EDITOR_LINE structure.\r
+\r
+  @param Src                    The line structure to free.\r
+**/\r
+VOID\r
+EFIAPI\r
+LineFree (\r
+  IN  EFI_EDITOR_LINE *Src\r
+  );\r
+\r
+/**\r
+  Duplicate a EFI_EDITOR_LINE structure.\r
+\r
+  @param Src                    The line structure to copy from.\r
+\r
+  @retval NULL                  A memory allocation failed.\r
+  @return                       a pointer to the newly allcoated line.\r
+**/\r
+EFI_EDITOR_LINE *\r
+EFIAPI\r
+LineDup (\r
+  IN  EFI_EDITOR_LINE *Src\r
+  );\r
+\r
+\r
+\r
+\r
+\r
+\r
+#endif\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni
new file mode 100644 (file)
index 0000000..09a0d47
Binary files /dev/null and b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni differ
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h
new file mode 100644 (file)
index 0000000..774f01a
--- /dev/null
@@ -0,0 +1,32 @@
+/** @file\r
+  Main include file for Edit shell Debug1 function.\r
+\r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_EDIT_H_\r
+#define _EFI_EDIT_H_\r
+\r
+#include "TextEditorTypes.h"\r
+\r
+#include "MainTextEditor.h"\r
+#include "FileBuffer.h"\r
+#include "EditTitleBar.h"\r
+#include "EditStatusBar.h"\r
+#include "EditInputBar.h"\r
+#include "EditMenuBar.h"\r
+#include "Misc.h"\r
+\r
+extern EFI_EDITOR_GLOBAL_EDITOR MainEditor;\r
+extern BOOLEAN                  EditorFirst;\r
+extern BOOLEAN                  EditorExit;\r
+\r
+#endif // _EFI_EDIT_H_\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h
new file mode 100644 (file)
index 0000000..9bcf39e
--- /dev/null
@@ -0,0 +1,102 @@
+/** @file\r
+  Declares editor types.\r
+\r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EDITOR_TYPE_H_\r
+#define _EDITOR_TYPE_H_\r
+\r
+#include "UefiShellDebug1CommandsLib.h"\r
+#include "EditTitleBar.h"\r
+#include "EditMenuBar.h"\r
+\r
+#define MIN_POOL_SIZE         125\r
+#define MAX_STRING_LENGTH     127\r
+\r
+typedef struct {\r
+  UINTN Row;\r
+  UINTN Column;\r
+} EFI_EDITOR_POSITION;\r
+\r
+typedef\r
+EFI_STATUS\r
+(*EFI_MENU_ITEM_FUNCTION) (\r
+  VOID\r
+  );\r
+\r
+typedef enum {\r
+  NewLineTypeDefault,\r
+  NewLineTypeLineFeed,\r
+  NewLineTypeCarriageReturn,\r
+  NewLineTypeCarriageReturnLineFeed,\r
+  NewLineTypeLineFeedCarriageReturn,\r
+  NewLineTypeUnknown\r
+} EE_NEWLINE_TYPE;\r
+\r
+#define LINE_LIST_SIGNATURE  'eell'\r
+typedef struct _EFI_EDITOR_LINE {\r
+  UINTN           Signature;\r
+  CHAR16          *Buffer;\r
+  UINTN           Size;                   // unit is Unicode\r
+  UINTN           TotalSize;              // unit is Unicode, exclude CHAR_NULL\r
+  EE_NEWLINE_TYPE Type;\r
+  LIST_ENTRY      Link;\r
+} EFI_EDITOR_LINE;\r
+\r
+typedef struct {\r
+  UINT32  Foreground : 4;\r
+  UINT32  Background : 4;\r
+} EFI_EDITOR_COLOR_ATTRIBUTES;\r
+\r
+typedef union {\r
+  EFI_EDITOR_COLOR_ATTRIBUTES Colors;\r
+  UINTN                       Data;\r
+} EFI_EDITOR_COLOR_UNION;\r
+\r
+typedef struct {\r
+  UINTN Columns;\r
+  UINTN Rows;\r
+} EFI_EDITOR_TEXT_MODE;\r
+\r
+typedef struct {\r
+  CHAR16                *FileName;        // file name current edited in editor\r
+  EDIT_FILE_TYPE        FileType;         // Unicode file or ASCII file\r
+  LIST_ENTRY            *ListHead;        // list head of lines\r
+  EFI_EDITOR_LINE       *Lines;           // lines of current file\r
+  UINTN                 NumLines;         // total line numbers\r
+  EFI_EDITOR_POSITION   DisplayPosition;  // cursor position in screen\r
+  EFI_EDITOR_POSITION   FilePosition;     // cursor position in file\r
+  EFI_EDITOR_POSITION   MousePosition;    // mouse position in screen\r
+  // file position of first byte displayed on screen\r
+  //\r
+  EFI_EDITOR_POSITION   LowVisibleRange;\r
+\r
+  BOOLEAN               FileModified;     // file is modified or not\r
+  BOOLEAN               ModeInsert;       // input mode INS or OVR\r
+  BOOLEAN               ReadOnly;         // file is read-only or not\r
+  EFI_EDITOR_LINE       *CurrentLine;     // current line cursor is at\r
+} EFI_EDITOR_FILE_BUFFER;\r
+\r
+typedef struct {\r
+  EFI_EDITOR_FILE_BUFFER      *FileBuffer;\r
+\r
+  EFI_EDITOR_COLOR_UNION      ColorAttributes;\r
+  EFI_EDITOR_POSITION         ScreenSize; // row number and column number\r
+  EFI_EDITOR_LINE             *CutLine;   // clip board\r
+  BOOLEAN                     MouseSupported;\r
+  EFI_SIMPLE_POINTER_PROTOCOL *MouseInterface;\r
+  INT32                       MouseAccumulatorX;\r
+  INT32                       MouseAccumulatorY;\r
+\r
+} EFI_EDITOR_GLOBAL_EDITOR;\r
+\r
+#endif\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.c
new file mode 100644 (file)
index 0000000..04ebd24
--- /dev/null
@@ -0,0 +1,2695 @@
+/** @file\r
+  Defines HBufferImage - the view of the file that is visible at any point,\r
+  as well as the event handlers for editing the file\r
+  \r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HexEditor.h"\r
+\r
+extern EFI_HANDLE                 HImageHandleBackup;\r
+\r
+extern HEFI_EDITOR_FILE_IMAGE     HFileImage;\r
+extern HEFI_EDITOR_DISK_IMAGE     HDiskImage;\r
+extern HEFI_EDITOR_MEM_IMAGE      HMemImage;\r
+\r
+extern HEFI_EDITOR_FILE_IMAGE     HFileImageBackupVar;\r
+extern HEFI_EDITOR_DISK_IMAGE     HDiskImageBackupVar;\r
+extern HEFI_EDITOR_MEM_IMAGE      HMemImageBackupVar;\r
+\r
+extern BOOLEAN                    HEditorMouseAction;\r
+\r
+extern HEFI_EDITOR_GLOBAL_EDITOR  HMainEditor;\r
+extern HEFI_EDITOR_GLOBAL_EDITOR  HMainEditorBackupVar;\r
+\r
+HEFI_EDITOR_BUFFER_IMAGE          HBufferImage;\r
+HEFI_EDITOR_BUFFER_IMAGE          HBufferImageBackupVar;\r
+\r
+//\r
+// for basic initialization of HBufferImage\r
+//\r
+HEFI_EDITOR_BUFFER_IMAGE          HBufferImageConst = {\r
+  NULL,\r
+  NULL,\r
+  0,\r
+  NULL,\r
+  {\r
+    0,\r
+    0\r
+  },\r
+  {\r
+    0,\r
+    0\r
+  },\r
+  {\r
+    0,\r
+    0\r
+  },\r
+  0,\r
+  TRUE,\r
+  FALSE,\r
+  FileTypeNone,\r
+  NULL,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+//\r
+// the whole edit area needs to be refreshed\r
+//\r
+BOOLEAN                           HBufferImageNeedRefresh;\r
+\r
+//\r
+// only the current line in edit area needs to be refresh\r
+//\r
+BOOLEAN                           HBufferImageOnlyLineNeedRefresh;\r
+\r
+BOOLEAN                           HBufferImageMouseNeedRefresh;\r
+\r
+EFI_STATUS\r
+HBufferImageInit (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Initialization function for HBufferImage\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+  EFI_LOAD_ERROR\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // basically initialize the HBufferImage\r
+  //\r
+  CopyMem (&HBufferImage, &HBufferImageConst, sizeof (HBufferImage));\r
+\r
+  //\r
+  // INIT listhead\r
+  //\r
+  HBufferImage.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY));\r
+  if (HBufferImage.ListHead == NULL) {\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  InitializeListHead (HBufferImage.ListHead);\r
+\r
+  HBufferImage.DisplayPosition.Row    = 2;\r
+  HBufferImage.DisplayPosition.Column = 10;\r
+  HBufferImage.MousePosition.Row      = 2;\r
+  HBufferImage.MousePosition.Column   = 10;\r
+\r
+  HBufferImage.FileImage              = &HFileImage;\r
+  HBufferImage.DiskImage              = &HDiskImage;\r
+  HBufferImage.MemImage               = &HMemImage;\r
+\r
+  HBufferImageNeedRefresh             = FALSE;\r
+  HBufferImageOnlyLineNeedRefresh     = FALSE;\r
+  HBufferImageMouseNeedRefresh        = FALSE;\r
+\r
+  HBufferImageBackupVar.FileImage     = &HFileImageBackupVar;\r
+  HBufferImageBackupVar.DiskImage     = &HDiskImageBackupVar;\r
+  HBufferImageBackupVar.MemImage      = &HMemImageBackupVar;\r
+\r
+  Status = HFileImageInit ();\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  Status = HDiskImageInit ();\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  Status = HMemImageInit ();\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageBackup (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Backup function for HBufferImage\r
+  Only a few fields need to be backup. \r
+  This is for making the file buffer refresh \r
+  as few as possible.\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  HBufferImageBackupVar.MousePosition   = HBufferImage.MousePosition;\r
+\r
+  HBufferImageBackupVar.BufferPosition  = HBufferImage.BufferPosition;\r
+\r
+  HBufferImageBackupVar.Modified        = HBufferImage.Modified;\r
+\r
+  HBufferImageBackupVar.BufferType      = HBufferImage.BufferType;\r
+  HBufferImageBackupVar.LowVisibleRow   = HBufferImage.LowVisibleRow;\r
+  HBufferImageBackupVar.HighBits        = HBufferImage.HighBits;\r
+\r
+  //\r
+  // three kinds of buffer supported\r
+  //   file buffer\r
+  //   disk buffer\r
+  //   memory buffer\r
+  //\r
+  switch (HBufferImage.BufferType) {\r
+  case FileTypeFileBuffer:\r
+    HFileImageBackup ();\r
+    break;\r
+\r
+  case FileTypeDiskBuffer:\r
+    HDiskImageBackup ();\r
+    break;\r
+\r
+  case FileTypeMemBuffer:\r
+    HMemImageBackup ();\r
+    break;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageFreeLines (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Free all the lines in HBufferImage\r
+    Fields affected:\r
+    Lines\r
+    CurrentLine\r
+    NumLines\r
+    ListHead \r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  HFreeLines (HBufferImage.ListHead, HBufferImage.Lines);\r
+\r
+  HBufferImage.Lines        = NULL;\r
+  HBufferImage.CurrentLine  = NULL;\r
+  HBufferImage.NumLines     = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageCleanup (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Cleanup function for HBufferImage\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // free all the lines\r
+  //\r
+  Status = HBufferImageFreeLines ();\r
+\r
+  SHELL_FREE_NON_NULL (HBufferImage.ListHead);\r
+  HBufferImage.ListHead = NULL;\r
+\r
+  HFileImageCleanup ();\r
+  HDiskImageCleanup ();\r
+  HMemImageCleanup ();\r
+\r
+  return Status;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImagePrintLine (\r
+  IN HEFI_EDITOR_LINE           *Line,\r
+  IN UINTN                      Row,\r
+  IN UINTN                      FRow,\r
+  IN HEFI_EDITOR_COLOR_UNION    Orig,\r
+  IN HEFI_EDITOR_COLOR_UNION    New\r
+\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Print Line on Row\r
+\r
+Arguments:  \r
+\r
+  Line - Line to print\r
+  Row  - Row on screen ( begin from 1 )\r
+  FRow - FRow\r
+  Orig - Orig\r
+  New  - Light display\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+\r
+  UINTN   Index;\r
+  UINTN   Pos;\r
+  BOOLEAN Selected;\r
+  BOOLEAN BeNewColor;\r
+  UINTN   RowStart;\r
+  UINTN   RowEnd;\r
+  UINTN   ColStart;\r
+  UINTN   ColEnd;\r
+\r
+  //\r
+  // variable initialization\r
+  //\r
+  ColStart  = 0;\r
+  ColEnd    = 0;\r
+  Selected  = FALSE;\r
+\r
+  //\r
+  // print the selected area in opposite color\r
+  //\r
+  if (HMainEditor.SelectStart != 0 && HMainEditor.SelectEnd != 0) {\r
+    RowStart  = (HMainEditor.SelectStart - 1) / 0x10 + 1;\r
+    RowEnd    = (HMainEditor.SelectEnd - 1) / 0x10 + 1;\r
+\r
+    ColStart  = (HMainEditor.SelectStart - 1) % 0x10 + 1;\r
+    ColEnd    = (HMainEditor.SelectEnd - 1) % 0x10 + 1;\r
+\r
+    if (FRow >= RowStart && FRow <= RowEnd) {\r
+      Selected = TRUE;\r
+    }\r
+\r
+    if (FRow > RowStart) {\r
+      ColStart = 1;\r
+    }\r
+\r
+    if (FRow < RowEnd) {\r
+      ColEnd = 0x10;\r
+    }\r
+\r
+  }\r
+\r
+  if (HEditorMouseAction == FALSE) {\r
+    ShellPrintEx (\r
+      0,\r
+      (INT32)Row - 1,\r
+      L"%8X ",\r
+      ((INT32)Row - 2 + HBufferImage.LowVisibleRow - 1) * 0x10\r
+      );\r
+\r
+  }\r
+\r
+  for (Index = 0; Index < 0x08 && Index < Line->Size; Index++) {\r
+\r
+    BeNewColor = FALSE;\r
+\r
+    if (Selected) {\r
+      if (Index + 1 >= ColStart && Index + 1 <= ColEnd) {\r
+        BeNewColor = TRUE;\r
+      }\r
+    }\r
+\r
+    if (BeNewColor) {\r
+      gST->ConOut->SetAttribute (gST->ConOut, New.Data);\r
+    } else {\r
+      gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);\r
+    }\r
+\r
+    Pos = 10 + (Index * 3);\r
+    if (Line->Buffer[Index] < 0x10) {\r
+      ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"0");\r
+      Pos++;\r
+    }\r
+\r
+    if (Index < 0x07) {\r
+      ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]);\r
+    } else {\r
+      ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x  ", Line->Buffer[Index]);\r
+    }\r
+\r
+  }\r
+\r
+  gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);\r
+  while (Index < 0x08) {\r
+    Pos = 10 + (Index * 3);\r
+    ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"    ");\r
+    Index++;\r
+  }\r
+\r
+  while (Index < 0x10 && Index < Line->Size) {\r
+\r
+    BeNewColor = FALSE;\r
+\r
+    if (Selected) {\r
+      if (Index + 1 >= ColStart && Index + 1 <= ColEnd) {\r
+        BeNewColor = TRUE;\r
+      }\r
+    }\r
+\r
+    if (BeNewColor) {\r
+      gST->ConOut->SetAttribute (gST->ConOut, New.Data);\r
+    } else {\r
+      gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);\r
+    }\r
+\r
+    Pos = 10 + (Index * 3) + 1;\r
+    if (Line->Buffer[Index] < 0x10) {\r
+      ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"0");\r
+      Pos++;\r
+    }\r
+\r
+    ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]);\r
+    Index++;\r
+  }\r
+\r
+  gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);\r
+  while (Index < 0x10) {\r
+    Pos = 10 + (Index * 3) + 1;\r
+    ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"   ");\r
+    Index++;\r
+  }\r
+  //\r
+  // restore the original color\r
+  //\r
+  gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);\r
+\r
+  //\r
+  // PRINT the buffer content\r
+  //\r
+  if (HEditorMouseAction == FALSE) {\r
+    for (Index = 0; Index < 0x10 && Index < Line->Size; Index++) {\r
+      Pos = ASCII_POSITION + Index;\r
+\r
+      //\r
+      // learned from shelle.h -- IsValidChar\r
+      //\r
+      if (Line->Buffer[Index] >= L' ') {\r
+        ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%c", (CHAR16) Line->Buffer[Index]);\r
+      } else {\r
+        ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%c", '.');\r
+      }\r
+    }\r
+\r
+    while (Index < 0x10) {\r
+      Pos = ASCII_POSITION + Index;\r
+      ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" ");\r
+      Index++;\r
+    }\r
+  }\r
+  //\r
+  // restore the abundant blank in hex edit area to original color\r
+  //\r
+  if (Selected) {\r
+    if (ColEnd <= 7) {\r
+      Pos = 10 + (ColEnd - 1) * 3 + 2;\r
+      ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" ");\r
+    } else if (ColEnd == 8) {\r
+      Pos = 10 + (ColEnd - 1) * 3 + 2;\r
+      ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"  ");\r
+    } else {\r
+      Pos = 10 + (ColEnd - 1) * 3 + 3;\r
+      ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" ");\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+HBufferImageIsAtHighBits (\r
+  IN  UINTN Column,\r
+  OUT UINTN *FCol\r
+  )\r
+{\r
+  Column -= 10;\r
+\r
+  //\r
+  // NOW AFTER THE SUB, Column start from 0\r
+  // 23 AND 24 ARE BOTH BLANK\r
+  //\r
+  if (Column == 24) {\r
+    *FCol = 0;\r
+    return FALSE;\r
+  }\r
+\r
+  if (Column > 24) {\r
+    Column--;\r
+  }\r
+\r
+  *FCol = (Column / 3) + 1;\r
+\r
+  if (!(Column % 3)) {\r
+    return TRUE;\r
+  }\r
+\r
+  if ((Column % 3 == 2)) {\r
+    *FCol = 0;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+BOOLEAN\r
+HBufferImageIsInSelectedArea (\r
+  IN UINTN MouseRow,\r
+  IN UINTN MouseCol\r
+  )\r
+{\r
+  UINTN FRow;\r
+  UINTN RowStart;\r
+  UINTN RowEnd;\r
+  UINTN ColStart;\r
+  UINTN ColEnd;\r
+  UINTN MouseColStart;\r
+  UINTN MouseColEnd;\r
+\r
+  //\r
+  // judge mouse position whether is in selected area\r
+  //\r
+  //\r
+  // not select\r
+  //\r
+  if (HMainEditor.SelectStart == 0 || HMainEditor.SelectEnd == 0) {\r
+    return FALSE;\r
+  }\r
+  //\r
+  // calculate the select area\r
+  //\r
+  RowStart  = (HMainEditor.SelectStart - 1) / 0x10 + 1;\r
+  RowEnd    = (HMainEditor.SelectEnd - 1) / 0x10 + 1;\r
+\r
+  ColStart  = (HMainEditor.SelectStart - 1) % 0x10 + 1;\r
+  ColEnd    = (HMainEditor.SelectEnd - 1) % 0x10 + 1;\r
+\r
+  FRow      = HBufferImage.LowVisibleRow + MouseRow - 2;\r
+  if (FRow < RowStart || FRow > RowEnd) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (FRow > RowStart) {\r
+    ColStart = 1;\r
+  }\r
+\r
+  if (FRow < RowEnd) {\r
+    ColEnd = 0x10;\r
+  }\r
+\r
+  MouseColStart = 10 + (ColStart - 1) * 3;\r
+  if (ColStart > 8) {\r
+    MouseColStart++;\r
+  }\r
+\r
+  MouseColEnd = 10 + (ColEnd - 1) * 3 + 1;\r
+  if (ColEnd > 8) {\r
+    MouseColEnd++;\r
+  }\r
+\r
+  if (MouseCol < MouseColStart || MouseCol > MouseColEnd) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageRestoreMousePosition (\r
+  VOID\r
+  )\r
+{\r
+  HEFI_EDITOR_COLOR_UNION Orig;\r
+  HEFI_EDITOR_COLOR_UNION New;\r
+  UINTN                   FRow;\r
+  UINTN                   FColumn;\r
+  BOOLEAN                 HasCharacter;\r
+  HEFI_EDITOR_LINE        *CurrentLine;\r
+  HEFI_EDITOR_LINE        *Line;\r
+  UINT8                   Value;\r
+  BOOLEAN                 HighBits;\r
+\r
+  Line = NULL;\r
+  if (HMainEditor.MouseSupported) {\r
+\r
+    if (HBufferImageMouseNeedRefresh) {\r
+\r
+      HBufferImageMouseNeedRefresh = FALSE;\r
+\r
+      //\r
+      // if mouse position not moved and only mouse action\r
+      // so do not need to refresh mouse position\r
+      //\r
+      if ((\r
+            HBufferImage.MousePosition.Row == HBufferImageBackupVar.MousePosition.Row &&\r
+          HBufferImage.MousePosition.Column == HBufferImageBackupVar.MousePosition.Column\r
+        ) &&\r
+          HEditorMouseAction\r
+          ) {\r
+        return EFI_SUCCESS;\r
+      }\r
+      //\r
+      // backup the old screen attributes\r
+      //\r
+      Orig                  = HMainEditor.ColorAttributes;\r
+      New.Colors.Foreground = Orig.Colors.Background;\r
+      New.Colors.Background = Orig.Colors.Foreground;\r
+\r
+      //\r
+      // if in selected area,\r
+      // so do not need to refresh mouse\r
+      //\r
+      if (!HBufferImageIsInSelectedArea (\r
+            HBufferImageBackupVar.MousePosition.Row,\r
+            HBufferImageBackupVar.MousePosition.Column\r
+            )) {\r
+        gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);\r
+      } else {\r
+        gST->ConOut->SetAttribute (gST->ConOut, New.Data);\r
+      }\r
+      //\r
+      // clear the old mouse position\r
+      //\r
+      FRow = HBufferImage.LowVisibleRow + HBufferImageBackupVar.MousePosition.Row - 2;\r
+\r
+      HighBits = HBufferImageIsAtHighBits (\r
+                  HBufferImageBackupVar.MousePosition.Column,\r
+                  &FColumn\r
+                  );\r
+\r
+      HasCharacter = TRUE;\r
+      if (FRow > HBufferImage.NumLines || FColumn == 0) {\r
+        HasCharacter = FALSE;\r
+      } else {\r
+        CurrentLine = HBufferImage.CurrentLine;\r
+        Line        = HMoveLine (FRow - HBufferImage.BufferPosition.Row);\r
+\r
+        if (FColumn > Line->Size) {\r
+          HasCharacter = FALSE;\r
+        }\r
+\r
+        HBufferImage.CurrentLine = CurrentLine;\r
+      }\r
+\r
+      ShellPrintEx (\r
+        (INT32)HBufferImageBackupVar.MousePosition.Column - 1,\r
+        (INT32)HBufferImageBackupVar.MousePosition.Row - 1,\r
+        L" "\r
+        );\r
+\r
+      if (HasCharacter) {\r
+        if (HighBits) {\r
+          Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf0);\r
+          Value = (UINT8) (Value >> 4);\r
+        } else {\r
+          Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf);\r
+        }\r
+\r
+        ShellPrintEx (\r
+          (INT32)HBufferImageBackupVar.MousePosition.Column - 1,\r
+          (INT32)HBufferImageBackupVar.MousePosition.Row - 1,\r
+          L"%x",\r
+          Value\r
+          );\r
+      }\r
+\r
+      if (!HBufferImageIsInSelectedArea (\r
+            HBufferImage.MousePosition.Row,\r
+            HBufferImage.MousePosition.Column\r
+            )) {\r
+        gST->ConOut->SetAttribute (gST->ConOut, New.Data);\r
+      } else {\r
+        gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);\r
+      }\r
+      //\r
+      // clear the old mouse position\r
+      //\r
+      FRow = HBufferImage.LowVisibleRow + HBufferImage.MousePosition.Row - 2;\r
+\r
+      HighBits = HBufferImageIsAtHighBits (\r
+                  HBufferImage.MousePosition.Column,\r
+                  &FColumn\r
+                  );\r
+\r
+      HasCharacter = TRUE;\r
+      if (FRow > HBufferImage.NumLines || FColumn == 0) {\r
+        HasCharacter = FALSE;\r
+      } else {\r
+        CurrentLine = HBufferImage.CurrentLine;\r
+        Line        = HMoveLine (FRow - HBufferImage.BufferPosition.Row);\r
+\r
+        if (FColumn > Line->Size) {\r
+          HasCharacter = FALSE;\r
+        }\r
+\r
+        HBufferImage.CurrentLine = CurrentLine;\r
+      }\r
+\r
+      ShellPrintEx (\r
+        (INT32)HBufferImage.MousePosition.Column - 1,\r
+        (INT32)HBufferImage.MousePosition.Row - 1,\r
+        L" "\r
+        );\r
+\r
+      if (HasCharacter) {\r
+        if (HighBits) {\r
+          Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf0);\r
+          Value = (UINT8) (Value >> 4);\r
+        } else {\r
+          Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf);\r
+        }\r
+\r
+        ShellPrintEx (\r
+          (INT32)HBufferImage.MousePosition.Column - 1,\r
+          (INT32)HBufferImage.MousePosition.Row - 1,\r
+          L"%x",\r
+          Value\r
+          );\r
+      }\r
+      //\r
+      // end of HasCharacter\r
+      //\r
+      gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);\r
+    }\r
+    //\r
+    // end of MouseNeedRefresh\r
+    //\r
+  }\r
+  //\r
+  // end of MouseSupported\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageRestorePosition (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Set cursor position according to HBufferImage.DisplayPosition.\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  //\r
+  // set cursor position\r
+  //\r
+  gST->ConOut->SetCursorPosition (\r
+        gST->ConOut,\r
+        HBufferImage.DisplayPosition.Column - 1,\r
+        HBufferImage.DisplayPosition.Row - 1\r
+        );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageRefresh (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Refresh function for HBufferImage\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+  EFI_LOAD_ERROR \r
+\r
+--*/\r
+{\r
+  LIST_ENTRY          *Link;\r
+  HEFI_EDITOR_LINE        *Line;\r
+  UINTN                   Row;\r
+  HEFI_EDITOR_COLOR_UNION Orig;\r
+  HEFI_EDITOR_COLOR_UNION New;\r
+\r
+  UINTN                   StartRow;\r
+  UINTN                   EndRow;\r
+  UINTN                   FStartRow;\r
+  UINTN                   FEndRow;\r
+  UINTN                   Tmp;\r
+\r
+  Orig                  = HMainEditor.ColorAttributes;\r
+  New.Colors.Foreground = Orig.Colors.Background;\r
+  New.Colors.Background = Orig.Colors.Foreground;\r
+\r
+  //\r
+  // if it's the first time after editor launch, so should refresh\r
+  //\r
+  if (HEditorFirst == FALSE) {\r
+    //\r
+    // no definite required refresh\r
+    // and file position displayed on screen has not been changed\r
+    //\r
+    if (HBufferImageNeedRefresh == FALSE &&\r
+        HBufferImageOnlyLineNeedRefresh == FALSE &&\r
+        HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow\r
+        ) {\r
+      HBufferImageRestoreMousePosition ();\r
+      HBufferImageRestorePosition ();\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+\r
+  //\r
+  // only need to refresh current line\r
+  //\r
+  if (HBufferImageOnlyLineNeedRefresh == TRUE && HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow) {\r
+\r
+    HBufferImagePrintLine (\r
+      HBufferImage.CurrentLine,\r
+      HBufferImage.DisplayPosition.Row,\r
+      HBufferImage.BufferPosition.Row,\r
+      Orig,\r
+      New\r
+      );\r
+  } else {\r
+    //\r
+    // the whole edit area need refresh\r
+    //\r
+    if (HEditorMouseAction && HMainEditor.SelectStart != 0 && HMainEditor.SelectEnd != 0) {\r
+      if (HMainEditor.SelectStart != HMainEditorBackupVar.SelectStart) {\r
+        if (HMainEditor.SelectStart >= HMainEditorBackupVar.SelectStart && HMainEditorBackupVar.SelectStart != 0) {\r
+          StartRow = (HMainEditorBackupVar.SelectStart - 1) / 0x10 + 1;\r
+        } else {\r
+          StartRow = (HMainEditor.SelectStart - 1) / 0x10 + 1;\r
+        }\r
+      } else {\r
+        StartRow = (HMainEditor.SelectStart - 1) / 0x10 + 1;\r
+      }\r
+\r
+      if (HMainEditor.SelectEnd <= HMainEditorBackupVar.SelectEnd) {\r
+        EndRow = (HMainEditorBackupVar.SelectEnd - 1) / 0x10 + 1;\r
+      } else {\r
+        EndRow = (HMainEditor.SelectEnd - 1) / 0x10 + 1;\r
+      }\r
+      //\r
+      // swap\r
+      //\r
+      if (StartRow > EndRow) {\r
+        Tmp       = StartRow;\r
+        StartRow  = EndRow;\r
+        EndRow    = Tmp;\r
+      }\r
+\r
+      FStartRow = StartRow;\r
+      FEndRow   = EndRow;\r
+\r
+      StartRow  = 2 + StartRow - HBufferImage.LowVisibleRow;\r
+      EndRow    = 2 + EndRow - HBufferImage.LowVisibleRow;\r
+\r
+    } else {\r
+      //\r
+      // not mouse selection actions\r
+      //\r
+      FStartRow = HBufferImage.LowVisibleRow;\r
+      StartRow  = 2;\r
+      EndRow    = (HMainEditor.ScreenSize.Row - 4);\r
+    }\r
+    //\r
+    // no line\r
+    //\r
+    if (HBufferImage.Lines == NULL) {\r
+      HBufferImageRestoreMousePosition ();\r
+      HBufferImageRestorePosition ();\r
+      gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // get the first line that will be displayed\r
+    //\r
+    Line = HMoveLine (FStartRow - HBufferImage.BufferPosition.Row);\r
+    if (Line == NULL) {\r
+      gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+      return EFI_LOAD_ERROR;\r
+    }\r
+\r
+    Link  = &(Line->Link);\r
+    Row   = StartRow;\r
+    do {\r
+      Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);\r
+\r
+      //\r
+      // print line at row\r
+      //\r
+      HBufferImagePrintLine (\r
+        Line,\r
+        Row,\r
+        HBufferImage.LowVisibleRow + Row - 2,\r
+        Orig,\r
+        New\r
+        );\r
+\r
+      Link = Link->ForwardLink;\r
+      Row++;\r
+    } while (Link != HBufferImage.ListHead && Row <= EndRow);\r
+\r
+    while (Row <= EndRow) {\r
+      HEditorClearLine (Row);\r
+      Row++;\r
+    }\r
+    //\r
+    // while not file end and not screen full\r
+    //\r
+  }\r
+\r
+  HBufferImageRestoreMousePosition ();\r
+  HBufferImageRestorePosition ();\r
+\r
+  HBufferImageNeedRefresh         = FALSE;\r
+  HBufferImageOnlyLineNeedRefresh = FALSE;\r
+  gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageRead (\r
+  IN CONST CHAR16                   *FileName,\r
+  IN CONST CHAR16                   *DiskName,\r
+  IN UINTN                          DiskOffset,\r
+  IN UINTN                          DiskSize,\r
+  IN UINTN                          MemOffset,\r
+  IN UINTN                          MemSize,\r
+  IN EDIT_FILE_TYPE                 BufferType,\r
+  IN BOOLEAN                        Recover\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EDIT_FILE_TYPE                  BufferTypeBackup;\r
+\r
+  //\r
+  // variable initialization\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // three types of buffer supported\r
+  //   file buffer\r
+  //   disk buffer\r
+  //   memory buffer\r
+  //\r
+  BufferTypeBackup = HBufferImage.BufferType;\r
+\r
+  switch (BufferType) {\r
+  case FileTypeFileBuffer:\r
+    Status = HFileImageRead (FileName, Recover);\r
+    break;\r
+\r
+  case FileTypeDiskBuffer:\r
+    Status = HDiskImageRead (DiskName, DiskOffset, DiskSize, Recover);\r
+    break;\r
+\r
+  case FileTypeMemBuffer:\r
+    Status = HMemImageRead (MemOffset, MemSize, Recover);\r
+    break;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    HBufferImage.BufferType = BufferTypeBackup;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageSave (\r
+  IN CHAR16                         *FileName,\r
+  IN CHAR16                         *DiskName,\r
+  IN UINTN                          DiskOffset,\r
+  IN UINTN                          DiskSize,\r
+  IN UINTN                          MemOffset,\r
+  IN UINTN                          MemSize,\r
+  IN EDIT_FILE_TYPE                 BufferType\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EDIT_FILE_TYPE                  BufferTypeBackup;\r
+\r
+  //\r
+  // variable initialization\r
+  //\r
+  Status            = EFI_SUCCESS;\r
+  BufferTypeBackup  = HBufferImage.BufferType;\r
+\r
+  switch (HBufferImage.BufferType) {\r
+  //\r
+  // file buffer\r
+  //\r
+  case FileTypeFileBuffer:\r
+    Status = HFileImageSave (FileName);\r
+    break;\r
+\r
+  //\r
+  // disk buffer\r
+  //\r
+  case FileTypeDiskBuffer:\r
+    Status = HDiskImageSave (DiskName, DiskOffset, DiskSize);\r
+    break;\r
+\r
+  //\r
+  // memory buffer\r
+  //\r
+  case FileTypeMemBuffer:\r
+    Status = HMemImageSave (MemOffset, MemSize);\r
+    break;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    HBufferImage.BufferType = BufferTypeBackup;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+HEFI_EDITOR_LINE *\r
+HBufferImageCreateLine (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Create a new line and append it to the line list\r
+    Fields affected:\r
+    NumLines\r
+    Lines \r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  NULL -- create line failed\r
+  Not NULL -- the line created\r
+\r
+--*/\r
+{\r
+  HEFI_EDITOR_LINE  *Line;\r
+\r
+  //\r
+  // allocate for line structure\r
+  //\r
+  Line = AllocateZeroPool (sizeof (HEFI_EDITOR_LINE));\r
+  if (Line == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Line->Signature = EFI_EDITOR_LINE_LIST;\r
+  Line->Size      = 0;\r
+\r
+  HBufferImage.NumLines++;\r
+\r
+  //\r
+  // insert to line list\r
+  //\r
+  InsertTailList (HBufferImage.ListHead, &Line->Link);\r
+\r
+  if (HBufferImage.Lines == NULL) {\r
+    HBufferImage.Lines = CR (\r
+                          HBufferImage.ListHead->ForwardLink,\r
+                          HEFI_EDITOR_LINE,\r
+                          Link,\r
+                          EFI_EDITOR_LINE_LIST\r
+                          );\r
+  }\r
+\r
+  return Line;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageFree (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Function called when load a new file in. It will free all the old lines\r
+  and set FileModified field to FALSE\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  //\r
+  // free all lines\r
+  //\r
+  HBufferImageFreeLines ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageHandleInput (\r
+  IN  EFI_INPUT_KEY *Key\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Dispatch input to different handler\r
+\r
+Arguments:  \r
+\r
+  Key -- input key\r
+   the keys can be:\r
+     ASCII KEY\r
+      Backspace/Delete\r
+      Direction key: up/down/left/right/pgup/pgdn\r
+      Home/End\r
+      INS\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+  EFI_LOAD_ERROR\r
+  EFI_OUT_OF_RESOURCES\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (Key->ScanCode) {\r
+  //\r
+  // ordinary key\r
+  //\r
+  case SCAN_NULL:\r
+    Status = HBufferImageDoCharInput (Key->UnicodeChar);\r
+    break;\r
+\r
+  //\r
+  // up arrow\r
+  //\r
+  case SCAN_UP:\r
+    Status = HBufferImageScrollUp ();\r
+    break;\r
+\r
+  //\r
+  // down arrow\r
+  //\r
+  case SCAN_DOWN:\r
+    Status = HBufferImageScrollDown ();\r
+    break;\r
+\r
+  //\r
+  // right arrow\r
+  //\r
+  case SCAN_RIGHT:\r
+    Status = HBufferImageScrollRight ();\r
+    break;\r
+\r
+  //\r
+  // left arrow\r
+  //\r
+  case SCAN_LEFT:\r
+    Status = HBufferImageScrollLeft ();\r
+    break;\r
+\r
+  //\r
+  // page up\r
+  //\r
+  case SCAN_PAGE_UP:\r
+    Status = HBufferImagePageUp ();\r
+    break;\r
+\r
+  //\r
+  // page down\r
+  //\r
+  case SCAN_PAGE_DOWN:\r
+    Status = HBufferImagePageDown ();\r
+    break;\r
+\r
+  //\r
+  // delete\r
+  //\r
+  case SCAN_DELETE:\r
+    Status = HBufferImageDoDelete ();\r
+    break;\r
+\r
+  //\r
+  // home\r
+  //\r
+  case SCAN_HOME:\r
+    Status = HBufferImageHome ();\r
+    break;\r
+\r
+  //\r
+  // end\r
+  //\r
+  case SCAN_END:\r
+    Status = HBufferImageEnd ();\r
+    break;\r
+\r
+  default:\r
+    Status = StatusBarSetStatusString (L"Unknown Command");\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageDoCharInput (\r
+  IN  CHAR16  Char\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  ASCII key + Backspace + return\r
+\r
+Arguments:  \r
+\r
+  Char -- input char\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+  EFI_LOAD_ERROR\r
+  EFI_OUT_OF_RESOURCES\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (Char) {\r
+  case 0:\r
+    break;\r
+\r
+  case 0x08:\r
+    Status = HBufferImageDoBackspace ();\r
+    break;\r
+\r
+  case 0x09:\r
+  case 0x0a:\r
+  case 0x0d:\r
+    //\r
+    // Tabs, Returns are thought as nothing\r
+    //\r
+    break;\r
+\r
+  default:\r
+    //\r
+    // DEAL WITH ASCII CHAR, filter out thing like ctrl+f\r
+    //\r
+    if (Char > 127 || Char < 32) {\r
+      Status = StatusBarSetStatusString (L"Unknown Command");\r
+    } else {\r
+      Status = HBufferImageAddChar (Char);\r
+    }\r
+\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+INTN\r
+HBufferImageCharToHex (\r
+  IN CHAR16 Char\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  change char to int value based on Hex\r
+\r
+Arguments:  \r
+\r
+  Char -- input char\r
+\r
+Returns:  \r
+\r
+  int value;\r
+\r
+\r
+--*/\r
+{\r
+  //\r
+  // change the character to hex\r
+  //\r
+  if (Char >= L'0' && Char <= L'9') {\r
+    return (INTN) (Char - L'0');\r
+  }\r
+\r
+  if (Char >= L'a' && Char <= L'f') {\r
+    return (INTN) (Char - L'a' + 10);\r
+  }\r
+\r
+  if (Char >= L'A' && Char <= L'F') {\r
+    return (INTN) (Char - L'A' + 10);\r
+  }\r
+\r
+  return -1;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageAddChar (\r
+  IN  CHAR16  Char\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Add character\r
+\r
+Arguments:  \r
+\r
+  Char -- input char\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+  EFI_OUT_OF_RESOURCES\r
+\r
+--*/\r
+{\r
+  HEFI_EDITOR_LINE  *Line;\r
+  HEFI_EDITOR_LINE  *NewLine;\r
+  INTN              Value;\r
+  UINT8             Old;\r
+  UINTN             FRow;\r
+  UINTN             FCol;\r
+  BOOLEAN           High;\r
+\r
+  Value = HBufferImageCharToHex (Char);\r
+\r
+  //\r
+  // invalid input\r
+  //\r
+  if (Value == -1) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Line  = HBufferImage.CurrentLine;\r
+  FRow  = HBufferImage.BufferPosition.Row;\r
+  FCol  = HBufferImage.BufferPosition.Column;\r
+  High  = HBufferImage.HighBits;\r
+\r
+  //\r
+  // only needs to refresh current line\r
+  //\r
+  HBufferImageOnlyLineNeedRefresh = TRUE;\r
+\r
+  //\r
+  // not a full line and beyond the last character\r
+  //\r
+  if (FCol > Line->Size) {\r
+    //\r
+    // cursor always at high 4 bits\r
+    // and always put input to the low 4 bits\r
+    //\r
+    Line->Buffer[Line->Size] = (UINT8) Value;\r
+    Line->Size++;\r
+    High = FALSE;\r
+  } else {\r
+\r
+    Old = Line->Buffer[FCol - 1];\r
+\r
+    //\r
+    // always put the input to the low 4 bits\r
+    //\r
+    Old                     = (UINT8) (Old & 0x0f);\r
+    Old                     = (UINT8) (Old << 4);\r
+    Old                     = (UINT8) (Value + Old);\r
+    Line->Buffer[FCol - 1]  = Old;\r
+\r
+    //\r
+    // at the low 4 bits of the last character of a full line\r
+    // so if no next line, need to create a new line\r
+    //\r
+    if (High == FALSE && FCol == 0x10) {\r
+\r
+      HBufferImageOnlyLineNeedRefresh = FALSE;\r
+      HBufferImageNeedRefresh         = TRUE;\r
+\r
+      if (Line->Link.ForwardLink == HBufferImage.ListHead) {\r
+        //\r
+        // last line\r
+        //\r
+        // create a new line\r
+        //\r
+        NewLine = HBufferImageCreateLine ();\r
+        if (NewLine == NULL) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+        //\r
+        // end of NULL\r
+        //\r
+      }\r
+      //\r
+      // end of == ListHead\r
+      //\r
+    }\r
+    //\r
+    // end of == 0x10\r
+    //\r
+    // if already at end of this line, scroll it to the start of next line\r
+    //\r
+    if (FCol == 0x10 && High == FALSE) {\r
+      //\r
+      // definitely has next line\r
+      //\r
+      FRow++;\r
+      FCol  = 1;\r
+      High  = TRUE;\r
+    } else {\r
+      //\r
+      // if not at end of this line, just move to next column\r
+      //\r
+      if (!High) {\r
+        FCol++;\r
+      }\r
+\r
+      if (High) {\r
+        High = FALSE;\r
+      } else {\r
+        High = TRUE;\r
+      }\r
+\r
+    }\r
+    //\r
+    // end of ==FALSE\r
+    //\r
+  }\r
+  //\r
+  // move cursor to right\r
+  //\r
+  HBufferImageMovePosition (FRow, FCol, High);\r
+\r
+  if (!HBufferImage.Modified) {\r
+    HBufferImage.Modified = TRUE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+HInCurrentScreen (\r
+  IN  UINTN FileRow\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Check user specified FileRow and FileCol is in current screen\r
+\r
+Arguments:  \r
+\r
+  FileRow -- Row of file position ( start from 1 )\r
+\r
+\r
+Returns:  \r
+\r
+  TRUE\r
+  FALSE\r
+\r
+--*/\r
+{\r
+  if (FileRow >= HBufferImage.LowVisibleRow && FileRow <= HBufferImage.LowVisibleRow + (HMainEditor.ScreenSize.Row - 5) - 1) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+BOOLEAN\r
+HAboveCurrentScreen (\r
+  IN  UINTN FileRow\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Check user specified FileRow is above current screen\r
+\r
+Arguments:  \r
+\r
+  FileRow -- Row of file position ( start from 1 )\r
+  \r
+Returns:  \r
+\r
+  TRUE\r
+  FALSE\r
+\r
+--*/\r
+{\r
+  if (FileRow < HBufferImage.LowVisibleRow) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+BOOLEAN\r
+HUnderCurrentScreen (\r
+  IN  UINTN FileRow\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Check user specified FileRow is under current screen\r
+\r
+Arguments:  \r
+\r
+  FileRow -- Row of file position ( start from 1 )\r
+\r
+Returns:  \r
+\r
+  TRUE\r
+  FALSE\r
+\r
+--*/\r
+{\r
+  if (FileRow > HBufferImage.LowVisibleRow + (HMainEditor.ScreenSize.Row - 5) - 1) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+VOID\r
+HBufferImageMovePosition (\r
+  IN UINTN    NewFilePosRow,\r
+  IN UINTN    NewFilePosCol,\r
+  IN BOOLEAN  HighBits\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  According to cursor's file position, adjust screen display\r
+\r
+Arguments:  \r
+\r
+  NewFilePosRow -- Row of file position ( start from 1 )\r
+  NewFilePosCol -- Column of file position ( start from 1 )   \r
+  HighBits      -- cursor will on high4 bits or low4 bits\r
+\r
+Returns:  \r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  INTN    RowGap;\r
+  UINTN   Abs;\r
+  BOOLEAN Above;\r
+  BOOLEAN Under;\r
+  UINTN   NewDisplayCol;\r
+\r
+  //\r
+  // CALCULATE gap between current file position and new file position\r
+  //\r
+  RowGap                = NewFilePosRow - HBufferImage.BufferPosition.Row;\r
+\r
+  Under                 = HUnderCurrentScreen (NewFilePosRow);\r
+  Above                 = HAboveCurrentScreen (NewFilePosRow);\r
+\r
+  HBufferImage.HighBits = HighBits;\r
+\r
+  //\r
+  // if is below current screen\r
+  //\r
+  if (Under) {\r
+    //\r
+    // display row will be unchanged\r
+    //\r
+    HBufferImage.BufferPosition.Row = NewFilePosRow;\r
+  } else {\r
+    if (Above) {\r
+      //\r
+      // has enough above line, so display row unchanged\r
+      // not has enough above lines, so the first line is\r
+      // at the first display line\r
+      //\r
+      if (NewFilePosRow < (HBufferImage.DisplayPosition.Row - 2 + 1)) {\r
+        HBufferImage.DisplayPosition.Row = NewFilePosRow + 2 - 1;\r
+      }\r
+\r
+      HBufferImage.BufferPosition.Row = NewFilePosRow;\r
+    } else {\r
+      //\r
+      // in current screen\r
+      //\r
+      HBufferImage.BufferPosition.Row = NewFilePosRow;\r
+      if (RowGap <= 0) {\r
+        Abs = -RowGap;\r
+        HBufferImage.DisplayPosition.Row -= Abs;\r
+      } else {\r
+        HBufferImage.DisplayPosition.Row += RowGap;\r
+      }\r
+\r
+    }\r
+  }\r
+\r
+  HBufferImage.LowVisibleRow = HBufferImage.BufferPosition.Row - (HBufferImage.DisplayPosition.Row - 2);\r
+\r
+  //\r
+  // always in current screen\r
+  //\r
+  HBufferImage.BufferPosition.Column  = NewFilePosCol;\r
+\r
+  NewDisplayCol                       = 10 + (NewFilePosCol - 1) * 3;\r
+  if (NewFilePosCol > 0x8) {\r
+    NewDisplayCol++;\r
+  }\r
+\r
+  if (HighBits == FALSE) {\r
+    NewDisplayCol++;\r
+  }\r
+\r
+  HBufferImage.DisplayPosition.Column = NewDisplayCol;\r
+\r
+  //\r
+  // let CurrentLine point to correct line;\r
+  //\r
+  HBufferImage.CurrentLine = HMoveCurrentLine (RowGap);\r
+\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageScrollRight (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Scroll cursor to right\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  HEFI_EDITOR_LINE  *Line;\r
+  UINTN             FRow;\r
+  UINTN             FCol;\r
+\r
+  //\r
+  // scroll right will always move to the high4 bits of the next character\r
+  //\r
+  HBufferImageNeedRefresh         = FALSE;\r
+  HBufferImageOnlyLineNeedRefresh = FALSE;\r
+\r
+  Line = HBufferImage.CurrentLine;\r
+\r
+  FRow = HBufferImage.BufferPosition.Row;\r
+  FCol = HBufferImage.BufferPosition.Column;\r
+\r
+  //\r
+  // this line is not full and no next line\r
+  //\r
+  if (FCol > Line->Size) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // if already at end of this line, scroll it to the start of next line\r
+  //\r
+  if (FCol == 0x10) {\r
+    //\r
+    // has next line\r
+    //\r
+    if (Line->Link.ForwardLink != HBufferImage.ListHead) {\r
+      FRow++;\r
+      FCol = 1;\r
+\r
+    } else {\r
+      return EFI_SUCCESS;\r
+    }\r
+  } else {\r
+    //\r
+    // if not at end of this line, just move to next column\r
+    //\r
+    FCol++;\r
+\r
+  }\r
+\r
+  HBufferImageMovePosition (FRow, FCol, TRUE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageScrollLeft (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Scroll cursor to left\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+\r
+  HEFI_EDITOR_LINE  *Line;\r
+  UINTN             FRow;\r
+  UINTN             FCol;\r
+\r
+  HBufferImageNeedRefresh         = FALSE;\r
+  HBufferImageOnlyLineNeedRefresh = FALSE;\r
+\r
+  Line = HBufferImage.CurrentLine;\r
+\r
+  FRow = HBufferImage.BufferPosition.Row;\r
+  FCol = HBufferImage.BufferPosition.Column;\r
+\r
+  //\r
+  // if already at start of this line, so move to the end of previous line\r
+  //\r
+  if (FCol <= 1) {\r
+    //\r
+    // has previous line\r
+    //\r
+    if (Line->Link.BackLink != HBufferImage.ListHead) {\r
+      FRow--;\r
+      Line  = CR (Line->Link.BackLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);\r
+      FCol  = Line->Size;\r
+    } else {\r
+      return EFI_SUCCESS;\r
+    }\r
+  } else {\r
+    //\r
+    // if not at start of this line, just move to previous column\r
+    //\r
+    FCol--;\r
+  }\r
+\r
+  HBufferImageMovePosition (FRow, FCol, TRUE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageScrollDown (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Scroll cursor to the next line\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  HEFI_EDITOR_LINE  *Line;\r
+  UINTN             FRow;\r
+  UINTN             FCol;\r
+  BOOLEAN           HighBits;\r
+\r
+  Line      = HBufferImage.CurrentLine;\r
+\r
+  FRow      = HBufferImage.BufferPosition.Row;\r
+  FCol      = HBufferImage.BufferPosition.Column;\r
+  HighBits  = HBufferImage.HighBits;\r
+\r
+  //\r
+  // has next line\r
+  //\r
+  if (Line->Link.ForwardLink != HBufferImage.ListHead) {\r
+    FRow++;\r
+    Line = CR (Line->Link.ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);\r
+\r
+    //\r
+    // if the next line is not that long, so move to end of next line\r
+    //\r
+    if (FCol > Line->Size) {\r
+      FCol      = Line->Size + 1;\r
+      HighBits  = TRUE;\r
+    }\r
+\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  HBufferImageMovePosition (FRow, FCol, HighBits);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageScrollUp (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Scroll cursor to previous line\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  HEFI_EDITOR_LINE  *Line;\r
+  UINTN             FRow;\r
+  UINTN             FCol;\r
+\r
+  Line  = HBufferImage.CurrentLine;\r
+\r
+  FRow  = HBufferImage.BufferPosition.Row;\r
+  FCol  = HBufferImage.BufferPosition.Column;\r
+\r
+  //\r
+  // has previous line\r
+  //\r
+  if (Line->Link.BackLink != HBufferImage.ListHead) {\r
+    FRow--;\r
+\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImagePageDown (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Scroll cursor to next page\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  HEFI_EDITOR_LINE  *Line;\r
+  UINTN             FRow;\r
+  UINTN             FCol;\r
+  UINTN             Gap;\r
+  BOOLEAN           HighBits;\r
+\r
+  Line      = HBufferImage.CurrentLine;\r
+\r
+  FRow      = HBufferImage.BufferPosition.Row;\r
+  FCol      = HBufferImage.BufferPosition.Column;\r
+  HighBits  = HBufferImage.HighBits;\r
+\r
+  //\r
+  // has next page\r
+  //\r
+  if (HBufferImage.NumLines >= FRow + (HMainEditor.ScreenSize.Row - 5)) {\r
+    Gap = (HMainEditor.ScreenSize.Row - 5);\r
+  } else {\r
+    //\r
+    // MOVE CURSOR TO LAST LINE\r
+    //\r
+    Gap = HBufferImage.NumLines - FRow;\r
+  }\r
+  //\r
+  // get correct line\r
+  //\r
+  Line = HMoveLine (Gap);\r
+\r
+  //\r
+  // if that line, is not that long, so move to the end of that line\r
+  //\r
+  if (FCol > Line->Size) {\r
+    FCol      = Line->Size + 1;\r
+    HighBits  = TRUE;\r
+  }\r
+\r
+  FRow += Gap;\r
+\r
+  HBufferImageMovePosition (FRow, FCol, HighBits);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImagePageUp (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Scroll cursor to previous page\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  HEFI_EDITOR_LINE  *Line;\r
+  UINTN             FRow;\r
+  UINTN             FCol;\r
+  UINTN             Gap;\r
+  INTN              Retreat;\r
+\r
+  Line  = HBufferImage.CurrentLine;\r
+\r
+  FRow  = HBufferImage.BufferPosition.Row;\r
+  FCol  = HBufferImage.BufferPosition.Column;\r
+\r
+  //\r
+  // has previous page\r
+  //\r
+  if (FRow > (HMainEditor.ScreenSize.Row - 5)) {\r
+    Gap = (HMainEditor.ScreenSize.Row - 5);\r
+  } else {\r
+    //\r
+    // the first line of file will displayed on the first line of screen\r
+    //\r
+    Gap = FRow - 1;\r
+  }\r
+\r
+  Retreat = Gap;\r
+  Retreat = -Retreat;\r
+\r
+  //\r
+  // get correct line\r
+  //\r
+  Line = HMoveLine (Retreat);\r
+\r
+  FRow -= Gap;\r
+\r
+  HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageHome (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Scroll cursor to start of line\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  HEFI_EDITOR_LINE  *Line;\r
+  UINTN             FRow;\r
+  UINTN             FCol;\r
+  BOOLEAN           HighBits;\r
+\r
+  Line = HBufferImage.CurrentLine;\r
+\r
+  //\r
+  // curosr will at the high bit\r
+  //\r
+  FRow      = HBufferImage.BufferPosition.Row;\r
+  FCol      = 1;\r
+  HighBits  = TRUE;\r
+\r
+  //\r
+  // move cursor position\r
+  //\r
+  HBufferImageMovePosition (FRow, FCol, HighBits);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageEnd (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Scroll cursor to end of line\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  HEFI_EDITOR_LINE  *Line;\r
+  UINTN             FRow;\r
+  UINTN             FCol;\r
+  BOOLEAN           HighBits;\r
+\r
+  //\r
+  // need refresh mouse\r
+  //\r
+  HBufferImageMouseNeedRefresh  = TRUE;\r
+\r
+  Line                          = HBufferImage.CurrentLine;\r
+\r
+  FRow                          = HBufferImage.BufferPosition.Row;\r
+\r
+  if (Line->Size == 0x10) {\r
+    FCol      = Line->Size;\r
+    HighBits  = FALSE;\r
+  } else {\r
+    FCol      = Line->Size + 1;\r
+    HighBits  = TRUE;\r
+  }\r
+  //\r
+  // move cursor position\r
+  //\r
+  HBufferImageMovePosition (FRow, FCol, HighBits);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+UINTN\r
+HBufferImageGetTotalSize (\r
+  VOID\r
+  )\r
+{\r
+  UINTN             Size;\r
+\r
+  HEFI_EDITOR_LINE  *Line;\r
+\r
+  //\r
+  // calculate the total size of whole line list's buffer\r
+  //\r
+  if (HBufferImage.Lines == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  Line = CR (\r
+          HBufferImage.ListHead->BackLink,\r
+          HEFI_EDITOR_LINE,\r
+          Link,\r
+          EFI_EDITOR_LINE_LIST\r
+          );\r
+  //\r
+  // one line at most 0x10\r
+  //\r
+  Size = 0x10 * (HBufferImage.NumLines - 1) + Line->Size;\r
+\r
+  return Size;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageDeleteCharacterFromBuffer (\r
+  IN  UINTN         Pos,\r
+  IN  UINTN         Count,\r
+  OUT UINT8         *DeleteBuffer\r
+  )\r
+/*++\r
+Routine Description:\r
+\r
+  Delete character from buffer\r
+  \r
+Arguments:\r
+\r
+  Pos - Position, Pos starting from 0\r
+  Count - Count\r
+  DeleteBuffer - DeleteBuffer\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS Success\r
+  \r
+--*/\r
+{\r
+  UINTN             Index;\r
+\r
+  VOID              *Buffer;\r
+  UINT8             *BufferPtr;\r
+  UINTN             Size;\r
+\r
+  HEFI_EDITOR_LINE  *Line;\r
+  LIST_ENTRY    *Link;\r
+  UINTN             StartRow;\r
+\r
+  UINTN             OldFCol;\r
+  UINTN             OldFRow;\r
+  UINTN             OldPos;\r
+\r
+  UINTN             NewPos;\r
+\r
+  EFI_STATUS        Status;\r
+\r
+  //\r
+  // get the line that start position is at\r
+  //\r
+  StartRow  = Pos / 0x10;\r
+\r
+  Size      = HBufferImageGetTotalSize ();\r
+\r
+  if (Size < Count) {\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  if (Size == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // relocate all the HBufferImage fields\r
+  //\r
+  OldFRow = HBufferImage.BufferPosition.Row;\r
+  OldFCol = HBufferImage.BufferPosition.Column;\r
+  OldPos  = (OldFRow - 1) * 0x10 + OldFCol - 1;\r
+\r
+  if (Pos > 0) {\r
+    //\r
+    // has character before it,\r
+    // so locate according to block's previous character\r
+    //\r
+    NewPos = Pos - 1;\r
+\r
+  } else {\r
+    //\r
+    // has no character before it,\r
+    // so locate according to block's next character\r
+    //\r
+    NewPos = 0;\r
+  }\r
+\r
+  HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE);\r
+\r
+  Buffer = AllocateZeroPool (Size);\r
+  if (Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  HBufferImageListToBuffer (Buffer, Size);\r
+\r
+  BufferPtr = (UINT8 *) Buffer;\r
+\r
+  //\r
+  // pass deleted buffer out\r
+  //\r
+  if (DeleteBuffer != NULL) {\r
+    for (Index = 0; Index < Count; Index++) {\r
+      DeleteBuffer[Index] = BufferPtr[Pos + Index];\r
+    }\r
+  }\r
+  //\r
+  // delete the part from Pos\r
+  //\r
+  for (Index = Pos; Index < Size - Count; Index++) {\r
+    BufferPtr[Index] = BufferPtr[Index + Count];\r
+  }\r
+\r
+  Size -= Count;\r
+\r
+  HBufferImageFreeLines ();\r
+\r
+  Status = HBufferImageBufferToList (Buffer, Size);\r
+  FreePool (Buffer);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Link = HMainEditor.BufferImage->ListHead->ForwardLink;\r
+  for (Index = 0; Index < NewPos / 0x10; Index++) {\r
+    Link = Link->ForwardLink;\r
+  }\r
+\r
+  Line                      = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);\r
+  HBufferImage.CurrentLine  = Line;\r
+\r
+  //\r
+  // if current cursor position if inside select area\r
+  // then move it to the block's NEXT character\r
+  //\r
+  if (OldPos >= Pos && OldPos < (Pos + Count)) {\r
+    NewPos = Pos;\r
+  } else {\r
+    if (OldPos < Pos) {\r
+      NewPos = OldPos;\r
+    } else {\r
+      NewPos = OldPos - Count;\r
+    }\r
+  }\r
+\r
+  HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageAddCharacterToBuffer (\r
+  IN  UINTN          Pos,\r
+  IN  UINTN          Count,\r
+  IN  UINT8          *AddBuffer\r
+  )\r
+/*++'\r
+Routine Description:\r
+\r
+  Add character to buffer, add before pos\r
+\r
+Arguments:\r
+\r
+  Pos - Position, Pos starting from 0\r
+  Count - Count\r
+  AddBuffer - Add buffer\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS Success\r
+  \r
+--*/\r
+{\r
+  INTN              Index;\r
+\r
+  VOID              *Buffer;\r
+  UINT8             *BufferPtr;\r
+  UINTN             Size;\r
+\r
+  HEFI_EDITOR_LINE  *Line;\r
+\r
+  LIST_ENTRY    *Link;\r
+  UINTN             StartRow;\r
+\r
+  UINTN             OldFCol;\r
+  UINTN             OldFRow;\r
+  UINTN             OldPos;\r
+\r
+  UINTN             NewPos;\r
+\r
+  //\r
+  // get the line that start position is at\r
+  //\r
+  StartRow  = Pos / 0x10;\r
+\r
+  Size      = HBufferImageGetTotalSize ();\r
+\r
+  //\r
+  // relocate all the HBufferImage fields\r
+  //\r
+  OldFRow = HBufferImage.BufferPosition.Row;\r
+  OldFCol = HBufferImage.BufferPosition.Column;\r
+  OldPos  = (OldFRow - 1) * 0x10 + OldFCol - 1;\r
+\r
+  //\r
+  // move cursor before Pos\r
+  //\r
+  if (Pos > 0) {\r
+    NewPos = Pos - 1;\r
+  } else {\r
+    NewPos = 0;\r
+  }\r
+\r
+  HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE);\r
+\r
+  Buffer = AllocateZeroPool (Size + Count);\r
+  if (Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  HBufferImageListToBuffer (Buffer, Size);\r
+\r
+  BufferPtr = (UINT8 *) Buffer;\r
+\r
+  //\r
+  // get a place to add\r
+  //\r
+  for (Index = (INTN) (Size + Count - 1); Index >= (INTN) Pos; Index--) {\r
+    BufferPtr[Index] = BufferPtr[Index - Count];\r
+  }\r
+  //\r
+  // add the buffer\r
+  //\r
+  for (Index = (INTN) 0; Index < (INTN) Count; Index++) {\r
+    BufferPtr[Index + Pos] = AddBuffer[Index];\r
+  }\r
+\r
+  Size += Count;\r
+\r
+  HBufferImageFreeLines ();\r
+\r
+  HBufferImageBufferToList (Buffer, Size);\r
+\r
+  FreePool (Buffer);\r
+\r
+  Link = HMainEditor.BufferImage->ListHead->ForwardLink;\r
+  for (Index = 0; Index < (INTN) NewPos / 0x10; Index++) {\r
+    Link = Link->ForwardLink;\r
+  }\r
+\r
+  Line                      = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);\r
+  HBufferImage.CurrentLine  = Line;\r
+\r
+  if (OldPos >= Pos) {\r
+    NewPos = OldPos + Count;\r
+  } else {\r
+    NewPos = OldPos;\r
+  }\r
+\r
+  HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageDoBackspace (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  delete the previous character\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  HEFI_EDITOR_LINE  *Line;\r
+\r
+  UINTN             FileColumn;\r
+  UINTN             FPos;\r
+  BOOLEAN           LastLine;\r
+\r
+  //\r
+  // variable initialization\r
+  //\r
+  LastLine = FALSE;\r
+\r
+  //\r
+  // already the first character\r
+  //\r
+  if (HBufferImage.BufferPosition.Row == 1 && HBufferImage.BufferPosition.Column == 1) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  FPos        = (HBufferImage.BufferPosition.Row - 1) * 0x10 + HBufferImage.BufferPosition.Column - 1;\r
+\r
+  FileColumn  = HBufferImage.BufferPosition.Column;\r
+\r
+  Line        = HBufferImage.CurrentLine;\r
+  LastLine    = FALSE;\r
+  if (Line->Link.ForwardLink == HBufferImage.ListHead && FileColumn > 1) {\r
+    LastLine = TRUE;\r
+  }\r
+\r
+  HBufferImageDeleteCharacterFromBuffer (FPos - 1, 1, NULL);\r
+\r
+  //\r
+  // if is the last line\r
+  // then only this line need to be refreshed\r
+  //\r
+  if (LastLine) {\r
+    HBufferImageNeedRefresh         = FALSE;\r
+    HBufferImageOnlyLineNeedRefresh = TRUE;\r
+  } else {\r
+    HBufferImageNeedRefresh         = TRUE;\r
+    HBufferImageOnlyLineNeedRefresh = FALSE;\r
+  }\r
+\r
+  if (!HBufferImage.Modified) {\r
+    HBufferImage.Modified = TRUE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageDoDelete (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Delete current character from line\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+\r
+  HEFI_EDITOR_LINE  *Line;\r
+\r
+  BOOLEAN           LastLine;\r
+  UINTN             FileColumn;\r
+  UINTN             FPos;\r
+\r
+  FPos        = (HBufferImage.BufferPosition.Row - 1) * 0x10 + HBufferImage.BufferPosition.Column - 1;\r
+\r
+  FileColumn  = HBufferImage.BufferPosition.Column;\r
+\r
+  Line        = HBufferImage.CurrentLine;\r
+\r
+  //\r
+  // if beyond the last character\r
+  //\r
+  if (FileColumn > Line->Size) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  LastLine = FALSE;\r
+  if (Line->Link.ForwardLink == HBufferImage.ListHead) {\r
+    LastLine = TRUE;\r
+  }\r
+\r
+  HBufferImageDeleteCharacterFromBuffer (FPos, 1, NULL);\r
+\r
+  //\r
+  // if is the last line\r
+  // then only this line need to be refreshed\r
+  //\r
+  if (LastLine) {\r
+    HBufferImageNeedRefresh         = FALSE;\r
+    HBufferImageOnlyLineNeedRefresh = TRUE;\r
+  } else {\r
+    HBufferImageNeedRefresh         = TRUE;\r
+    HBufferImageOnlyLineNeedRefresh = FALSE;\r
+  }\r
+\r
+  if (!HBufferImage.Modified) {\r
+    HBufferImage.Modified = TRUE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageBufferToList (\r
+  IN VOID   *Buffer,\r
+  IN UINTN  Bytes\r
+  )\r
+{\r
+  UINTN             i;\r
+  UINTN             j;\r
+  UINTN             Left;\r
+  HEFI_EDITOR_LINE  *Line;\r
+  UINT8             *BufferPtr;\r
+\r
+  i         = 0;\r
+  Left      = 0;\r
+  BufferPtr = (UINT8 *) Buffer;\r
+\r
+  //\r
+  // parse file content line by line\r
+  //\r
+  while (i < Bytes) {\r
+    if (Bytes - i >= 0x10) {\r
+      Left = 0x10;\r
+    } else {\r
+      Left = Bytes - i;\r
+    }\r
+\r
+    //\r
+    // allocate a new line\r
+    //\r
+    Line = HBufferImageCreateLine ();\r
+    if (Line == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Line->Size = Left;\r
+\r
+    for (j = 0; j < Left; j++) {\r
+      Line->Buffer[j] = BufferPtr[i];\r
+      i++;\r
+    }\r
+\r
+  }\r
+\r
+  //\r
+  // last line is a full line, SO create a new line\r
+  //\r
+  if (Left == 0x10 || Bytes == 0) {\r
+    Line = HBufferImageCreateLine ();\r
+    if (Line == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HBufferImageListToBuffer (\r
+  IN VOID   *Buffer,\r
+  IN UINTN  Bytes\r
+  )\r
+{\r
+  UINTN             Count;\r
+  UINTN             Index;\r
+  HEFI_EDITOR_LINE  *Line;\r
+  LIST_ENTRY    *Link;\r
+  UINT8             *BufferPtr;\r
+\r
+  //\r
+  // change the line list to a large buffer\r
+  //\r
+  if (HBufferImage.Lines == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Link      = &HBufferImage.Lines->Link;\r
+  Count     = 0;\r
+  BufferPtr = (UINT8 *) Buffer;\r
+\r
+  //\r
+  // deal line by line\r
+  //\r
+  while (Link != HBufferImage.ListHead) {\r
+\r
+    Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);\r
+\r
+    if (Count + Line->Size > Bytes) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    for (Index = 0; Index < Line->Size; Index++) {\r
+      BufferPtr[Index] = Line->Buffer[Index];\r
+    }\r
+\r
+    Count += Line->Size;\r
+    BufferPtr += Line->Size;\r
+\r
+    Link = Link->ForwardLink;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+HBufferImageAdjustMousePosition (\r
+  IN INT32 TextX,\r
+  IN INT32 TextY\r
+  )\r
+{\r
+  UINTN X;\r
+  UINTN Y;\r
+  UINTN AbsX;\r
+  UINTN AbsY;\r
+\r
+  //\r
+  // TextX and TextY is mouse movement data returned by mouse driver\r
+  // This function will change it to MousePosition\r
+  //\r
+  //\r
+  // get absolute X value\r
+  //\r
+  if (TextX >= 0) {\r
+    AbsX = TextX;\r
+  } else {\r
+    AbsX = -TextX;\r
+  }\r
+  //\r
+  // get absolute Y value\r
+  //\r
+  if (TextY >= 0) {\r
+    AbsY = TextY;\r
+  } else {\r
+    AbsY = -TextY;\r
+  }\r
+\r
+  X = HBufferImage.MousePosition.Column;\r
+  Y = HBufferImage.MousePosition.Row;\r
+\r
+  if (TextX >= 0) {\r
+    X += TextX;\r
+  } else {\r
+    if (X >= AbsX) {\r
+      X -= AbsX;\r
+    } else {\r
+      X = 0;\r
+    }\r
+  }\r
+\r
+  if (TextY >= 0) {\r
+    Y += TextY;\r
+  } else {\r
+    if (Y >= AbsY) {\r
+      Y -= AbsY;\r
+    } else {\r
+      Y = 0;\r
+    }\r
+  }\r
+  //\r
+  // check whether new mouse column position is beyond screen\r
+  // if not, adjust it\r
+  //\r
+  if (X >= 10 && X <= (10 + 0x10 * 3 - 1)) {\r
+    HBufferImage.MousePosition.Column = X;\r
+  } else if (X < 10) {\r
+    HBufferImage.MousePosition.Column = 10;\r
+  } else if (X > (10 + 0x10 * 3 - 1)) {\r
+    HBufferImage.MousePosition.Column = 10 + 0x10 * 3 - 1;\r
+  }\r
+  //\r
+  // check whether new mouse row position is beyond screen\r
+  // if not, adjust it\r
+  //\r
+  if (Y >= 2 && Y <= (HMainEditor.ScreenSize.Row - 4)) {\r
+    HBufferImage.MousePosition.Row = Y;\r
+  } else if (Y < 2) {\r
+    HBufferImage.MousePosition.Row = 2;\r
+  } else if (Y > (HMainEditor.ScreenSize.Row - 4)) {\r
+    HBufferImage.MousePosition.Row = (HMainEditor.ScreenSize.Row - 4);\r
+  }\r
+\r
+}\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.h
new file mode 100644 (file)
index 0000000..d661e50
--- /dev/null
@@ -0,0 +1,250 @@
+/** @file\r
+    Defines BufferImage - the view of the file that is visible at any point, \r
+    as well as the event handlers for editing the file\r
+  \r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _LIB_BUFFER_IMAGE_H_\r
+#define _LIB_BUFFER_IMAGE_H_\r
+\r
+#include "HexEditor.h"\r
+\r
+EFI_STATUS\r
+HBufferImageInit (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageCleanup (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageRefresh (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageHide (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageHandleInput (\r
+  EFI_INPUT_KEY *\r
+  );\r
+EFI_STATUS\r
+HBufferImageBackup (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageRead (\r
+  IN CONST CHAR16   *,\r
+  IN CONST CHAR16   *,\r
+  IN          UINTN,\r
+  IN          UINTN,\r
+  IN          UINTN,\r
+  IN          UINTN,\r
+  IN          EDIT_FILE_TYPE,\r
+  IN          BOOLEAN\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageSave (\r
+  IN CHAR16   *,\r
+  IN CHAR16   *,\r
+  IN          UINTN,\r
+  IN          UINTN,\r
+  IN          UINTN,\r
+  IN          UINTN,\r
+  IN          EDIT_FILE_TYPE\r
+  );\r
+\r
+INTN\r
+HBufferImageCharToHex (\r
+  IN CHAR16\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageRestoreMousePosition (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageRestorePosition (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+HBufferImageMovePosition (\r
+  IN UINTN,\r
+  IN UINTN,\r
+  IN BOOLEAN\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageHandleInput (\r
+  EFI_INPUT_KEY *\r
+  );\r
+\r
+HEFI_EDITOR_LINE  *\r
+HBufferImageCreateLine (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageDoCharInput (\r
+  CHAR16\r
+  );\r
+EFI_STATUS\r
+HBufferImageAddChar (\r
+  CHAR16\r
+  );\r
+\r
+BOOLEAN\r
+HInCurrentScreen (\r
+  UINTN\r
+  );\r
+BOOLEAN\r
+HAboveCurrentScreen (\r
+  UINTN\r
+  );\r
+BOOLEAN\r
+HUnderCurrentScreen (\r
+  UINTN\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageScrollRight (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageScrollLeft (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageScrollDown (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageScrollUp (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImagePageUp (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImagePageDown (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageHome (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageEnd (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageDoBackspace (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HBufferImageDoDelete (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageCutLine (\r
+  HEFI_EDITOR_LINE **\r
+  );\r
+EFI_STATUS\r
+HBufferImagePasteLine (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageGetFileInfo (\r
+  EFI_FILE_HANDLE,\r
+  CHAR16          *,\r
+  EFI_FILE_INFO   **\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageSearch (\r
+  CHAR16  *,\r
+  UINTN\r
+  );\r
+EFI_STATUS\r
+HBufferImageReplace (\r
+  CHAR16  *,\r
+  UINTN\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageFree (\r
+  VOID\r
+  ) ;\r
+\r
+EFI_STATUS\r
+HBufferImageDeleteCharacterFromBuffer (\r
+  IN      UINTN,\r
+  IN      UINTN,\r
+  UINT8   *\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageAddCharacterToBuffer (\r
+  IN      UINTN,\r
+  IN      UINTN,\r
+  UINT8   *\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageBufferToList (\r
+  IN VOID   *,\r
+  IN        UINTN\r
+  );\r
+\r
+EFI_STATUS\r
+HBufferImageListToBuffer (\r
+  IN VOID   *,\r
+  IN        UINTN\r
+  );\r
+\r
+VOID\r
+HBufferImageAdjustMousePosition (\r
+  INT32,\r
+  INT32\r
+  );\r
+\r
+BOOLEAN\r
+HBufferImageIsAtHighBits (\r
+  UINTN,\r
+  UINTN *\r
+  ) ;\r
+\r
+EFI_STATUS\r
+HBufferImageCutLine (\r
+  HEFI_EDITOR_LINE **\r
+  );\r
+\r
+UINTN\r
+HBufferImageGetTotalSize (\r
+  VOID\r
+  );\r
+\r
+BOOLEAN\r
+HBufferImageIsInSelectedArea (\r
+  UINTN,\r
+  UINTN\r
+  );\r
+\r
+#endif\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.c
new file mode 100644 (file)
index 0000000..2408027
--- /dev/null
@@ -0,0 +1,112 @@
+/** @file\r
+    Functions to deal with Clip Board\r
+  \r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HexEditor.h"\r
+\r
+HEFI_EDITOR_CLIPBOARD HClipBoard;\r
+\r
+//\r
+// for basic initialization of HClipBoard\r
+//\r
+HEFI_EDITOR_CLIPBOARD HClipBoardConst = {\r
+  NULL,\r
+  0\r
+};\r
+\r
+EFI_STATUS\r
+HClipBoardInit (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Initialization function for HDiskImage\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+  EFI_LOAD_ERROR\r
+\r
+--*/\r
+{\r
+  //\r
+  // basiclly initialize the HDiskImage\r
+  //\r
+  CopyMem (&HClipBoard, &HClipBoardConst, sizeof (HClipBoard));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HClipBoardCleanup (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Initialization function for HDiskImage\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+  EFI_LOAD_ERROR\r
+\r
+--*/\r
+{\r
+\r
+  SHELL_FREE_NON_NULL (HClipBoard.Buffer);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HClipBoardSet (\r
+  IN UINT8 *Buffer,\r
+  IN UINTN Size\r
+  )\r
+{\r
+  //\r
+  // free the old clipboard buffer\r
+  // and set new clipboard buffer\r
+  //\r
+  SHELL_FREE_NON_NULL (HClipBoard.Buffer);\r
+  HClipBoard.Buffer = Buffer;\r
+\r
+  HClipBoard.Size   = Size;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+UINTN\r
+HClipBoardGet (\r
+  OUT UINT8  **Buffer\r
+  )\r
+{\r
+  //\r
+  // return the clipboard buffer\r
+  //\r
+  *Buffer = HClipBoard.Buffer;\r
+\r
+  return HClipBoard.Size;\r
+}\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.h
new file mode 100644 (file)
index 0000000..9165d98
--- /dev/null
@@ -0,0 +1,40 @@
+/** @file\r
+    Defines DiskImage - the view of the file that is visible at any point, \r
+    as well as the event handlers for editing the file\r
+  \r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _LIB_CLIP_BOARD_H_\r
+#define _LIB_CLIP_BOARD_H_\r
+\r
+#include "HexEditor.h"\r
+\r
+EFI_STATUS\r
+HClipBoardInit (\r
+  VOID\r
+  );\r
+EFI_STATUS\r
+HClipBoardCleanup (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+HClipBoardSet (\r
+  UINT8   *,\r
+  UINTN\r
+  );\r
+UINTN\r
+HClipBoardGet (\r
+  UINT8 **\r
+  );\r
+\r
+#endif\r
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.c
new file mode 100644 (file)
index 0000000..140db71
--- /dev/null
@@ -0,0 +1,487 @@
+/** @file\r
+  Functions to deal with Disk buffer.\r
+\r
+  Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HexEditor.h"\r
+#include <Protocol/BlockIo.h>\r
+\r
+extern EFI_HANDLE                 HImageHandleBackup;\r
+extern HEFI_EDITOR_BUFFER_IMAGE   HBufferImage;\r
+\r
+extern BOOLEAN                    HBufferImageNeedRefresh;\r
+extern BOOLEAN                    HBufferImageOnlyLineNeedRefresh;\r
+extern BOOLEAN                    HBufferImageMouseNeedRefresh;\r
+\r
+extern HEFI_EDITOR_GLOBAL_EDITOR  HMainEditor;\r
+\r
+HEFI_EDITOR_DISK_IMAGE            HDiskImage;\r
+HEFI_EDITOR_DISK_IMAGE            HDiskImageBackupVar;\r
+\r
+//\r
+// for basic initialization of HDiskImage\r
+//\r
+HEFI_EDITOR_DISK_IMAGE            HDiskImageConst = {\r
+  NULL,\r
+  0,\r
+  0,\r
+  0\r
+};\r
+\r
+EFI_STATUS\r
+HDiskImageInit (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Initialization function for HDiskImage\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+  EFI_LOAD_ERROR\r
+\r
+--*/\r
+{\r
+  //\r
+  // basically initialize the HDiskImage\r
+  //\r
+  CopyMem (&HDiskImage, &HDiskImageConst, sizeof (HDiskImage));\r
+\r
+  CopyMem (&HDiskImageBackupVar, &HDiskImageConst, sizeof (HDiskImageBackupVar));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HDiskImageBackup (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Backup function for HDiskImage\r
+  Only a few fields need to be backup. \r
+  This is for making the Disk buffer refresh \r
+  as few as possible.\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS          - Success\r
+  EFI_OUT_OF_RESOURCES - gST->ConOut of resources\r
+\r
+--*/\r
+{\r
+  //\r
+  // backup the disk name, offset and size\r
+  //\r
+  //\r
+  SHELL_FREE_NON_NULL (HDiskImageBackupVar.Name);\r
+\r
+  HDiskImageBackupVar.Name = CatSPrint(NULL, L"%s", HDiskImage.Name);\r
+  if (HDiskImageBackupVar.Name == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  HDiskImageBackupVar.Offset  = HDiskImage.Offset;\r
+  HDiskImageBackupVar.Size    = HDiskImage.Size;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HDiskImageCleanup (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Cleanup function for HDiskImage\r
+\r
+Arguments:  \r
+\r
+  None\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+  SHELL_FREE_NON_NULL (HDiskImage.Name);\r
+  SHELL_FREE_NON_NULL (HDiskImageBackupVar.Name);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+HDiskImageSetDiskNameOffsetSize (\r
+  IN CONST CHAR16   *Str,\r
+  IN UINTN    Offset,\r
+  IN UINTN    Size\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Set FileName field in HFileImage\r
+\r
+Arguments:  \r
+\r
+  Str    - File name to set\r
+  Offset - The offset\r
+  Size   - The size\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+  EFI_OUT_OF_RESOURCES\r
+\r
+--*/\r
+{\r
+  UINTN Len;\r
+  UINTN Index;\r
+\r
+  //\r
+  // free the old file name\r
+  //\r
+  SHELL_FREE_NON_NULL (HDiskImage.Name);\r
+\r
+  Len             = StrLen (Str);\r
+\r
+  HDiskImage.Name = AllocateZeroPool (2 * (Len + 1));\r
+  if (HDiskImage.Name == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (Index = 0; Index < Len; Index++) {\r
+    HDiskImage.Name[Index] = Str[Index];\r
+  }\r
+\r
+  HDiskImage.Name[Len]  = L'\0';\r
+\r
+  HDiskImage.Offset     = Offset;\r
+  HDiskImage.Size       = Size;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HDiskImageRead (\r
+  IN CONST CHAR16   *DeviceName,\r
+  IN UINTN    Offset,\r
+  IN UINTN    Size,\r
+  IN BOOLEAN  Recover\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Read a disk from disk into HBufferImage\r
+\r
+Arguments:  \r
+\r
+  DeviceName - filename to read\r
+  Offset     - The offset\r
+  Size       - The size\r
+  Recover    - if is for recover, no information print\r
+\r
+Returns:  \r
+\r
+  EFI_SUCCESS\r
+  EFI_LOAD_ERROR\r
+  EFI_OUT_OF_RESOURCES\r
+  EFI_INVALID_PARAMETER \r
+  \r
+--*/\r
+{\r
+  CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DupDevicePath;\r
+  EFI_HANDLE                      Handle;\r
+  EFI_BLOCK_IO_PROTOCOL           *BlkIo;\r
+  EFI_STATUS                      Status;\r
+\r
+  VOID                            *Buffer;\r
+  CHAR16                          *Str;\r
+  UINTN                           Bytes;\r
+\r
+  HEFI_EDITOR_LINE                *Line;\r
+  UINT64                          ByteOffset;\r
+\r
+  EDIT_FILE_TYPE                  BufferTypeBackup;\r
+\r
+  BufferTypeBackup        = HBufferImage.BufferType;\r
+  HBufferImage.BufferType = FileTypeDiskBuffer;\r
+\r
+  DevicePath              = gEfiShellProtocol->GetDevicePathFromMap(DeviceName);\r
+  if (DevicePath == NULL) {\r
+    StatusBarSetStatusString (L"Cannot Find Device");\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  DupDevicePath = DuplicateDevicePath(DevicePath);\r
+  //\r
+  // get blkio interface\r
+  //\r
+  Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid,&DupDevicePath,&Handle);\r
+  FreePool(DupDevicePath);\r
+  if (EFI_ERROR (Status)) {\r
+    StatusBarSetStatusString (L"Read Disk Failed");\r
+    return Status;\r
+  }\r
+  Status = gBS->OpenProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID**)&BlkIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+  if (EFI_ERROR (Status)) {\r
+    StatusBarSetStatusString (L"Read Disk Failed");\r
+    return Status;\r
+  }\r
+  //\r
+  // if Offset exceeds LastBlock,\r
+  //   return error\r
+  //\r
+  if (Offset > BlkIo->Media->LastBlock || Offset + Size > BlkIo->Media->LastBlock) {\r
+    StatusBarSetStatusString (L"Invalid Offset + Size");\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  Bytes   = BlkIo->Media->BlockSize * Size;\r
+  Buffer  = AllocateZeroPool (Bytes);\r
+\r
+  if (Buffer == NULL) {\r
+    StatusBarSetStatusString (L"Read Disk Failed");\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ByteOffset = MultU64x32 (Offset, BlkIo->Media->BlockSize);\r
+\r
+  //\r
+  // read from disk\r
+  //\r
+  Status = BlkIo->ReadBlocks (\r
+                    BlkIo,\r
+                    BlkIo->Media->MediaId,\r
+                    Offset,\r
+                    Bytes,\r
+                    Buffer\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Buffer);\r
+    StatusBarSetStatusString (L"Read Disk Failed");\r
+    return EFI_LOAD_ERROR;\r
+  }\r
+\r
+  HBufferImageFree ();\r
+\r
+  //\r
+  // convert buffer to line list\r
+  //\r
+  Status = HBufferImageBufferToList (Buffer, Bytes);\r
+  FreePool (Buffer);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    StatusBarSetStatusString (L"Read Disk Failed");\r
+    return Status;\r
+  }\r
+\r
+  Status = HDiskImageSetDiskNameOffsetSize (DeviceName, Offset, Size);\r
+  if (EFI_ERROR (Status)) {\r
+    StatusBarSetStatusString (L"Read Disk Failed");\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // initialize some variables\r
+  //\r
+  HDiskImage.BlockSize                = BlkIo->Media->BlockSize;\r
+\r
+  HBufferImage.DisplayPosition.Row    = 2;\r
+  HBufferImage.DisplayPosition.Column = 10;\r
+\r
+  HBufferImage.MousePosition.Row      = 2;\r
+  HBufferImage.MousePosition.Column   = 10;\r
+\r
+  HBufferImage.LowVisibleRow          = 1;\r
+  HBufferImage.HighBits               = TRUE;\r
+\r
+  HBufferImage.BufferPosition.Row     = 1;\r
+  HBufferImage.BufferPosition.Column  = 1;\r
+\r
+  if (!Recover) {\r
+    Str = CatSPrint(NULL, L"%d Lines Read", HBufferImage.NumLines);\r
+    if (Str == NULL) {\r
+      StatusBarSetStatusString (L"Read Disk Failed");\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    StatusBarSetStatusString (Str);\r
+    SHELL_FREE_NON_NULL (Str);\r
+\r
+    HMainEditor.SelectStart = 0;\r
+    HMainEditor.SelectEnd   = 0;\r
+\r
+  }\r
+\r
+  //\r
+  // has line\r
+  //\r
+  if (HBufferImage.Lines != NULL) {\r
+    HBufferImage.CurrentLine = CR (\r
+                                HBufferImage.ListHead->ForwardLink,\r
+                                HEFI_EDITOR_LINE,\r
+                                Link,\r
+                                EFI_EDITOR_LINE_LIST\r
+                                );\r
+  } else {\r
+    //\r
+    // create a dummy line\r
+    //\r
+    Line = HBufferImageCreateLine ();\r
+    if (Line == NULL) {\r
+      StatusBarSetStatusString (L"Read Disk Failed");\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    HBufferImage.CurrentLine = Line;\r
+  }\r
+\r
+  HBufferImage.Modified           = FALSE;\r
+  HBufferImageNeedRefresh         = TRUE;\r
+  HBufferImageOnlyLineNeedRefresh = FALSE;\r
+  HBufferImageMouseNeedRefresh    = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HDiskImageSave (\r
+  IN CHAR16 *DeviceName,\r
+  IN UINTN  Offset,\r
+  IN UINTN  Size\r
+  )\r
+/*++\r
+\r
+Routine Description: \r
+\r
+  Save lines in HBufferImage to disk