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