Home | History | Annotate | Download | only in HexEdit
      1 /** @file
      2     Defines the Main Editor data type -
      3      - Global variables
      4      - Instances of the other objects of the editor
      5      - Main Interfaces
      6 
      7   Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved. <BR>
      8   This program and the accompanying materials
      9   are licensed and made available under the terms and conditions of the BSD License
     10   which accompanies this distribution.  The full text of the license may be found at
     11   http://opensource.org/licenses/bsd-license.php
     12 
     13   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include "HexEditor.h"
     19 #include "EditStatusBar.h"
     20 #include "EditInputBar.h"
     21 
     22 HEFI_EDITOR_COLOR_ATTRIBUTES    HOriginalColors;
     23 INTN                            HOriginalMode;
     24 
     25 //
     26 // the first time editor launch
     27 //
     28 BOOLEAN                         HEditorFirst;
     29 
     30 //
     31 // it's time editor should exit
     32 //
     33 BOOLEAN                         HEditorExit;
     34 
     35 BOOLEAN                         HEditorMouseAction;
     36 
     37 extern HEFI_EDITOR_BUFFER_IMAGE HBufferImage;
     38 extern HEFI_EDITOR_BUFFER_IMAGE HBufferImageBackupVar;
     39 
     40 extern BOOLEAN                  HBufferImageMouseNeedRefresh;
     41 extern BOOLEAN                  HBufferImageNeedRefresh;
     42 extern BOOLEAN                  HBufferImageOnlyLineNeedRefresh;
     43 
     44 HEFI_EDITOR_GLOBAL_EDITOR       HMainEditor;
     45 HEFI_EDITOR_GLOBAL_EDITOR       HMainEditorBackupVar;
     46 
     47 //
     48 // basic initialization for MainEditor
     49 //
     50 HEFI_EDITOR_GLOBAL_EDITOR       HMainEditorConst = {
     51   &HBufferImage,
     52   {
     53     {0, 0}
     54   },
     55   {
     56     0,
     57     0
     58   },
     59   FALSE,
     60   NULL,
     61   0,
     62   0,
     63   1,
     64   1
     65 };
     66 
     67 /**
     68   Help info that will be displayed.
     69 **/
     70 EFI_STRING_ID  HexMainMenuHelpInfo[] = {
     71   STRING_TOKEN(STR_HEXEDIT_HELP_TITLE),
     72   STRING_TOKEN(STR_HEXEDIT_HELP_BLANK),
     73   STRING_TOKEN(STR_HEXEDIT_HELP_LIST_TITLE),
     74   STRING_TOKEN(STR_HEXEDIT_HELP_DIV),
     75   STRING_TOKEN(STR_HEXEDIT_HELP_GO_TO_OFFSET),
     76   STRING_TOKEN(STR_HEXEDIT_HELP_SAVE_BUFFER),
     77   STRING_TOKEN(STR_HEXEDIT_HELP_EXIT),
     78   STRING_TOKEN(STR_HEXEDIT_HELP_SELECT_START),
     79   STRING_TOKEN(STR_HEXEDIT_HELP_SELECT_END),
     80   STRING_TOKEN(STR_HEXEDIT_HELP_CUT),
     81   STRING_TOKEN(STR_HEXEDIT_HELP_PASTE),
     82   STRING_TOKEN(STR_HEXEDIT_HELP_OPEN_FILE),
     83   STRING_TOKEN(STR_HEXEDIT_HELP_OPEN_DISK),
     84   STRING_TOKEN(STR_HEXEDIT_HELP_OPEN_MEMORY),
     85   STRING_TOKEN(STR_HEXEDIT_HELP_BLANK),
     86   STRING_TOKEN(STR_HEXEDIT_HELP_EXIT_HELP),
     87   STRING_TOKEN(STR_HEXEDIT_HELP_BLANK),
     88   STRING_TOKEN(STR_HEXEDIT_HELP_BLANK),
     89   STRING_TOKEN(STR_HEXEDIT_HELP_BLANK),
     90   STRING_TOKEN(STR_HEXEDIT_HELP_BLANK),
     91   STRING_TOKEN(STR_HEXEDIT_HELP_BLANK),
     92   STRING_TOKEN(STR_HEXEDIT_HELP_BLANK),
     93   STRING_TOKEN(STR_HEXEDIT_HELP_DIV),
     94   0
     95 };
     96 
     97 
     98 /**
     99   show help menu.
    100 
    101   @retval EFI_SUCCESS             The operation was successful.
    102 **/
    103 EFI_STATUS
    104 HMainCommandDisplayHelp (
    105   VOID
    106   )
    107 {
    108   INT32    CurrentLine;
    109   CHAR16 * InfoString;
    110   EFI_INPUT_KEY  Key;
    111 
    112   CurrentLine = 0;
    113   // print helpInfo
    114   for (CurrentLine = 0; 0 != HexMainMenuHelpInfo[CurrentLine]; CurrentLine++) {
    115     InfoString = HiiGetString(gShellDebug1HiiHandle, HexMainMenuHelpInfo[CurrentLine]
    116 , NULL);
    117     ShellPrintEx (0,CurrentLine+1,L"%E%s%N",InfoString);
    118   }
    119 
    120   // scan for ctrl+w
    121   do {
    122     gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    123   } while(SCAN_CONTROL_W != Key.UnicodeChar);
    124 
    125   // update screen with buffer's info
    126   HBufferImageNeedRefresh = TRUE;
    127   HBufferImageOnlyLineNeedRefresh = FALSE;
    128   HBufferImageRefresh ();
    129 
    130   return EFI_SUCCESS;
    131 }
    132 
    133 /**
    134   Move cursor to specified lines.
    135 
    136   @retval EFI_SUCCESS   The operation was successful.
    137 **/
    138 EFI_STATUS
    139 HMainCommandGoToOffset (
    140   VOID
    141   )
    142 {
    143   UINTN       Size;
    144   UINT64      Offset;
    145   EFI_STATUS  Status;
    146   UINTN       FRow;
    147   UINTN       FCol;
    148 
    149   //
    150   // variable initialization
    151   //
    152   Size    = 0;
    153   Offset  = 0;
    154   FRow    = 0;
    155   FCol    = 0;
    156 
    157   //
    158   // get offset
    159   //
    160   Status = InputBarSetPrompt (L"Go To Offset: ");
    161   if (EFI_ERROR (Status)) {
    162     return Status;
    163   }
    164 
    165   Status = InputBarSetStringSize (8);
    166   if (EFI_ERROR (Status)) {
    167     return Status;
    168   }
    169 
    170   while (1) {
    171     Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
    172 
    173     //
    174     // ESC pressed
    175     //
    176     if (Status == EFI_NOT_READY) {
    177 
    178       return EFI_SUCCESS;
    179     }
    180     //
    181     // THE input string length should > 0
    182     //
    183     if (StrLen (InputBarGetString()) > 0) {
    184       Status = ShellConvertStringToUint64 (InputBarGetString(), &Offset, TRUE, FALSE);
    185       if (EFI_ERROR (Status)) {
    186         StatusBarSetStatusString (L"Invalid Offset");
    187         return EFI_SUCCESS;
    188       }
    189 
    190       break;
    191     }
    192   }
    193 
    194   Size = HBufferImageGetTotalSize ();
    195   if (Offset >= Size) {
    196     StatusBarSetStatusString (L"Invalid Offset");
    197     return EFI_SUCCESS;
    198   }
    199 
    200   FRow  = (UINTN)DivU64x32(Offset , 0x10) + 1;
    201   FCol  = (UINTN)ModU64x32(Offset , 0x10) + 1;
    202 
    203   HBufferImageMovePosition (FRow, FCol, TRUE);
    204 
    205   HBufferImageNeedRefresh         = TRUE;
    206   HBufferImageOnlyLineNeedRefresh = FALSE;
    207   HBufferImageMouseNeedRefresh    = TRUE;
    208 
    209   return EFI_SUCCESS;
    210 }
    211 
    212 /**
    213   Save current opened buffer.
    214   If is file buffer, you can save to current file name or
    215   save to another file name.
    216 
    217   @retval EFI_SUCCESS             The operation was successful.
    218   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
    219   @retval EFI_LOAD_ERROR          A load error occured.
    220 **/
    221 EFI_STATUS
    222 HMainCommandSaveBuffer (
    223   VOID
    224   )
    225 {
    226   EFI_STATUS          Status;
    227   BOOLEAN             Done;
    228   CHAR16              *FileName;
    229   BOOLEAN             OldFile;
    230   CHAR16              *Str;
    231   EFI_FILE_INFO       *Info;
    232   SHELL_FILE_HANDLE   ShellFileHandle;
    233 
    234   if (HMainEditor.BufferImage->BufferType != FileTypeFileBuffer) {
    235     if (!HMainEditor.BufferImage->Modified) {
    236       return EFI_SUCCESS;
    237     }
    238 
    239     Status = InputBarSetPrompt (L"Dangerous to save disk/mem buffer. Save (Yes/No/Cancel) ? ");
    240     if (EFI_ERROR (Status)) {
    241       return Status;
    242     }
    243     //
    244     // the answer is just one character
    245     //
    246     Status = InputBarSetStringSize (1);
    247     if (EFI_ERROR (Status)) {
    248       return Status;
    249     }
    250     //
    251     // loop for user's answer
    252     // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C'
    253     //
    254     while (1) {
    255       Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
    256 
    257       //
    258       // ESC pressed
    259       //
    260       if (Status == EFI_NOT_READY) {
    261         return EFI_SUCCESS;
    262       }
    263 
    264       switch (InputBarGetString()[0]) {
    265       case L'y':
    266       case L'Y':
    267         //
    268         // want to save this buffer first
    269         //
    270         Status = HBufferImageSave (
    271                   NULL,
    272                   HMainEditor.BufferImage->DiskImage->Name,
    273                   HMainEditor.BufferImage->DiskImage->Offset,
    274                   HMainEditor.BufferImage->DiskImage->Size,
    275                   HMainEditor.BufferImage->MemImage->Offset,
    276                   HMainEditor.BufferImage->MemImage->Size,
    277                   HMainEditor.BufferImage->BufferType
    278                   );
    279 
    280         if (EFI_ERROR (Status)) {
    281           StatusBarSetStatusString (L"BufferSave: Problems Writing");
    282           return Status;
    283         }
    284 
    285         return EFI_SUCCESS;
    286 
    287       case L'n':
    288       case L'N':
    289         //
    290         // the file won't be saved
    291         //
    292         return EFI_SUCCESS;
    293 
    294       case L'c':
    295       case L'C':
    296         return EFI_SUCCESS;
    297       }
    298       //
    299       // end of switch
    300       //
    301     }
    302     //
    303     // ENDOF WHILE
    304     //
    305   }
    306   //
    307   // ENDOF != FILEBUFFER
    308   //
    309   // This command will save currently opened file to disk.
    310   // You can choose save to another file name or just save to
    311   // current file name.
    312   // Below is the scenario of Save File command: (
    313   //    Suppose the old file name is A )
    314   // 1. An Input Bar will be prompted:    "File To Save: [ old file name]"
    315   //    IF user press ESC, Save File command ends .
    316   //    IF user press Enter, input file name will be A.
    317   //    IF user inputs a new file name B,  input file name will be B.
    318   //
    319   // 2. IF input file name is A, go to do Step 3.
    320   //    IF input file name is B, go to do Step 4.
    321   //
    322   // 3. IF A is read only, Status Bar will show "Access Denied"
    323   //       and Save File commands ends.
    324   //    IF A is not read only, save file buffer to disk
    325   //       and remove Modified flag in Title Bar , then Save File command ends.
    326   //
    327   // 4. IF B does not exist, create this file and save file buffer to it.
    328   //       Go to do Step 7.
    329   //    IF B exits, do Step 5.
    330   //
    331   // 5. An Input Bar will be prompted:
    332   //       "File Exists. Overwrite ( Yes/No/Cancel ) ?"
    333   //      IF user press 'y' or 'Y', do Step 6.
    334   //      IF user press 'n' or 'N', Save File commands ends.
    335   //      IF user press 'c' or 'C' or ESC, Save File commands ends.
    336   //
    337   // 6. IF B is a read-only file, Status Bar will show "Access Denied"
    338   //       and Save File commands ends.
    339   //    IF B can be read and write, save file buffer to B.
    340   //
    341   // 7. Update File Name field in Title Bar to B
    342   //       and remove the Modified flag in Title Bar.
    343   //
    344   Str = CatSPrint(NULL,
    345           L"File to Save: [%s]",
    346           HMainEditor.BufferImage->FileImage->FileName
    347           );
    348   if (Str == NULL) {
    349     return EFI_OUT_OF_RESOURCES;
    350   }
    351 
    352   if (StrLen (Str) >= 50) {
    353     //
    354     // replace the long file name with "..."
    355     //
    356     Str[46] = L'.';
    357     Str[47] = L'.';
    358     Str[48] = L'.';
    359     Str[49] = L']';
    360     Str[50] = L'\0';
    361   }
    362 
    363   Status = InputBarSetPrompt (Str);
    364   if (EFI_ERROR (Status)) {
    365     return Status;
    366   }
    367 
    368   Status = InputBarSetStringSize (100);
    369   if (EFI_ERROR (Status)) {
    370     return Status;
    371   }
    372   //
    373   // get new file name
    374   //
    375   Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
    376 
    377   //
    378   // if user pressed ESC
    379   //
    380   if (Status == EFI_NOT_READY) {
    381     SHELL_FREE_NON_NULL (Str);
    382     return EFI_SUCCESS;
    383   }
    384 
    385   SHELL_FREE_NON_NULL (Str);
    386 
    387   //
    388   // if just enter pressed, so think save to current file name
    389   //
    390   if (StrLen (InputBarGetString()) == 0) {
    391     FileName = CatSPrint(NULL,
    392                 L"%s",
    393                 HMainEditor.BufferImage->FileImage->FileName
    394                 );
    395   } else {
    396     FileName = CatSPrint(NULL, L"%s", InputBarGetString());
    397   }
    398 
    399   if (FileName == NULL) {
    400     return EFI_OUT_OF_RESOURCES;
    401   }
    402 
    403   if (!IsValidFileName (FileName)) {
    404     StatusBarSetStatusString (L"Invalid File Name");
    405     SHELL_FREE_NON_NULL (FileName);
    406     return EFI_SUCCESS;
    407   }
    408 
    409   OldFile = FALSE;
    410 
    411   //
    412   // save to the old file
    413   //
    414   if (StringNoCaseCompare (
    415         &FileName,
    416         &HMainEditor.BufferImage->FileImage->FileName
    417         ) == 0) {
    418     OldFile = TRUE;
    419   }
    420 
    421   if (OldFile) {
    422     //
    423     // if the file is read only, so can not write back to it.
    424     //
    425     if (HMainEditor.BufferImage->FileImage->ReadOnly) {
    426       StatusBarSetStatusString (L"Access Denied");
    427       SHELL_FREE_NON_NULL (FileName);
    428       return EFI_SUCCESS;
    429     }
    430   } else {
    431     Status = ShellOpenFileByName (FileName, &ShellFileHandle, EFI_FILE_MODE_READ, 0);
    432 
    433     if (!EFI_ERROR (Status)) {
    434 
    435       Info = ShellGetFileInfo(ShellFileHandle);
    436 
    437       ShellCloseFile(&ShellFileHandle);
    438       //
    439       // check if read only
    440       //
    441       if (Info->Attribute & EFI_FILE_READ_ONLY) {
    442         StatusBarSetStatusString (L"Access Denied");
    443         SHELL_FREE_NON_NULL (FileName);
    444         return EFI_SUCCESS;
    445       }
    446 
    447       SHELL_FREE_NON_NULL(Info);
    448       //
    449       // ask user whether to overwrite this file
    450       //
    451       Status = InputBarSetPrompt (L"File exists. Overwrite (Yes/No/Cancel) ? ");
    452       if (EFI_ERROR (Status)) {
    453         SHELL_FREE_NON_NULL (FileName);
    454         return Status;
    455       }
    456 
    457       Status = InputBarSetStringSize (1);
    458       if (EFI_ERROR (Status)) {
    459         SHELL_FREE_NON_NULL (FileName);
    460         return Status;
    461       }
    462 
    463       Done = FALSE;
    464       while (!Done) {
    465         Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
    466 
    467         if (Status == EFI_NOT_READY) {
    468           SHELL_FREE_NON_NULL (FileName);
    469           return EFI_SUCCESS;
    470         }
    471 
    472         switch (InputBarGetString()[0]) {
    473         case L'y':
    474         case L'Y':
    475           Done = TRUE;
    476           break;
    477         case L'n':
    478         case L'N':
    479           SHELL_FREE_NON_NULL (FileName);
    480           return EFI_SUCCESS;
    481         case L'c':
    482         case L'C':
    483           SHELL_FREE_NON_NULL (FileName);
    484           return EFI_SUCCESS;
    485         } // switch
    486       } // while
    487     } // if opened existing file
    488   } // if OldFile
    489 
    490   //
    491   // save file back to disk
    492   //
    493   Status = HBufferImageSave (
    494             FileName,
    495             HMainEditor.BufferImage->DiskImage->Name,
    496             HMainEditor.BufferImage->DiskImage->Offset,
    497             HMainEditor.BufferImage->DiskImage->Size,
    498             HMainEditor.BufferImage->MemImage->Offset,
    499             HMainEditor.BufferImage->MemImage->Size,
    500             FileTypeFileBuffer
    501             );
    502   SHELL_FREE_NON_NULL (FileName);
    503 
    504   if (EFI_ERROR (Status)) {
    505     return EFI_LOAD_ERROR;
    506   }
    507 
    508   return EFI_SUCCESS;
    509 }
    510 
    511 /**
    512   Load a disk buffer editor.
    513 
    514   @retval EFI_SUCCESS             The operation was successful.
    515   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
    516   @retval EFI_LOAD_ERROR          A load error occured.
    517 **/
    518 EFI_STATUS
    519 HMainCommandSelectStart (
    520   VOID
    521   )
    522 {
    523   UINTN Start;
    524 
    525   Start = (HMainEditor.BufferImage->BufferPosition.Row - 1) * 0x10 + HMainEditor.BufferImage->BufferPosition.Column;
    526 
    527   //
    528   // last line
    529   //
    530   if (HMainEditor.BufferImage->CurrentLine->Link.ForwardLink == HMainEditor.BufferImage->ListHead) {
    531     if (HMainEditor.BufferImage->BufferPosition.Column > HMainEditor.BufferImage->CurrentLine->Size) {
    532       StatusBarSetStatusString (L"Invalid Block Start");
    533       return EFI_LOAD_ERROR;
    534     }
    535   }
    536 
    537   if (HMainEditor.SelectEnd != 0 && Start > HMainEditor.SelectEnd) {
    538     StatusBarSetStatusString (L"Invalid Block Start");
    539     return EFI_LOAD_ERROR;
    540   }
    541 
    542   HMainEditor.SelectStart = Start;
    543 
    544   HBufferImageNeedRefresh = TRUE;
    545 
    546   return EFI_SUCCESS;
    547 }
    548 
    549 /**
    550   Load a disk buffer editor.
    551 
    552   @retval EFI_SUCCESS             The operation was successful.
    553   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
    554   @retval EFI_LOAD_ERROR          A load error occured.
    555 **/
    556 EFI_STATUS
    557 HMainCommandSelectEnd (
    558   VOID
    559   )
    560 {
    561   UINTN End;
    562 
    563   End = (HMainEditor.BufferImage->BufferPosition.Row - 1) * 0x10 + HMainEditor.BufferImage->BufferPosition.Column;
    564 
    565   //
    566   // last line
    567   //
    568   if (HMainEditor.BufferImage->CurrentLine->Link.ForwardLink == HMainEditor.BufferImage->ListHead) {
    569     if (HMainEditor.BufferImage->BufferPosition.Column > HMainEditor.BufferImage->CurrentLine->Size) {
    570       StatusBarSetStatusString (L"Invalid Block End");
    571       return EFI_LOAD_ERROR;
    572     }
    573   }
    574 
    575   if (HMainEditor.SelectStart != 0 && End < HMainEditor.SelectStart) {
    576     StatusBarSetStatusString (L"Invalid Block End");
    577     return EFI_SUCCESS;
    578   }
    579 
    580   HMainEditor.SelectEnd   = End;
    581 
    582   HBufferImageNeedRefresh = TRUE;
    583 
    584   return EFI_SUCCESS;
    585 }
    586 
    587 /**
    588   Cut current line to clipboard.
    589 
    590   @retval EFI_SUCCESS             The operation was successful.
    591   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
    592   @retval EFI_LOAD_ERROR          A load error occured.
    593 **/
    594 EFI_STATUS
    595 HMainCommandCut (
    596   VOID
    597   )
    598 {
    599   UINTN             Index;
    600   LIST_ENTRY    *Link;
    601   UINT8             *Buffer;
    602   UINTN             Count;
    603 
    604   //
    605   // not select, so not allowed to cut
    606   //
    607   if (HMainEditor.SelectStart == 0) {
    608     StatusBarSetStatusString (L"No Block is Selected");
    609     return EFI_SUCCESS;
    610   }
    611   //
    612   // not select, so not allowed to cut
    613   //
    614   if (HMainEditor.SelectEnd == 0) {
    615     StatusBarSetStatusString (L"No Block is Selected");
    616     return EFI_SUCCESS;
    617   }
    618 
    619   Link = HMainEditor.BufferImage->ListHead->ForwardLink;
    620   for (Index = 0; Index < (HMainEditor.SelectEnd - 1) / 0x10; Index++) {
    621     Link = Link->ForwardLink;
    622   }
    623 
    624   Count   = HMainEditor.SelectEnd - HMainEditor.SelectStart + 1;
    625   Buffer  = AllocateZeroPool (Count);
    626   if (Buffer == NULL) {
    627     return EFI_OUT_OF_RESOURCES;
    628   }
    629   //
    630   // cut the selected area
    631   //
    632   HBufferImageDeleteCharacterFromBuffer (
    633     HMainEditor.SelectStart - 1,
    634     Count,
    635     Buffer
    636     );
    637 
    638   //
    639   // put to clipboard
    640   //
    641   HClipBoardSet (Buffer, Count);
    642 
    643   HBufferImageNeedRefresh         = TRUE;
    644   HBufferImageOnlyLineNeedRefresh = FALSE;
    645 
    646   if (!HMainEditor.BufferImage->Modified) {
    647     HMainEditor.BufferImage->Modified = TRUE;
    648   }
    649 
    650   //
    651   // now no select area
    652   //
    653   HMainEditor.SelectStart = 0;
    654   HMainEditor.SelectEnd   = 0;
    655 
    656   return EFI_SUCCESS;
    657 }
    658 
    659 /**
    660   Paste line to file buffer.
    661 
    662   @retval EFI_SUCCESS             The operation was successful.
    663   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
    664   @retval EFI_LOAD_ERROR          A load error occured.
    665 **/
    666 EFI_STATUS
    667 HMainCommandPaste (
    668   VOID
    669   )
    670 {
    671 
    672   BOOLEAN           OnlyLineRefresh;
    673   HEFI_EDITOR_LINE  *Line;
    674   UINT8             *Buffer;
    675   UINTN             Count;
    676   UINTN             FPos;
    677 
    678   Count = HClipBoardGet (&Buffer);
    679   if (Count == 0 || Buffer == NULL) {
    680     StatusBarSetStatusString (L"Nothing to Paste");
    681     return EFI_SUCCESS;
    682   }
    683 
    684   Line            = HMainEditor.BufferImage->CurrentLine;
    685 
    686   OnlyLineRefresh = FALSE;
    687   if (Line->Link.ForwardLink == HMainEditor.BufferImage->ListHead && Line->Size + Count < 0x10) {
    688     //
    689     // is at last line, and after paste will not exceed
    690     // so only this line need to be refreshed
    691     //
    692     // if after add, the line is 0x10, then will append a new line
    693     // so the whole page will need be refreshed
    694     //
    695     OnlyLineRefresh = TRUE;
    696 
    697   }
    698 
    699   FPos = 0x10 * (HMainEditor.BufferImage->BufferPosition.Row - 1) + HMainEditor.BufferImage->BufferPosition.Column - 1;
    700 
    701   HBufferImageAddCharacterToBuffer (FPos, Count, Buffer);
    702 
    703   if (OnlyLineRefresh) {
    704     HBufferImageNeedRefresh         = FALSE;
    705     HBufferImageOnlyLineNeedRefresh = TRUE;
    706   } else {
    707     HBufferImageNeedRefresh         = TRUE;
    708     HBufferImageOnlyLineNeedRefresh = FALSE;
    709   }
    710 
    711   if (!HMainEditor.BufferImage->Modified) {
    712     HMainEditor.BufferImage->Modified = TRUE;
    713   }
    714 
    715   return EFI_SUCCESS;
    716 
    717 }
    718 
    719 /**
    720   Exit editor.
    721 
    722   @retval EFI_SUCCESS             The operation was successful.
    723   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
    724   @retval EFI_LOAD_ERROR          A load error occured.
    725 **/
    726 EFI_STATUS
    727 HMainCommandExit (
    728   VOID
    729   )
    730 {
    731   EFI_STATUS  Status;
    732 
    733   //
    734   // Below is the scenario of Exit command:
    735   // 1. IF currently opened file is not modified, exit the editor and
    736   //       Exit command ends.
    737   //    IF currently opened file is modified, do Step 2
    738   //
    739   // 2. An Input Bar will be prompted:
    740   //       "File modified. Save ( Yes/No/Cancel )?"
    741   //      IF user press 'y' or 'Y', currently opened file will be saved and
    742   //         Editor exits
    743   //      IF user press 'n' or 'N', currently opened file will not be saved
    744   //         and Editor exits.
    745   //      IF user press 'c' or 'C' or ESC, Exit command ends.
    746   //
    747   //
    748   // if file has been modified, so will prompt user
    749   //       whether to save the changes
    750   //
    751   if (HMainEditor.BufferImage->Modified) {
    752 
    753     Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? ");
    754     if (EFI_ERROR (Status)) {
    755       return Status;
    756     }
    757 
    758     Status = InputBarSetStringSize (1);
    759     if (EFI_ERROR (Status)) {
    760       return Status;
    761     }
    762 
    763     while (1) {
    764       Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
    765 
    766       //
    767       // ESC pressed
    768       //
    769       if (Status == EFI_NOT_READY) {
    770         return EFI_SUCCESS;
    771       }
    772 
    773       switch (InputBarGetString()[0]) {
    774       case L'y':
    775       case L'Y':
    776         //
    777         // write file back to disk
    778         //
    779         Status = HBufferImageSave (
    780                   HMainEditor.BufferImage->FileImage->FileName,
    781                   HMainEditor.BufferImage->DiskImage->Name,
    782                   HMainEditor.BufferImage->DiskImage->Offset,
    783                   HMainEditor.BufferImage->DiskImage->Size,
    784                   HMainEditor.BufferImage->MemImage->Offset,
    785                   HMainEditor.BufferImage->MemImage->Size,
    786                   HMainEditor.BufferImage->BufferType
    787                   );
    788         if (!EFI_ERROR (Status)) {
    789           HEditorExit = TRUE;
    790         }
    791 
    792         return Status;
    793 
    794       case L'n':
    795       case L'N':
    796         HEditorExit = TRUE;
    797         return EFI_SUCCESS;
    798 
    799       case L'c':
    800       case L'C':
    801         return EFI_SUCCESS;
    802 
    803       }
    804     }
    805   }
    806 
    807   HEditorExit = TRUE;
    808   return EFI_SUCCESS;
    809 
    810 }
    811 
    812 /**
    813   Load a file from disk to editor.
    814 
    815   @retval EFI_SUCCESS             The operation was successful.
    816   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
    817   @retval EFI_LOAD_ERROR          A load error occured.
    818 **/
    819 EFI_STATUS
    820 HMainCommandOpenFile (
    821   VOID
    822   )
    823 {
    824   BOOLEAN                         Done;
    825   EFI_STATUS                      Status;
    826   EDIT_FILE_TYPE                  BufferType;
    827 
    828   BufferType = HMainEditor.BufferImage->BufferType;
    829 
    830   //
    831   //  This command will open a file from current working directory.
    832   //  Read-only file can also be opened. But it can not be modified.
    833   // Below is the scenario of Open File command:
    834   // 1. IF currently opened file has not been modified, directly go to step .
    835   //  IF currently opened file has been modified, an Input Bar will be
    836   //     prompted as :
    837   //      "File Modified. Save ( Yes/No/Cancel) ?"
    838   //          IF user press 'y' or 'Y', currently opened file will be saved.
    839   //          IF user press 'n' or 'N', currently opened file will
    840   //             not be saved.
    841   //          IF user press 'c' or 'C' or ESC, Open File command ends and
    842   //             currently opened file is still opened.
    843   //
    844   // 2. An Input Bar will be prompted as :  "File Name to Open: "
    845   //      IF user press ESC, Open File command ends and
    846   //         currently opened file is still opened.
    847   //      Any other inputs with a Return will cause
    848   //          currently opened file close.
    849   //
    850   // 3. IF user input file name is an existing file ,
    851   //       this file will be read and opened.
    852   //    IF user input file name is a new file, this file will be created
    853   //       and opened. This file's type ( UNICODE or ASCII ) is the same with
    854   //       the old file.
    855   //
    856   //
    857   // if current file is modified, so you need to choose whether to
    858   //    save it first.
    859   //
    860   if (HMainEditor.BufferImage->Modified) {
    861 
    862     Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? ");
    863     if (EFI_ERROR (Status)) {
    864       return Status;
    865     }
    866     //
    867     // the answer is just one character
    868     //
    869     Status = InputBarSetStringSize (1);
    870     if (EFI_ERROR (Status)) {
    871       return Status;
    872     }
    873     //
    874     // loop for user's answer
    875     // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C'
    876     //
    877     Done = FALSE;
    878     while (!Done) {
    879       Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
    880 
    881       //
    882       // ESC pressed
    883       //
    884       if (Status == EFI_NOT_READY) {
    885         return EFI_SUCCESS;
    886       }
    887 
    888       switch (InputBarGetString()[0]) {
    889       case L'y':
    890       case L'Y':
    891         //
    892         // want to save this buffer first
    893         //
    894         Status = HBufferImageSave (
    895                   HMainEditor.BufferImage->FileImage->FileName,
    896                   HMainEditor.BufferImage->DiskImage->Name,
    897                   HMainEditor.BufferImage->DiskImage->Offset,
    898                   HMainEditor.BufferImage->DiskImage->Size,
    899                   HMainEditor.BufferImage->MemImage->Offset,
    900                   HMainEditor.BufferImage->MemImage->Size,
    901                   HMainEditor.BufferImage->BufferType
    902                   );
    903         if (EFI_ERROR (Status)) {
    904           return Status;
    905         }
    906 
    907         MainTitleBarRefresh (
    908           HMainEditor.BufferImage->BufferType == FileTypeFileBuffer?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Name:NULL,
    909           HMainEditor.BufferImage->BufferType,
    910           HMainEditor.BufferImage->FileImage->ReadOnly,
    911           FALSE,
    912           HMainEditor.ScreenSize.Column,
    913           HMainEditor.ScreenSize.Row,
    914           HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Offset:HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Offset:0,
    915           HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Size  :HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Size  :0
    916           );
    917         Done = TRUE;
    918         break;
    919 
    920       case L'n':
    921       case L'N':
    922         //
    923         // the file won't be saved
    924         //
    925         Done = TRUE;
    926         break;
    927 
    928       case L'c':
    929       case L'C':
    930         return EFI_SUCCESS;
    931       }
    932     }
    933   }
    934   //
    935   // TO get the open file name
    936   //
    937   Status = InputBarSetPrompt (L"File Name to Open: ");
    938   if (EFI_ERROR (Status)) {
    939     HBufferImageRead (
    940       HMainEditor.BufferImage->FileImage->FileName,
    941       HMainEditor.BufferImage->DiskImage->Name,
    942       HMainEditor.BufferImage->DiskImage->Offset,
    943       HMainEditor.BufferImage->DiskImage->Size,
    944       HMainEditor.BufferImage->MemImage->Offset,
    945       HMainEditor.BufferImage->MemImage->Size,
    946       BufferType,
    947       TRUE
    948       );
    949     return Status;
    950   }
    951 
    952   Status = InputBarSetStringSize (100);
    953   if (EFI_ERROR (Status)) {
    954     Status = HBufferImageRead (
    955               HMainEditor.BufferImage->FileImage->FileName,
    956               HMainEditor.BufferImage->DiskImage->Name,
    957               HMainEditor.BufferImage->DiskImage->Offset,
    958               HMainEditor.BufferImage->DiskImage->Size,
    959               HMainEditor.BufferImage->MemImage->Offset,
    960               HMainEditor.BufferImage->MemImage->Size,
    961               BufferType,
    962               TRUE
    963               );
    964     return Status;
    965   }
    966 
    967   while (1) {
    968     Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
    969 
    970     //
    971     // ESC pressed
    972     //
    973     if (Status == EFI_NOT_READY) {
    974       Status = HBufferImageRead (
    975                 HMainEditor.BufferImage->FileImage->FileName,
    976                 HMainEditor.BufferImage->DiskImage->Name,
    977                 HMainEditor.BufferImage->DiskImage->Offset,
    978                 HMainEditor.BufferImage->DiskImage->Size,
    979                 HMainEditor.BufferImage->MemImage->Offset,
    980                 HMainEditor.BufferImage->MemImage->Size,
    981                 BufferType,
    982                 TRUE
    983                 );
    984 
    985       return Status;
    986     }
    987     //
    988     // THE input string length should > 0
    989     //
    990     if (StrLen (InputBarGetString()) > 0) {
    991       //
    992       // CHECK if filename's valid
    993       //
    994       if (!IsValidFileName (InputBarGetString())) {
    995         HBufferImageRead (
    996           HMainEditor.BufferImage->FileImage->FileName,
    997           HMainEditor.BufferImage->DiskImage->Name,
    998           HMainEditor.BufferImage->DiskImage->Offset,
    999           HMainEditor.BufferImage->DiskImage->Size,
   1000           HMainEditor.BufferImage->MemImage->Offset,
   1001           HMainEditor.BufferImage->MemImage->Size,
   1002           BufferType,
   1003           TRUE
   1004           );
   1005 
   1006         StatusBarSetStatusString (L"Invalid File Name");
   1007         return EFI_SUCCESS;
   1008       }
   1009 
   1010       break;
   1011     }
   1012   }
   1013   //
   1014   // read from disk
   1015   //
   1016   Status = HBufferImageRead (
   1017             InputBarGetString(),
   1018             HMainEditor.BufferImage->DiskImage->Name,
   1019             HMainEditor.BufferImage->DiskImage->Offset,
   1020             HMainEditor.BufferImage->DiskImage->Size,
   1021             HMainEditor.BufferImage->MemImage->Offset,
   1022             HMainEditor.BufferImage->MemImage->Size,
   1023             FileTypeFileBuffer,
   1024             FALSE
   1025             );
   1026 
   1027   if (EFI_ERROR (Status)) {
   1028     HBufferImageRead (
   1029       HMainEditor.BufferImage->FileImage->FileName,
   1030       HMainEditor.BufferImage->DiskImage->Name,
   1031       HMainEditor.BufferImage->DiskImage->Offset,
   1032       HMainEditor.BufferImage->DiskImage->Size,
   1033       HMainEditor.BufferImage->MemImage->Offset,
   1034       HMainEditor.BufferImage->MemImage->Size,
   1035       BufferType,
   1036       TRUE
   1037       );
   1038 
   1039     return EFI_LOAD_ERROR;
   1040   }
   1041 
   1042   return EFI_SUCCESS;
   1043 }
   1044 
   1045 /**
   1046   Load a disk buffer editor.
   1047 
   1048   @retval EFI_SUCCESS             The operation was successful.
   1049   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
   1050   @retval EFI_LOAD_ERROR          A load error occured.
   1051   @retval EFI_NOT_FOUND           The disk was not found.
   1052 **/
   1053 EFI_STATUS
   1054 HMainCommandOpenDisk (
   1055   VOID
   1056   )
   1057 {
   1058   UINT64                          Size;
   1059   UINT64                          Offset;
   1060   CHAR16                          *DeviceName;
   1061   EFI_STATUS                      Status;
   1062   BOOLEAN                         Done;
   1063 
   1064   EDIT_FILE_TYPE                  BufferType;
   1065 
   1066   //
   1067   // variable initialization
   1068   //
   1069   Size        = 0;
   1070   Offset      = 0;
   1071   BufferType  = HMainEditor.BufferImage->BufferType;
   1072 
   1073   //
   1074   // if current file is modified, so you need to choose
   1075   // whether to save it first.
   1076   //
   1077   if (HMainEditor.BufferImage->Modified) {
   1078 
   1079     Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? ");
   1080     if (EFI_ERROR (Status)) {
   1081       return Status;
   1082     }
   1083     //
   1084     // the answer is just one character
   1085     //
   1086     Status = InputBarSetStringSize (1);
   1087     if (EFI_ERROR (Status)) {
   1088       return Status;
   1089     }
   1090     //
   1091     // loop for user's answer
   1092     // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C'
   1093     //
   1094     Done = FALSE;
   1095     while (!Done) {
   1096       Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
   1097 
   1098       //
   1099       // ESC pressed
   1100       //
   1101       if (Status == EFI_NOT_READY) {
   1102         return EFI_SUCCESS;
   1103       }
   1104 
   1105       switch (InputBarGetString()[0]) {
   1106       case L'y':
   1107       case L'Y':
   1108         //
   1109         // want to save this buffer first
   1110         //
   1111         Status = HBufferImageSave (
   1112                   HMainEditor.BufferImage->FileImage->FileName,
   1113                   HMainEditor.BufferImage->DiskImage->Name,
   1114                   HMainEditor.BufferImage->DiskImage->Offset,
   1115                   HMainEditor.BufferImage->DiskImage->Size,
   1116                   HMainEditor.BufferImage->MemImage->Offset,
   1117                   HMainEditor.BufferImage->MemImage->Size,
   1118                   BufferType
   1119                   );
   1120         if (EFI_ERROR (Status)) {
   1121           return Status;
   1122         }
   1123 
   1124         MainTitleBarRefresh (
   1125           HMainEditor.BufferImage->BufferType == FileTypeFileBuffer?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Name:NULL,
   1126           HMainEditor.BufferImage->BufferType,
   1127           HMainEditor.BufferImage->FileImage->ReadOnly,
   1128           FALSE,
   1129           HMainEditor.ScreenSize.Column,
   1130           HMainEditor.ScreenSize.Row,
   1131           HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Offset:HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Offset:0,
   1132           HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Size  :HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Size  :0
   1133           );
   1134         Done = TRUE;
   1135         break;
   1136 
   1137       case L'n':
   1138       case L'N':
   1139         //
   1140         // the file won't be saved
   1141         //
   1142         Done = TRUE;
   1143         break;
   1144 
   1145       case L'c':
   1146       case L'C':
   1147         return EFI_SUCCESS;
   1148       }
   1149     }
   1150   }
   1151   //
   1152   // get disk block device name
   1153   //
   1154   Status = InputBarSetPrompt (L"Block Device to Open: ");
   1155   if (EFI_ERROR (Status)) {
   1156     return Status;
   1157   }
   1158 
   1159   Status = InputBarSetStringSize (100);
   1160   if (EFI_ERROR (Status)) {
   1161     return Status;
   1162   }
   1163 
   1164   while (1) {
   1165     Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
   1166 
   1167     //
   1168     // ESC pressed
   1169     //
   1170     if (Status == EFI_NOT_READY) {
   1171 
   1172       return EFI_SUCCESS;
   1173     }
   1174     //
   1175     // THE input string length should > 0
   1176     //
   1177     if (StrLen (InputBarGetString()) > 0) {
   1178       break;
   1179     }
   1180   }
   1181 
   1182   DeviceName = CatSPrint(NULL, L"%s", InputBarGetString());
   1183   if (DeviceName == NULL) {
   1184     return EFI_OUT_OF_RESOURCES;
   1185   }
   1186   //
   1187   // get starting offset
   1188   //
   1189   Status = InputBarSetPrompt (L"First Block No.: ");
   1190   if (EFI_ERROR (Status)) {
   1191     return Status;
   1192   }
   1193 
   1194   Status = InputBarSetStringSize (16);
   1195   if (EFI_ERROR (Status)) {
   1196     return Status;
   1197   }
   1198 
   1199   while (1) {
   1200     Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
   1201 
   1202     //
   1203     // ESC pressed
   1204     //
   1205     if (Status == EFI_NOT_READY) {
   1206 
   1207       return EFI_SUCCESS;
   1208     }
   1209     //
   1210     // THE input string length should > 0
   1211     //
   1212     if (StrLen (InputBarGetString()) > 0) {
   1213       Status = ShellConvertStringToUint64 (InputBarGetString(), &Offset, TRUE, FALSE);
   1214       if (EFI_ERROR (Status)) {
   1215         continue;
   1216       }
   1217 
   1218       break;
   1219     }
   1220   }
   1221   //
   1222   // get Number of Blocks:
   1223   //
   1224   Status = InputBarSetPrompt (L"Number of Blocks: ");
   1225   if (EFI_ERROR (Status)) {
   1226     return Status;
   1227   }
   1228 
   1229   Status = InputBarSetStringSize (8);
   1230   if (EFI_ERROR (Status)) {
   1231     return Status;
   1232   }
   1233 
   1234   while (1) {
   1235     Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
   1236 
   1237     //
   1238     // ESC pressed
   1239     //
   1240     if (Status == EFI_NOT_READY) {
   1241 
   1242       return EFI_SUCCESS;
   1243     }
   1244     //
   1245     // THE input string length should > 0
   1246     //
   1247     if (StrLen (InputBarGetString()) > 0) {
   1248       Status = ShellConvertStringToUint64 (InputBarGetString(), &Size, TRUE, FALSE);
   1249       if (EFI_ERROR (Status)) {
   1250         continue;
   1251       }
   1252 
   1253       if (Size == 0) {
   1254         continue;
   1255       }
   1256 
   1257       break;
   1258     }
   1259   }
   1260 
   1261   Status = HBufferImageRead (
   1262             NULL,
   1263             DeviceName,
   1264             (UINTN)Offset,
   1265             (UINTN)Size,
   1266             0,
   1267             0,
   1268             FileTypeDiskBuffer,
   1269             FALSE
   1270             );
   1271 
   1272   if (EFI_ERROR (Status)) {
   1273 
   1274     HBufferImageRead (
   1275       HMainEditor.BufferImage->FileImage->FileName,
   1276       HMainEditor.BufferImage->DiskImage->Name,
   1277       HMainEditor.BufferImage->DiskImage->Offset,
   1278       HMainEditor.BufferImage->DiskImage->Size,
   1279       HMainEditor.BufferImage->MemImage->Offset,
   1280       HMainEditor.BufferImage->MemImage->Size,
   1281       BufferType,
   1282       TRUE
   1283       );
   1284     return EFI_NOT_FOUND;
   1285   }
   1286 
   1287   return EFI_SUCCESS;
   1288 }
   1289 
   1290 /**
   1291   Load memory content to editor
   1292 
   1293   @retval EFI_SUCCESS             The operation was successful.
   1294   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
   1295   @retval EFI_LOAD_ERROR          A load error occured.
   1296   @retval EFI_NOT_FOUND           The disk was not found.
   1297 **/
   1298 EFI_STATUS
   1299 HMainCommandOpenMemory (
   1300   VOID
   1301   )
   1302 {
   1303   UINT64                          Size;
   1304   UINT64                          Offset;
   1305   EFI_STATUS                      Status;
   1306   BOOLEAN                         Done;
   1307   EDIT_FILE_TYPE                  BufferType;
   1308 
   1309   //
   1310   // variable initialization
   1311   //
   1312   Size        = 0;
   1313   Offset      = 0;
   1314   BufferType  = HMainEditor.BufferImage->BufferType;
   1315 
   1316   //
   1317   // if current buffer is modified, so you need to choose
   1318   // whether to save it first.
   1319   //
   1320   if (HMainEditor.BufferImage->Modified) {
   1321 
   1322     Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? ");
   1323     if (EFI_ERROR (Status)) {
   1324       return Status;
   1325     }
   1326     //
   1327     // the answer is just one character
   1328     //
   1329     Status = InputBarSetStringSize (1);
   1330     if (EFI_ERROR (Status)) {
   1331       return Status;
   1332     }
   1333     //
   1334     // loop for user's answer
   1335     // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C'
   1336     //
   1337     Done = FALSE;
   1338     while (!Done) {
   1339       Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
   1340 
   1341       //
   1342       // ESC pressed
   1343       //
   1344       if (Status == EFI_NOT_READY) {
   1345         return EFI_SUCCESS;
   1346       }
   1347 
   1348       switch (InputBarGetString()[0]) {
   1349       case L'y':
   1350       case L'Y':
   1351         //
   1352         // want to save this buffer first
   1353         //
   1354         Status = HBufferImageSave (
   1355                   HMainEditor.BufferImage->FileImage->FileName,
   1356                   HMainEditor.BufferImage->DiskImage->Name,
   1357                   HMainEditor.BufferImage->DiskImage->Offset,
   1358                   HMainEditor.BufferImage->DiskImage->Size,
   1359                   HMainEditor.BufferImage->MemImage->Offset,
   1360                   HMainEditor.BufferImage->MemImage->Size,
   1361                   BufferType
   1362                   );
   1363         if (EFI_ERROR (Status)) {
   1364           return Status;
   1365         }
   1366 
   1367         MainTitleBarRefresh (
   1368           HMainEditor.BufferImage->BufferType == FileTypeFileBuffer?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Name:NULL,
   1369           HMainEditor.BufferImage->BufferType,
   1370           HMainEditor.BufferImage->FileImage->ReadOnly,
   1371           FALSE,
   1372           HMainEditor.ScreenSize.Column,
   1373           HMainEditor.ScreenSize.Row,
   1374           HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Offset:HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Offset:0,
   1375           HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Size  :HMainEditor.BufferImage->BufferType == FileTypeMemBuffer?HMainEditor.BufferImage->MemImage->Size  :0
   1376           );
   1377         Done = TRUE;
   1378         break;
   1379 
   1380       case L'n':
   1381       case L'N':
   1382         //
   1383         // the file won't be saved
   1384         //
   1385         Done = TRUE;
   1386         break;
   1387 
   1388       case L'c':
   1389       case L'C':
   1390         return EFI_SUCCESS;
   1391       }
   1392     }
   1393   }
   1394   //
   1395   // get starting offset
   1396   //
   1397   Status = InputBarSetPrompt (L"Starting Offset: ");
   1398   if (EFI_ERROR (Status)) {
   1399     return Status;
   1400   }
   1401 
   1402   Status = InputBarSetStringSize (8);
   1403   if (EFI_ERROR (Status)) {
   1404     return Status;
   1405   }
   1406 
   1407   while (1) {
   1408     Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
   1409 
   1410     //
   1411     // ESC pressed
   1412     //
   1413     if (Status == EFI_NOT_READY) {
   1414 
   1415       return EFI_SUCCESS;
   1416     }
   1417     //
   1418     // THE input string length should > 0
   1419     //
   1420     if (StrLen (InputBarGetString()) > 0) {
   1421       Status = ShellConvertStringToUint64 (InputBarGetString(), &Offset, TRUE, FALSE);
   1422       if (EFI_ERROR (Status)) {
   1423         continue;
   1424       }
   1425 
   1426       break;
   1427     }
   1428   }
   1429   //
   1430   // get Number of Blocks:
   1431   //
   1432   Status = InputBarSetPrompt (L"Buffer Size: ");
   1433   if (EFI_ERROR (Status)) {
   1434     return Status;
   1435   }
   1436 
   1437   Status = InputBarSetStringSize (8);
   1438   if (EFI_ERROR (Status)) {
   1439     return Status;
   1440   }
   1441 
   1442   while (1) {
   1443     Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column);
   1444 
   1445     //
   1446     // ESC pressed
   1447     //
   1448     if (Status == EFI_NOT_READY) {
   1449 
   1450       return EFI_SUCCESS;
   1451     }
   1452     //
   1453     // THE input string length should > 0
   1454     //
   1455     if (StrLen (InputBarGetString()) > 0) {
   1456       Status = ShellConvertStringToUint64 (InputBarGetString(), &Size, TRUE, FALSE);
   1457       if (EFI_ERROR (Status)) {
   1458         continue;
   1459       }
   1460 
   1461       if (Size == 0) {
   1462         continue;
   1463       }
   1464 
   1465       break;
   1466     }
   1467   }
   1468 
   1469   if ((Offset + Size - 1)> 0xffffffff) {
   1470     StatusBarSetStatusString (L"Invalid parameter");
   1471     return EFI_LOAD_ERROR;
   1472   }
   1473 
   1474   Status = HBufferImageRead (
   1475             NULL,
   1476             NULL,
   1477             0,
   1478             0,
   1479             (UINTN)Offset,
   1480             (UINTN)Size,
   1481             FileTypeMemBuffer,
   1482             FALSE
   1483             );
   1484 
   1485   if (EFI_ERROR (Status)) {
   1486     StatusBarSetStatusString (L"Read Device Error!");
   1487     HBufferImageRead (
   1488       HMainEditor.BufferImage->FileImage->FileName,
   1489       HMainEditor.BufferImage->DiskImage->Name,
   1490       HMainEditor.BufferImage->DiskImage->Offset,
   1491       HMainEditor.BufferImage->DiskImage->Size,
   1492       HMainEditor.BufferImage->MemImage->Offset,
   1493       HMainEditor.BufferImage->MemImage->Size,
   1494       BufferType,
   1495       TRUE
   1496       );
   1497     return EFI_NOT_FOUND;
   1498   }
   1499   return EFI_SUCCESS;
   1500 
   1501 }
   1502 
   1503 MENU_ITEM_FUNCTION HexMainControlBasedMenuFunctions[] = {
   1504   NULL,
   1505   NULL,                      /* Ctrl - A */
   1506   NULL,                      /* Ctrl - B */
   1507   NULL,                      /* Ctrl - C */
   1508   HMainCommandSelectEnd,     /* Ctrl - D */
   1509   HMainCommandDisplayHelp,   /* Ctrl - E */
   1510   NULL,                      /* Ctrl - F */
   1511   HMainCommandGoToOffset,    /* Ctrl - G */
   1512   NULL,                      /* Ctrl - H */
   1513   HMainCommandOpenDisk,      /* Ctrl - I */
   1514   NULL,                      /* Ctrl - J */
   1515   NULL,                      /* Ctrl - K */
   1516   NULL,                      /* Ctrl - L */
   1517   HMainCommandOpenMemory,    /* Ctrl - M */
   1518   NULL,                      /* Ctrl - N */
   1519   HMainCommandOpenFile,      /* Ctrl - O */
   1520   NULL,                      /* Ctrl - P */
   1521   HMainCommandExit,          /* Ctrl - Q */
   1522   NULL,                      /* Ctrl - R */
   1523   HMainCommandSaveBuffer,    /* Ctrl - S */
   1524   HMainCommandSelectStart,   /* Ctrl - T */
   1525   NULL,                      /* Ctrl - U */
   1526   HMainCommandPaste,         /* Ctrl - V */
   1527   NULL,                      /* Ctrl - W */
   1528   HMainCommandCut,           /* Ctrl - X */
   1529   NULL,                      /* Ctrl - Y */
   1530   NULL,                      /* Ctrl - Z */
   1531 };
   1532 
   1533 CONST EDITOR_MENU_ITEM HexEditorMenuItems[] = {
   1534   {
   1535     STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_GO_TO_OFFSET),
   1536     STRING_TOKEN(STR_EDIT_LIBMENUBAR_F1),
   1537     HMainCommandGoToOffset
   1538   },
   1539   {
   1540     STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_SAVE_BUFFER),
   1541     STRING_TOKEN(STR_EDIT_LIBMENUBAR_F2),
   1542     HMainCommandSaveBuffer
   1543   },
   1544   {
   1545     STRING_TOKEN(STR_EDIT_LIBMENUBAR_EXIT),
   1546     STRING_TOKEN(STR_EDIT_LIBMENUBAR_F3),
   1547     HMainCommandExit
   1548   },
   1549 
   1550   {
   1551     STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_SELECT_START),
   1552     STRING_TOKEN(STR_EDIT_LIBMENUBAR_F4),
   1553     HMainCommandSelectStart
   1554   },
   1555   {
   1556     STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_SELECT_END),
   1557     STRING_TOKEN(STR_EDIT_LIBMENUBAR_F5),
   1558     HMainCommandSelectEnd
   1559   },
   1560   {
   1561     STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_CUT),
   1562     STRING_TOKEN(STR_EDIT_LIBMENUBAR_F6),
   1563     HMainCommandCut
   1564   },
   1565   {
   1566     STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_PASTE),
   1567     STRING_TOKEN(STR_EDIT_LIBMENUBAR_F7),
   1568     HMainCommandPaste
   1569   },
   1570 
   1571   {
   1572     STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_OPEN_FILE),
   1573     STRING_TOKEN(STR_EDIT_LIBMENUBAR_F8),
   1574     HMainCommandOpenFile
   1575   },
   1576   {
   1577     STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_OPEN_DISK),
   1578     STRING_TOKEN(STR_EDIT_LIBMENUBAR_F9),
   1579     HMainCommandOpenDisk
   1580   },
   1581   {
   1582     STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_OPEN_MEMORY),
   1583     STRING_TOKEN(STR_EDIT_LIBMENUBAR_F10),
   1584     HMainCommandOpenMemory
   1585   },
   1586 
   1587   {
   1588     0,
   1589     0,
   1590     NULL
   1591   }
   1592 };
   1593 
   1594 /**
   1595   Init function for MainEditor
   1596 
   1597   @retval EFI_SUCCESS             The operation was successful.
   1598   @retval EFI_LOAD_ERROR          A load error occured.
   1599 **/
   1600 EFI_STATUS
   1601 HMainEditorInit (
   1602   VOID
   1603   )
   1604 {
   1605   EFI_STATUS  Status;
   1606   EFI_HANDLE  *HandleBuffer;
   1607   UINTN       HandleCount;
   1608   UINTN       Index;
   1609 
   1610   //
   1611   // basic initialization
   1612   //
   1613   CopyMem (&HMainEditor, &HMainEditorConst, sizeof (HMainEditor));
   1614 
   1615   //
   1616   // set screen attributes
   1617   //
   1618   HMainEditor.ColorAttributes.Colors.Foreground = gST->ConOut->Mode->Attribute & 0x000000ff;
   1619 
   1620   HMainEditor.ColorAttributes.Colors.Background = (UINT8) (gST->ConOut->Mode->Attribute >> 4);
   1621 
   1622   HOriginalColors = HMainEditor.ColorAttributes.Colors;
   1623 
   1624   HOriginalMode = gST->ConOut->Mode->Mode;
   1625 
   1626   //
   1627   // query screen size
   1628   //
   1629   gST->ConOut->QueryMode (
   1630         gST->ConOut,
   1631         gST->ConOut->Mode->Mode,
   1632         &(HMainEditor.ScreenSize.Column),
   1633         &(HMainEditor.ScreenSize.Row)
   1634         );
   1635 
   1636   //
   1637   // Find mouse in System Table ConsoleInHandle
   1638   //
   1639   Status = gBS->HandleProtocol (
   1640                 gST->ConIn,
   1641                 &gEfiSimplePointerProtocolGuid,
   1642                 (VOID**)&HMainEditor.MouseInterface
   1643                 );
   1644   if (EFI_ERROR (Status)) {
   1645     //
   1646     // If there is no Simple Pointer Protocol on System Table
   1647     //
   1648     HandleBuffer = NULL;
   1649     HMainEditor.MouseInterface = NULL;
   1650     Status = gBS->LocateHandleBuffer (
   1651                   ByProtocol,
   1652                   &gEfiSimplePointerProtocolGuid,
   1653                   NULL,
   1654                   &HandleCount,
   1655                   &HandleBuffer
   1656                   );
   1657     if (!EFI_ERROR (Status) && HandleCount > 0) {
   1658       //
   1659       // Try to find the first available mouse device
   1660       //
   1661       for (Index = 0; Index < HandleCount; Index++) {
   1662         Status = gBS->HandleProtocol (
   1663                       HandleBuffer[Index],
   1664                       &gEfiSimplePointerProtocolGuid,
   1665                       (VOID**)&HMainEditor.MouseInterface
   1666                       );
   1667         if (!EFI_ERROR (Status)) {
   1668           break;
   1669         }
   1670       }
   1671     }
   1672     if (HandleBuffer != NULL) {
   1673       FreePool (HandleBuffer);
   1674     }
   1675   }
   1676 
   1677   if (!EFI_ERROR (Status) && HMainEditor.MouseInterface != NULL) {
   1678     HMainEditor.MouseAccumulatorX  = 0;
   1679     HMainEditor.MouseAccumulatorY  = 0;
   1680     HMainEditor.MouseSupported     = TRUE;
   1681   }
   1682 
   1683   //
   1684   // below will call the five components' init function
   1685   //
   1686   Status = MainTitleBarInit (L"UEFI HEXEDIT");
   1687   if (EFI_ERROR (Status)) {
   1688     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_TITLE), gShellDebug1HiiHandle);
   1689     return EFI_LOAD_ERROR;
   1690   }
   1691 
   1692   Status = ControlHotKeyInit (HexMainControlBasedMenuFunctions);
   1693   if (EFI_ERROR (Status)) {
   1694     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_MAINMENU), gShellDebug1HiiHandle);
   1695     return EFI_LOAD_ERROR;
   1696   }
   1697   Status = MenuBarInit (HexEditorMenuItems);
   1698   if (EFI_ERROR (Status)) {
   1699     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_MAINMENU), gShellDebug1HiiHandle);
   1700     return EFI_LOAD_ERROR;
   1701   }
   1702 
   1703   Status = StatusBarInit ();
   1704   if (EFI_ERROR (Status)) {
   1705     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_STATUS), gShellDebug1HiiHandle);
   1706     return EFI_LOAD_ERROR;
   1707   }
   1708 
   1709   InputBarInit ();
   1710 
   1711   Status = HBufferImageInit ();
   1712   if (EFI_ERROR (Status)) {
   1713     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_BUFFERIMAGE), gShellDebug1HiiHandle);
   1714     return EFI_LOAD_ERROR;
   1715   }
   1716 
   1717   Status = HClipBoardInit ();
   1718   if (EFI_ERROR (Status)) {
   1719     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_CLIPBOARD), gShellDebug1HiiHandle);
   1720     return EFI_LOAD_ERROR;
   1721   }
   1722   //
   1723   // clear whole screen and enable cursor
   1724   //
   1725   gST->ConOut->ClearScreen (gST->ConOut);
   1726   gST->ConOut->EnableCursor (gST->ConOut, TRUE);
   1727 
   1728   //
   1729   // initialize EditorFirst and EditorExit
   1730   //
   1731   HEditorFirst        = TRUE;
   1732   HEditorExit         = FALSE;
   1733   HEditorMouseAction  = FALSE;
   1734 
   1735   return EFI_SUCCESS;
   1736 }
   1737 
   1738 /**
   1739   Cleanup function for MainEditor.
   1740 
   1741   @retval EFI_SUCCESS             The operation was successful.
   1742   @retval EFI_LOAD_ERROR          A load error occured.
   1743 **/
   1744 EFI_STATUS
   1745 HMainEditorCleanup (
   1746   VOID
   1747   )
   1748 {
   1749   EFI_STATUS  Status;
   1750 
   1751   //
   1752   // call the five components' cleanup function
   1753   //
   1754   MainTitleBarCleanup ();
   1755 
   1756   MenuBarCleanup ();
   1757 
   1758   StatusBarCleanup ();
   1759 
   1760   InputBarCleanup ();
   1761 
   1762   Status = HBufferImageCleanup ();
   1763   if (EFI_ERROR (Status)) {
   1764     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_BUFFERIMAGE_CLEAN), gShellDebug1HiiHandle);
   1765   }
   1766 
   1767   Status = HClipBoardCleanup ();
   1768   if (EFI_ERROR (Status)) {
   1769     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_CLIPBOARD_CLEAN), gShellDebug1HiiHandle);
   1770   }
   1771   //
   1772   // restore old mode
   1773   //
   1774   if (HOriginalMode != gST->ConOut->Mode->Mode) {
   1775     gST->ConOut->SetMode (gST->ConOut, HOriginalMode);
   1776   }
   1777 
   1778   gST->ConOut->SetAttribute (
   1779         gST->ConOut,
   1780         EFI_TEXT_ATTR (HOriginalColors.Foreground, HOriginalColors.Background)
   1781         );
   1782   gST->ConOut->ClearScreen (gST->ConOut);
   1783 
   1784   return EFI_SUCCESS;
   1785 }
   1786 
   1787 /**
   1788   Refresh function for MainEditor.
   1789 
   1790   @retval EFI_SUCCESS             The operation was successful.
   1791 **/
   1792 EFI_STATUS
   1793 HMainEditorRefresh (
   1794   VOID
   1795   )
   1796 {
   1797   BOOLEAN NameChange;
   1798   BOOLEAN ReadChange;
   1799 
   1800   NameChange = FALSE;
   1801   ReadChange = FALSE;
   1802 
   1803   if (HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer) {
   1804     if (HMainEditor.BufferImage->DiskImage != NULL &&
   1805         HBufferImageBackupVar.DiskImage != NULL &&
   1806         (HMainEditor.BufferImage->DiskImage->Offset != HBufferImageBackupVar.DiskImage->Offset ||
   1807            HMainEditor.BufferImage->DiskImage->Size != HBufferImageBackupVar.DiskImage->Size) ){
   1808       NameChange = TRUE;
   1809     }
   1810   } else if (HMainEditor.BufferImage->BufferType == FileTypeMemBuffer) {
   1811     if (HMainEditor.BufferImage->MemImage != NULL &&
   1812         HBufferImageBackupVar.MemImage != NULL &&
   1813         (HMainEditor.BufferImage->MemImage->Offset != HBufferImageBackupVar.MemImage->Offset ||
   1814            HMainEditor.BufferImage->MemImage->Size != HBufferImageBackupVar.MemImage->Size) ){
   1815       NameChange = TRUE;
   1816     }
   1817   } else if (HMainEditor.BufferImage->BufferType == FileTypeFileBuffer) {
   1818     if ( HMainEditor.BufferImage->FileImage != NULL &&
   1819          HMainEditor.BufferImage->FileImage->FileName != NULL &&
   1820          HBufferImageBackupVar.FileImage != NULL &&
   1821          HBufferImageBackupVar.FileImage->FileName != NULL &&
   1822          StrCmp (HMainEditor.BufferImage->FileImage->FileName, HBufferImageBackupVar.FileImage->FileName) != 0 ) {
   1823       NameChange = TRUE;
   1824     }
   1825   }
   1826   if ( HMainEditor.BufferImage->FileImage != NULL &&
   1827        HBufferImageBackupVar.FileImage != NULL &&
   1828        HMainEditor.BufferImage->FileImage->ReadOnly != HBufferImageBackupVar.FileImage->ReadOnly ) {
   1829     ReadChange = TRUE;
   1830   }
   1831 
   1832   //
   1833   // to aVOID screen flicker
   1834   // the stall value is from experience
   1835   //
   1836   gBS->Stall (50);
   1837 
   1838   //
   1839   // call the components refresh function
   1840   //
   1841   if (HEditorFirst
   1842     || NameChange
   1843     || HMainEditor.BufferImage->BufferType != HBufferImageBackupVar.BufferType
   1844     || HBufferImageBackupVar.Modified != HMainEditor.BufferImage->Modified
   1845     || ReadChange ) {
   1846 
   1847     MainTitleBarRefresh (
   1848       HMainEditor.BufferImage->BufferType == FileTypeFileBuffer&&HMainEditor.BufferImage->FileImage!=NULL?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer&&HMainEditor.BufferImage->DiskImage!=NULL?HMainEditor.BufferImage->DiskImage->Name:NULL,
   1849       HMainEditor.BufferImage->BufferType,
   1850       (BOOLEAN)(HMainEditor.BufferImage->FileImage!=NULL?HMainEditor.BufferImage->FileImage->ReadOnly:FALSE),
   1851       HMainEditor.BufferImage->Modified,
   1852       HMainEditor.ScreenSize.Column,
   1853       HMainEditor.ScreenSize.Row,
   1854       HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer&&HMainEditor.BufferImage->DiskImage!=NULL?HMainEditor.BufferImage->DiskImage->Offset:HMainEditor.BufferImage->BufferType == FileTypeMemBuffer&&HMainEditor.BufferImage->MemImage!=NULL?HMainEditor.BufferImage->MemImage->Offset:0,
   1855       HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer&&HMainEditor.BufferImage->DiskImage!=NULL?HMainEditor.BufferImage->DiskImage->Size  :HMainEditor.BufferImage->BufferType == FileTypeMemBuffer&&HMainEditor.BufferImage->MemImage!=NULL?HMainEditor.BufferImage->MemImage->Size  :0
   1856       );
   1857     HBufferImageRefresh ();
   1858   }
   1859   if (HEditorFirst
   1860     || HBufferImageBackupVar.DisplayPosition.Row != HMainEditor.BufferImage->DisplayPosition.Row
   1861     || HBufferImageBackupVar.DisplayPosition.Column != HMainEditor.BufferImage->DisplayPosition.Column
   1862     || StatusBarGetRefresh()) {
   1863 
   1864     StatusBarRefresh (
   1865       HEditorFirst,
   1866       HMainEditor.ScreenSize.Row,
   1867       HMainEditor.ScreenSize.Column,
   1868       (UINTN)(-1),
   1869       (UINTN)(-1),
   1870       FALSE
   1871       );
   1872     HBufferImageRefresh ();
   1873   }
   1874 
   1875   if (HEditorFirst) {
   1876     HBufferImageRefresh ();
   1877   }
   1878 
   1879   //
   1880   // EditorFirst is now set to FALSE
   1881   //
   1882   HEditorFirst = FALSE;
   1883 
   1884   return EFI_SUCCESS;
   1885 }
   1886 
   1887 /**
   1888   Handle the mouse input.
   1889 
   1890   @param[in] MouseState             The current mouse state.
   1891   @param[out] BeforeLeftButtonDown  helps with selections.
   1892 
   1893   @retval EFI_SUCCESS             The operation was successful.
   1894   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
   1895   @retval EFI_LOAD_ERROR          A load error occured.
   1896   @retval EFI_NOT_FOUND           The disk was not found.
   1897 **/
   1898 EFI_STATUS
   1899 HMainEditorHandleMouseInput (
   1900   IN  EFI_SIMPLE_POINTER_STATE       MouseState,
   1901   OUT BOOLEAN                        *BeforeLeftButtonDown
   1902   )
   1903 {
   1904 
   1905   INT32             TextX;
   1906   INT32             TextY;
   1907   UINTN             FRow;
   1908   UINTN             FCol;
   1909   BOOLEAN           HighBits;
   1910   LIST_ENTRY    *Link;
   1911   HEFI_EDITOR_LINE  *Line;
   1912   UINTN             Index;
   1913   BOOLEAN           Action;
   1914 
   1915   Action = FALSE;
   1916 
   1917   //
   1918   // have mouse movement
   1919   //
   1920   if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) {
   1921     //
   1922     // handle
   1923     //
   1924     TextX = HGetTextX (MouseState.RelativeMovementX);
   1925     TextY = HGetTextY (MouseState.RelativeMovementY);
   1926 
   1927     HBufferImageAdjustMousePosition (TextX, TextY);
   1928 
   1929     Action = TRUE;
   1930 
   1931   }
   1932 
   1933   if (MouseState.LeftButton) {
   1934     HighBits = HBufferImageIsAtHighBits (
   1935                 HMainEditor.BufferImage->MousePosition.Column,
   1936                 &FCol
   1937                 );
   1938 
   1939     //
   1940     // not at an movable place
   1941     //
   1942     if (FCol == 0) {
   1943       //
   1944       // now just move mouse pointer to legal position
   1945       //
   1946       //
   1947       // move mouse position to legal position
   1948       //
   1949       HMainEditor.BufferImage->MousePosition.Column -= 10;
   1950       if (HMainEditor.BufferImage->MousePosition.Column > 24) {
   1951         HMainEditor.BufferImage->MousePosition.Column--;
   1952         FCol = HMainEditor.BufferImage->MousePosition.Column / 3 + 1 + 1;
   1953       } else {
   1954         if (HMainEditor.BufferImage->MousePosition.Column < 24) {
   1955           FCol = HMainEditor.BufferImage->MousePosition.Column / 3 + 1 + 1;
   1956         } else {
   1957           //
   1958           // == 24
   1959           //
   1960           FCol = 9;
   1961         }
   1962       }
   1963 
   1964       HighBits = TRUE;
   1965 
   1966     }
   1967 
   1968     FRow = HMainEditor.BufferImage->BufferPosition.Row +
   1969       HMainEditor.BufferImage->MousePosition.Row -
   1970       HMainEditor.BufferImage->DisplayPosition.Row;
   1971 
   1972     if (HMainEditor.BufferImage->NumLines < FRow) {
   1973       //
   1974       // dragging
   1975       //
   1976       //
   1977       // now just move mouse pointer to legal position
   1978       //
   1979       FRow      = HMainEditor.BufferImage->NumLines;
   1980       HighBits  = TRUE;
   1981     }
   1982 
   1983     Link = HMainEditor.BufferImage->ListHead->ForwardLink;
   1984     for (Index = 0; Index < FRow - 1; Index++) {
   1985       Link = Link->ForwardLink;
   1986     }
   1987 
   1988     Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
   1989 
   1990     //
   1991     // dragging
   1992     //
   1993     //
   1994     // now just move mouse pointer to legal position
   1995     //
   1996     if (FCol > Line->Size) {
   1997       if (*BeforeLeftButtonDown) {
   1998         HighBits = FALSE;
   1999 
   2000         if (Line->Size == 0) {
   2001           if (FRow > 1) {
   2002             FRow--;
   2003             FCol = 16;
   2004           } else {
   2005             FRow  = 1;
   2006             FCol  = 1;
   2007           }
   2008 
   2009         } else {
   2010           FCol = Line->Size;
   2011         }
   2012       } else {
   2013         FCol      = Line->Size + 1;
   2014         HighBits  = TRUE;
   2015       }
   2016     }
   2017 
   2018     HBufferImageMovePosition (FRow, FCol, HighBits);
   2019 
   2020     HMainEditor.BufferImage->MousePosition.Row    = HMainEditor.BufferImage->DisplayPosition.Row;
   2021 
   2022     HMainEditor.BufferImage->MousePosition.Column = HMainEditor.BufferImage->DisplayPosition.Column;
   2023 
   2024     *BeforeLeftButtonDown                         = TRUE;
   2025 
   2026     Action = TRUE;
   2027   } else {
   2028     //
   2029     // else of if LButton
   2030     //
   2031     // release LButton
   2032     //
   2033     if (*BeforeLeftButtonDown) {
   2034       Action = TRUE;
   2035     }
   2036     //
   2037     // mouse up
   2038     //
   2039     *BeforeLeftButtonDown = FALSE;
   2040   }
   2041 
   2042   if (Action) {
   2043     return EFI_SUCCESS;
   2044   }
   2045 
   2046   return EFI_NOT_FOUND;
   2047 }
   2048 
   2049 /**
   2050   Handle user key input. will route it to other components handle function.
   2051 
   2052   @retval EFI_SUCCESS             The operation was successful.
   2053   @retval EFI_OUT_OF_RESOURCES    A memory allocation occured.
   2054   @retval EFI_LOAD_ERROR          A load error occured.
   2055 **/
   2056 EFI_STATUS
   2057 HMainEditorKeyInput (
   2058   VOID
   2059   )
   2060 {
   2061   EFI_INPUT_KEY             Key;
   2062   EFI_STATUS                Status;
   2063   EFI_SIMPLE_POINTER_STATE  MouseState;
   2064   BOOLEAN                   LengthChange;
   2065   UINTN                     Size;
   2066   UINTN                     OldSize;
   2067   BOOLEAN                   BeforeMouseIsDown;
   2068   BOOLEAN                   MouseIsDown;
   2069   BOOLEAN                   FirstDown;
   2070   BOOLEAN                   MouseDrag;
   2071   UINTN                     FRow;
   2072   UINTN                     FCol;
   2073   UINTN                     SelectStartBackup;
   2074   UINTN                     SelectEndBackup;
   2075 
   2076   //
   2077   // variable initialization
   2078   //
   2079   OldSize       = 0;
   2080   FRow          = 0;
   2081   FCol          = 0;
   2082   LengthChange  = FALSE;
   2083 
   2084   MouseIsDown   = FALSE;
   2085   FirstDown     = FALSE;
   2086   MouseDrag     = FALSE;
   2087 
   2088   do {
   2089 
   2090     Status              = EFI_SUCCESS;
   2091 
   2092     HEditorMouseAction  = FALSE;
   2093 
   2094     //
   2095     // backup some key elements, so that can aVOID some refresh work
   2096     //
   2097     HMainEditorBackup ();
   2098 
   2099     //
   2100     // wait for user key input
   2101     //
   2102     //
   2103     // change priority of checking mouse/keyboard activity dynamically
   2104     // so prevent starvation of keyboard.
   2105     // if last time, mouse moves then this time check keyboard
   2106     //
   2107     if (HMainEditor.MouseSupported) {
   2108       Status = HMainEditor.MouseInterface->GetState (
   2109                                             HMainEditor.MouseInterface,
   2110                                             &MouseState
   2111                                             );
   2112       if (!EFI_ERROR (Status)) {
   2113 
   2114         BeforeMouseIsDown = MouseIsDown;
   2115 
   2116         Status            = HMainEditorHandleMouseInput (MouseState, &MouseIsDown);
   2117 
   2118         if (!EFI_ERROR (Status)) {
   2119           if (!BeforeMouseIsDown) {
   2120             //
   2121             // mouse down
   2122             //
   2123             if (MouseIsDown) {
   2124               FRow              = HBufferImage.BufferPosition.Row;
   2125               FCol              = HBufferImage.BufferPosition.Column;
   2126               SelectStartBackup = HMainEditor.SelectStart;
   2127               SelectEndBackup   = HMainEditor.SelectEnd;
   2128 
   2129               FirstDown         = TRUE;
   2130             }
   2131           } else {
   2132 
   2133             SelectStartBackup = HMainEditor.SelectStart;
   2134             SelectEndBackup   = HMainEditor.SelectEnd;
   2135 
   2136             //
   2137             // begin to drag
   2138             //
   2139             if (MouseIsDown) {
   2140               if (FirstDown) {
   2141                 if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) {
   2142                   HMainEditor.SelectStart = 0;
   2143                   HMainEditor.SelectEnd   = 0;
   2144                   HMainEditor.SelectStart = (FRow - 1) * 0x10 + FCol;
   2145 
   2146                   MouseDrag               = TRUE;
   2147                   FirstDown               = FALSE;
   2148                 }
   2149               } else {
   2150                 if ((
   2151                       (HBufferImage.BufferPosition.Row - 1) *
   2152                     0x10 +
   2153                     HBufferImage.BufferPosition.Column
   2154                       ) >= HMainEditor.SelectStart
   2155                         ) {
   2156                   HMainEditor.SelectEnd = (HBufferImage.BufferPosition.Row - 1) *
   2157                     0x10 +
   2158                     HBufferImage.BufferPosition.Column;
   2159                 } else {
   2160                   HMainEditor.SelectEnd = 0;
   2161                 }
   2162               }
   2163               //
   2164               // end of if RelativeX/Y
   2165               //
   2166             } else {
   2167               //
   2168               // mouse is up
   2169               //
   2170               if (MouseDrag) {
   2171                 if (HBufferImageGetTotalSize () == 0) {
   2172                   HMainEditor.SelectStart = 0;
   2173                   HMainEditor.SelectEnd   = 0;
   2174                   FirstDown               = FALSE;
   2175                   MouseDrag               = FALSE;
   2176                 }
   2177 
   2178                 if ((
   2179                       (HBufferImage.BufferPosition.Row - 1) *
   2180                     0x10 +
   2181                     HBufferImage.BufferPosition.Column
   2182                       ) >= HMainEditor.SelectStart
   2183                         ) {
   2184                   HMainEditor.SelectEnd = (HBufferImage.BufferPosition.Row - 1) *
   2185                     0x10 +
   2186                     HBufferImage.BufferPosition.Column;
   2187                 } else {
   2188                   HMainEditor.SelectEnd = 0;
   2189                 }
   2190 
   2191                 if (HMainEditor.SelectEnd == 0) {
   2192                   HMainEditor.SelectStart = 0;
   2193                 }
   2194               }
   2195 
   2196               FirstDown = FALSE;
   2197               MouseDrag = FALSE;
   2198             }
   2199 
   2200             if (SelectStartBackup != HMainEditor.SelectStart || SelectEndBackup != HMainEditor.SelectEnd) {
   2201               if ((SelectStartBackup - 1) / 0x10 != (HMainEditor.SelectStart - 1) / 0x10) {
   2202                 HBufferImageNeedRefresh = TRUE;
   2203               } else {
   2204                 if ((SelectEndBackup - 1) / 0x10 != (HMainEditor.SelectEnd - 1) / 0x10) {
   2205                   HBufferImageNeedRefresh = TRUE;
   2206                 } else {
   2207                   HBufferImageOnlyLineNeedRefresh = TRUE;
   2208                 }
   2209               }
   2210             }
   2211           }
   2212 
   2213           HEditorMouseAction            = TRUE;
   2214           HBufferImageMouseNeedRefresh  = TRUE;
   2215 
   2216         } else if (Status == EFI_LOAD_ERROR) {
   2217           StatusBarSetStatusString (L"Invalid Mouse Movement ");
   2218         }
   2219       }
   2220     }
   2221 
   2222     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
   2223     if (!EFI_ERROR (Status)) {
   2224       //
   2225       // dispatch to different components' key handling function
   2226       // so not everywhere has to set this variable
   2227       //
   2228       HBufferImageMouseNeedRefresh = TRUE;
   2229 
   2230       //
   2231       // clear previous status string
   2232       //
   2233       StatusBarSetRefresh();
   2234       if (EFI_SUCCESS == MenuBarDispatchControlHotKey(&Key)) {
   2235         Status = EFI_SUCCESS;
   2236       } else if (Key.ScanCode == SCAN_NULL) {
   2237         Status = HBufferImageHandleInput (&Key);
   2238       } else if (((Key.ScanCode >= SCAN_UP) && (Key.ScanCode <= SCAN_PAGE_DOWN))) {
   2239         Status = HBufferImageHandleInput (&Key);
   2240       } else if (((Key.ScanCode >= SCAN_F1) && Key.ScanCode <= (SCAN_F12))) {
   2241         Status = MenuBarDispatchFunctionKey (&Key);
   2242       } else {
   2243         StatusBarSetStatusString (L"Unknown Command");
   2244 
   2245         HBufferImageMouseNeedRefresh = FALSE;
   2246       }
   2247 
   2248       if (Status != EFI_SUCCESS && Status != EFI_OUT_OF_RESOURCES) {
   2249         //
   2250         // not already has some error status
   2251         //
   2252         if (StrCmp (L"", StatusBarGetString()) == 0) {
   2253           StatusBarSetStatusString (L"Disk Error. Try Again");
   2254         }
   2255       }
   2256     }
   2257     //
   2258     // decide if has to set length warning
   2259     //
   2260     if (HBufferImage.BufferType != HBufferImageBackupVar.BufferType) {
   2261       LengthChange = FALSE;
   2262     } else {
   2263       //
   2264       // still the old buffer
   2265       //
   2266       if (HBufferImage.BufferType != FileTypeFileBuffer) {
   2267         Size = HBufferImageGetTotalSize ();
   2268 
   2269         switch (HBufferImage.BufferType) {
   2270         case FileTypeDiskBuffer:
   2271           OldSize = HBufferImage.DiskImage->Size * HBufferImage.DiskImage->BlockSize;
   2272           break;
   2273 
   2274         case FileTypeMemBuffer:
   2275           OldSize = HBufferImage.MemImage->Size;
   2276           break;
   2277 
   2278         default:
   2279           OldSize = 0;
   2280           break;
   2281         }
   2282 
   2283         if (!LengthChange) {
   2284           if (OldSize != Size) {
   2285             StatusBarSetStatusString (L"Disk/Mem Buffer Length should not be changed");
   2286           }
   2287         }
   2288 
   2289         if (OldSize != Size) {
   2290           LengthChange = TRUE;
   2291         } else {
   2292           LengthChange = FALSE;
   2293         }
   2294       }
   2295     }
   2296     //
   2297     // after handling, refresh editor
   2298     //
   2299     HMainEditorRefresh ();
   2300 
   2301   } while (Status != EFI_OUT_OF_RESOURCES && !HEditorExit);
   2302 
   2303   return Status;
   2304 }
   2305 
   2306 /**
   2307   Backup function for MainEditor.
   2308 **/
   2309 VOID
   2310 HMainEditorBackup (
   2311   VOID
   2312   )
   2313 {
   2314   HMainEditorBackupVar.SelectStart  = HMainEditor.SelectStart;
   2315   HMainEditorBackupVar.SelectEnd    = HMainEditor.SelectEnd;
   2316   HBufferImageBackup ();
   2317 }
   2318