1 /** @file
2   Defines HBufferImage - the view of the file that is visible at any point,
3   as well as the event handlers for editing the file
4 
5   Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved. <BR>
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "HexEditor.h"
11 
12 extern EFI_HANDLE                 HImageHandleBackup;
13 
14 extern HEFI_EDITOR_FILE_IMAGE     HFileImage;
15 extern HEFI_EDITOR_DISK_IMAGE     HDiskImage;
16 extern HEFI_EDITOR_MEM_IMAGE      HMemImage;
17 
18 extern HEFI_EDITOR_FILE_IMAGE     HFileImageBackupVar;
19 extern HEFI_EDITOR_DISK_IMAGE     HDiskImageBackupVar;
20 extern HEFI_EDITOR_MEM_IMAGE      HMemImageBackupVar;
21 
22 extern BOOLEAN                    HEditorMouseAction;
23 
24 extern HEFI_EDITOR_GLOBAL_EDITOR  HMainEditor;
25 extern HEFI_EDITOR_GLOBAL_EDITOR  HMainEditorBackupVar;
26 
27 HEFI_EDITOR_BUFFER_IMAGE          HBufferImage;
28 HEFI_EDITOR_BUFFER_IMAGE          HBufferImageBackupVar;
29 
30 //
31 // for basic initialization of HBufferImage
32 //
33 HEFI_EDITOR_BUFFER_IMAGE          HBufferImageConst = {
34   NULL,
35   NULL,
36   0,
37   NULL,
38   {
39     0,
40     0
41   },
42   {
43     0,
44     0
45   },
46   {
47     0,
48     0
49   },
50   0,
51   TRUE,
52   FALSE,
53   FileTypeNone,
54   NULL,
55   NULL,
56   NULL
57 };
58 
59 //
60 // the whole edit area needs to be refreshed
61 //
62 BOOLEAN                           HBufferImageNeedRefresh;
63 
64 //
65 // only the current line in edit area needs to be refresh
66 //
67 BOOLEAN                           HBufferImageOnlyLineNeedRefresh;
68 
69 BOOLEAN                           HBufferImageMouseNeedRefresh;
70 
71 /**
72   Initialization function for HBufferImage
73 
74   @retval EFI_SUCCESS       The operation was successful.
75   @retval EFI_LOAD_ERROR    A load error occurred.
76 **/
77 EFI_STATUS
78 HBufferImageInit (
79   VOID
80   )
81 {
82   EFI_STATUS  Status;
83 
84   //
85   // basically initialize the HBufferImage
86   //
87   CopyMem (&HBufferImage, &HBufferImageConst, sizeof (HBufferImage));
88 
89   //
90   // INIT listhead
91   //
92   HBufferImage.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY));
93   if (HBufferImage.ListHead == NULL) {
94     return EFI_LOAD_ERROR;
95   }
96 
97   InitializeListHead (HBufferImage.ListHead);
98 
99   HBufferImage.DisplayPosition.Row    = 2;
100   HBufferImage.DisplayPosition.Column = 10;
101   HBufferImage.MousePosition.Row      = 2;
102   HBufferImage.MousePosition.Column   = 10;
103 
104   HBufferImage.FileImage              = &HFileImage;
105   HBufferImage.DiskImage              = &HDiskImage;
106   HBufferImage.MemImage               = &HMemImage;
107 
108   HBufferImageNeedRefresh             = FALSE;
109   HBufferImageOnlyLineNeedRefresh     = FALSE;
110   HBufferImageMouseNeedRefresh        = FALSE;
111 
112   HBufferImageBackupVar.FileImage     = &HFileImageBackupVar;
113   HBufferImageBackupVar.DiskImage     = &HDiskImageBackupVar;
114   HBufferImageBackupVar.MemImage      = &HMemImageBackupVar;
115 
116   Status = HFileImageInit ();
117   if (EFI_ERROR (Status)) {
118     return EFI_LOAD_ERROR;
119   }
120 
121   Status = HDiskImageInit ();
122   if (EFI_ERROR (Status)) {
123     return EFI_LOAD_ERROR;
124   }
125 
126   Status = HMemImageInit ();
127   if (EFI_ERROR (Status)) {
128     return EFI_LOAD_ERROR;
129   }
130 
131   return EFI_SUCCESS;
132 }
133 
134 /**
135   Backup function for HBufferImage. Only a few fields need to be backup.
136   This is for making the file buffer refresh as few as possible.
137 
138   @retval EFI_SUCCESS  The operation was successful.
139 **/
140 EFI_STATUS
141 HBufferImageBackup (
142   VOID
143   )
144 {
145   HBufferImageBackupVar.MousePosition   = HBufferImage.MousePosition;
146 
147   HBufferImageBackupVar.BufferPosition  = HBufferImage.BufferPosition;
148 
149   HBufferImageBackupVar.Modified        = HBufferImage.Modified;
150 
151   HBufferImageBackupVar.BufferType      = HBufferImage.BufferType;
152   HBufferImageBackupVar.LowVisibleRow   = HBufferImage.LowVisibleRow;
153   HBufferImageBackupVar.HighBits        = HBufferImage.HighBits;
154 
155   //
156   // three kinds of buffer supported
157   //   file buffer
158   //   disk buffer
159   //   memory buffer
160   //
161   switch (HBufferImage.BufferType) {
162   case FileTypeFileBuffer:
163     HFileImageBackup ();
164     break;
165 
166   case FileTypeDiskBuffer:
167     HDiskImageBackup ();
168     break;
169 
170   case FileTypeMemBuffer:
171     HMemImageBackup ();
172     break;
173 
174   default:
175     break;
176   }
177 
178   return EFI_SUCCESS;
179 }
180 
181 /**
182   Free all the lines in HBufferImage.
183     Fields affected:
184     Lines
185     CurrentLine
186     NumLines
187     ListHead
188 
189   @retval EFI_SUCCESS  The operation was successful.
190 **/
191 EFI_STATUS
192 HBufferImageFreeLines (
193   VOID
194   )
195 {
196   HFreeLines (HBufferImage.ListHead, HBufferImage.Lines);
197 
198   HBufferImage.Lines        = NULL;
199   HBufferImage.CurrentLine  = NULL;
200   HBufferImage.NumLines     = 0;
201 
202   return EFI_SUCCESS;
203 }
204 
205 /**
206   Cleanup function for HBufferImage
207 
208   @retval EFI_SUCCESS  The operation was successful.
209 **/
210 EFI_STATUS
211 HBufferImageCleanup (
212   VOID
213   )
214 {
215   EFI_STATUS  Status;
216 
217   //
218   // free all the lines
219   //
220   Status = HBufferImageFreeLines ();
221 
222   SHELL_FREE_NON_NULL (HBufferImage.ListHead);
223   HBufferImage.ListHead = NULL;
224 
225   HFileImageCleanup ();
226   HDiskImageCleanup ();
227 
228   return Status;
229 
230 }
231 
232 /**
233   Print Line on Row
234 
235   @param[in] Line     The lline to print.
236   @param[in] Row      The row on screen ( begin from 1 ).
237   @param[in] FRow     The FRow.
238   @param[in] Orig     The original color.
239   @param[in] New      The color to print with.
240 
241   @retval EFI_SUCCESS The operation was successful.
242 **/
243 EFI_STATUS
244 HBufferImagePrintLine (
245   IN HEFI_EDITOR_LINE           *Line,
246   IN UINTN                      Row,
247   IN UINTN                      FRow,
248   IN HEFI_EDITOR_COLOR_UNION    Orig,
249   IN HEFI_EDITOR_COLOR_UNION    New
250 
251   )
252 {
253 
254   UINTN   Index;
255   UINTN   Pos;
256   BOOLEAN Selected;
257   BOOLEAN BeNewColor;
258   UINTN   RowStart;
259   UINTN   RowEnd;
260   UINTN   ColStart;
261   UINTN   ColEnd;
262 
263   //
264   // variable initialization
265   //
266   ColStart  = 0;
267   ColEnd    = 0;
268   Selected  = FALSE;
269 
270   //
271   // print the selected area in opposite color
272   //
273   if (HMainEditor.SelectStart != 0 && HMainEditor.SelectEnd != 0) {
274     RowStart  = (HMainEditor.SelectStart - 1) / 0x10 + 1;
275     RowEnd    = (HMainEditor.SelectEnd - 1) / 0x10 + 1;
276 
277     ColStart  = (HMainEditor.SelectStart - 1) % 0x10 + 1;
278     ColEnd    = (HMainEditor.SelectEnd - 1) % 0x10 + 1;
279 
280     if (FRow >= RowStart && FRow <= RowEnd) {
281       Selected = TRUE;
282     }
283 
284     if (FRow > RowStart) {
285       ColStart = 1;
286     }
287 
288     if (FRow < RowEnd) {
289       ColEnd = 0x10;
290     }
291 
292   }
293 
294   if (!HEditorMouseAction) {
295     ShellPrintEx (
296       0,
297       (INT32)Row - 1,
298       L"%8X ",
299       ((INT32)Row - 2 + HBufferImage.LowVisibleRow - 1) * 0x10
300       );
301 
302   }
303 
304   for (Index = 0; Index < 0x08 && Index < Line->Size; Index++) {
305 
306     BeNewColor = FALSE;
307 
308     if (Selected) {
309       if (Index + 1 >= ColStart && Index + 1 <= ColEnd) {
310         BeNewColor = TRUE;
311       }
312     }
313 
314     if (BeNewColor) {
315       gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F);
316     } else {
317       gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F);
318     }
319 
320     Pos = 10 + (Index * 3);
321     if (Line->Buffer[Index] < 0x10) {
322       ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"0");
323       Pos++;
324     }
325 
326     if (Index < 0x07) {
327       ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]);
328     } else {
329       ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x  ", Line->Buffer[Index]);
330     }
331 
332   }
333 
334   gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F);
335   while (Index < 0x08) {
336     Pos = 10 + (Index * 3);
337     ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"    ");
338     Index++;
339   }
340 
341   while (Index < 0x10 && Index < Line->Size) {
342 
343     BeNewColor = FALSE;
344 
345     if (Selected) {
346       if (Index + 1 >= ColStart && Index + 1 <= ColEnd) {
347         BeNewColor = TRUE;
348       }
349     }
350 
351     if (BeNewColor) {
352       gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F);
353     } else {
354       gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F);
355     }
356 
357     Pos = 10 + (Index * 3) + 1;
358     if (Line->Buffer[Index] < 0x10) {
359       ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"0");
360       Pos++;
361     }
362 
363     ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]);
364     Index++;
365   }
366 
367   gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F);
368   while (Index < 0x10) {
369     Pos = 10 + (Index * 3) + 1;
370     ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"   ");
371     Index++;
372   }
373   //
374   // restore the original color
375   //
376   gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F);
377 
378   //
379   // PRINT the buffer content
380   //
381   if (!HEditorMouseAction) {
382     for (Index = 0; Index < 0x10 && Index < Line->Size; Index++) {
383       Pos = ASCII_POSITION + Index;
384 
385       //
386       // learned from shelle.h -- IsValidChar
387       //
388       if (Line->Buffer[Index] >= L' ') {
389         ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%c", (CHAR16) Line->Buffer[Index]);
390       } else {
391         ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%c", '.');
392       }
393     }
394 
395     while (Index < 0x10) {
396       Pos = ASCII_POSITION + Index;
397       ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" ");
398       Index++;
399     }
400   }
401   //
402   // restore the abundant blank in hex edit area to original color
403   //
404   if (Selected) {
405     if (ColEnd <= 7) {
406       Pos = 10 + (ColEnd - 1) * 3 + 2;
407       ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" ");
408     } else if (ColEnd == 8) {
409       Pos = 10 + (ColEnd - 1) * 3 + 2;
410       ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"  ");
411     } else {
412       Pos = 10 + (ColEnd - 1) * 3 + 3;
413       ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" ");
414     }
415   }
416 
417   return EFI_SUCCESS;
418 }
419 
420 /**
421   Function to decide if a column number is stored in the high bits.
422 
423   @param[in] Column     The column to examine.
424   @param[out] FCol      The actual column number.
425 
426   @retval TRUE      The actual column was in high bits and is now in FCol.
427   @retval FALSE     There was not a column number in the high bits.
428 **/
429 BOOLEAN
430 HBufferImageIsAtHighBits (
431   IN  UINTN Column,
432   OUT UINTN *FCol
433   )
434 {
435   Column -= 10;
436 
437   //
438   // NOW AFTER THE SUB, Column start from 0
439   // 23 AND 24 ARE BOTH BLANK
440   //
441   if (Column == 24) {
442     *FCol = 0;
443     return FALSE;
444   }
445 
446   if (Column > 24) {
447     Column--;
448   }
449 
450   *FCol = (Column / 3) + 1;
451 
452   if (Column % 3 == 0) {
453     return TRUE;
454   }
455 
456   if ((Column % 3 == 2)) {
457     *FCol = 0;
458   }
459 
460   return FALSE;
461 }
462 
463 /**
464   Decide if a point is in the already selected area.
465 
466   @param[in] MouseRow     The row of the point to test.
467   @param[in] MouseCol     The col of the point to test.
468 
469   @retval TRUE      The point is in the selected area.
470   @retval FALSE     The point is not in the selected area.
471 **/
472 BOOLEAN
473 HBufferImageIsInSelectedArea (
474   IN UINTN MouseRow,
475   IN UINTN MouseCol
476   )
477 {
478   UINTN FRow;
479   UINTN RowStart;
480   UINTN RowEnd;
481   UINTN ColStart;
482   UINTN ColEnd;
483   UINTN MouseColStart;
484   UINTN MouseColEnd;
485 
486   //
487   // judge mouse position whether is in selected area
488   //
489   //
490   // not select
491   //
492   if (HMainEditor.SelectStart == 0 || HMainEditor.SelectEnd == 0) {
493     return FALSE;
494   }
495   //
496   // calculate the select area
497   //
498   RowStart  = (HMainEditor.SelectStart - 1) / 0x10 + 1;
499   RowEnd    = (HMainEditor.SelectEnd - 1) / 0x10 + 1;
500 
501   ColStart  = (HMainEditor.SelectStart - 1) % 0x10 + 1;
502   ColEnd    = (HMainEditor.SelectEnd - 1) % 0x10 + 1;
503 
504   FRow      = HBufferImage.LowVisibleRow + MouseRow - 2;
505   if (FRow < RowStart || FRow > RowEnd) {
506     return FALSE;
507   }
508 
509   if (FRow > RowStart) {
510     ColStart = 1;
511   }
512 
513   if (FRow < RowEnd) {
514     ColEnd = 0x10;
515   }
516 
517   MouseColStart = 10 + (ColStart - 1) * 3;
518   if (ColStart > 8) {
519     MouseColStart++;
520   }
521 
522   MouseColEnd = 10 + (ColEnd - 1) * 3 + 1;
523   if (ColEnd > 8) {
524     MouseColEnd++;
525   }
526 
527   if (MouseCol < MouseColStart || MouseCol > MouseColEnd) {
528     return FALSE;
529   }
530 
531   return TRUE;
532 }
533 
534 /**
535   Set mouse position according to HBufferImage.MousePosition.
536 
537   @retval EFI_SUCCESS  The operation was successful.
538 **/
539 EFI_STATUS
540 HBufferImageRestoreMousePosition (
541   VOID
542   )
543 {
544   HEFI_EDITOR_COLOR_UNION Orig;
545   HEFI_EDITOR_COLOR_UNION New;
546   UINTN                   FRow;
547   UINTN                   FColumn;
548   BOOLEAN                 HasCharacter;
549   HEFI_EDITOR_LINE        *CurrentLine;
550   HEFI_EDITOR_LINE        *Line;
551   UINT8                   Value;
552   BOOLEAN                 HighBits;
553 
554   Line = NULL;
555   if (HMainEditor.MouseSupported) {
556 
557     if (HBufferImageMouseNeedRefresh) {
558 
559       HBufferImageMouseNeedRefresh = FALSE;
560 
561       //
562       // if mouse position not moved and only mouse action
563       // so do not need to refresh mouse position
564       //
565       if ((
566             HBufferImage.MousePosition.Row == HBufferImageBackupVar.MousePosition.Row &&
567           HBufferImage.MousePosition.Column == HBufferImageBackupVar.MousePosition.Column
568         ) &&
569           HEditorMouseAction
570           ) {
571         return EFI_SUCCESS;
572       }
573       //
574       // backup the old screen attributes
575       //
576       Orig                  = HMainEditor.ColorAttributes;
577       New.Data              = 0;
578       New.Colors.Foreground = Orig.Colors.Background & 0xF;
579       New.Colors.Background = Orig.Colors.Foreground & 0x7;
580 
581       //
582       // if in selected area,
583       // so do not need to refresh mouse
584       //
585       if (!HBufferImageIsInSelectedArea (
586             HBufferImageBackupVar.MousePosition.Row,
587             HBufferImageBackupVar.MousePosition.Column
588             )) {
589         gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);
590       } else {
591         gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F);
592       }
593       //
594       // clear the old mouse position
595       //
596       FRow = HBufferImage.LowVisibleRow + HBufferImageBackupVar.MousePosition.Row - 2;
597 
598       HighBits = HBufferImageIsAtHighBits (
599                   HBufferImageBackupVar.MousePosition.Column,
600                   &FColumn
601                   );
602 
603       HasCharacter = TRUE;
604       if (FRow > HBufferImage.NumLines || FColumn == 0) {
605         HasCharacter = FALSE;
606       } else {
607         CurrentLine = HBufferImage.CurrentLine;
608         Line        = HMoveLine (FRow - HBufferImage.BufferPosition.Row);
609 
610         if (Line == NULL || FColumn > Line->Size) {
611           HasCharacter = FALSE;
612         }
613 
614         HBufferImage.CurrentLine = CurrentLine;
615       }
616 
617       ShellPrintEx (
618         (INT32)HBufferImageBackupVar.MousePosition.Column - 1,
619         (INT32)HBufferImageBackupVar.MousePosition.Row - 1,
620         L" "
621         );
622 
623       if (HasCharacter) {
624         if (HighBits) {
625           Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf0);
626           Value = (UINT8) (Value >> 4);
627         } else {
628           Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf);
629         }
630 
631         ShellPrintEx (
632           (INT32)HBufferImageBackupVar.MousePosition.Column - 1,
633           (INT32)HBufferImageBackupVar.MousePosition.Row - 1,
634           L"%x",
635           Value
636           );
637       }
638 
639       if (!HBufferImageIsInSelectedArea (
640             HBufferImage.MousePosition.Row,
641             HBufferImage.MousePosition.Column
642             )) {
643         gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F);
644       } else {
645         gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);
646       }
647       //
648       // clear the old mouse position
649       //
650       FRow = HBufferImage.LowVisibleRow + HBufferImage.MousePosition.Row - 2;
651 
652       HighBits = HBufferImageIsAtHighBits (
653                   HBufferImage.MousePosition.Column,
654                   &FColumn
655                   );
656 
657       HasCharacter = TRUE;
658       if (FRow > HBufferImage.NumLines || FColumn == 0) {
659         HasCharacter = FALSE;
660       } else {
661         CurrentLine = HBufferImage.CurrentLine;
662         Line        = HMoveLine (FRow - HBufferImage.BufferPosition.Row);
663 
664         if (Line == NULL || FColumn > Line->Size) {
665           HasCharacter = FALSE;
666         }
667 
668         HBufferImage.CurrentLine = CurrentLine;
669       }
670 
671       ShellPrintEx (
672         (INT32)HBufferImage.MousePosition.Column - 1,
673         (INT32)HBufferImage.MousePosition.Row - 1,
674         L" "
675         );
676 
677       if (HasCharacter) {
678         if (HighBits) {
679           Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf0);
680           Value = (UINT8) (Value >> 4);
681         } else {
682           Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf);
683         }
684 
685         ShellPrintEx (
686           (INT32)HBufferImage.MousePosition.Column - 1,
687           (INT32)HBufferImage.MousePosition.Row - 1,
688           L"%x",
689           Value
690           );
691       }
692       //
693       // end of HasCharacter
694       //
695       gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);
696     }
697     //
698     // end of MouseNeedRefresh
699     //
700   }
701   //
702   // end of MouseSupported
703   //
704   return EFI_SUCCESS;
705 }
706 
707 /**
708   Set cursor position according to HBufferImage.DisplayPosition.
709 
710   @retval EFI_SUCCESS  The operation was successful.
711 **/
712 EFI_STATUS
713 HBufferImageRestorePosition (
714   VOID
715   )
716 {
717   //
718   // set cursor position
719   //
720   gST->ConOut->SetCursorPosition (
721         gST->ConOut,
722         HBufferImage.DisplayPosition.Column - 1,
723         HBufferImage.DisplayPosition.Row - 1
724         );
725 
726   return EFI_SUCCESS;
727 }
728 
729 /**
730   Refresh function for HBufferImage.
731 
732   @retval EFI_SUCCESS     The operation was successful.
733   @retval EFI_LOAD_ERROR  A Load error occurred.
734 
735 **/
736 EFI_STATUS
737 HBufferImageRefresh (
738   VOID
739   )
740 {
741   LIST_ENTRY          *Link;
742   HEFI_EDITOR_LINE        *Line;
743   UINTN                   Row;
744   HEFI_EDITOR_COLOR_UNION Orig;
745   HEFI_EDITOR_COLOR_UNION New;
746 
747   UINTN                   StartRow;
748   UINTN                   EndRow;
749   UINTN                   FStartRow;
750   UINTN                   Tmp;
751 
752   Orig                  = HMainEditor.ColorAttributes;
753   New.Data              = 0;
754   New.Colors.Foreground = Orig.Colors.Background;
755   New.Colors.Background = Orig.Colors.Foreground;
756 
757   //
758   // if it's the first time after editor launch, so should refresh
759   //
760   if (HEditorFirst == FALSE) {
761     //
762     // no definite required refresh
763     // and file position displayed on screen has not been changed
764     //
765     if (!HBufferImageNeedRefresh &&
766         !HBufferImageOnlyLineNeedRefresh &&
767         HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow
768         ) {
769       HBufferImageRestoreMousePosition ();
770       HBufferImageRestorePosition ();
771       return EFI_SUCCESS;
772     }
773   }
774 
775   gST->ConOut->EnableCursor (gST->ConOut, FALSE);
776 
777   //
778   // only need to refresh current line
779   //
780   if (HBufferImageOnlyLineNeedRefresh && HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow) {
781 
782     HBufferImagePrintLine (
783       HBufferImage.CurrentLine,
784       HBufferImage.DisplayPosition.Row,
785       HBufferImage.BufferPosition.Row,
786       Orig,
787       New
788       );
789   } else {
790     //
791     // the whole edit area need refresh
792     //
793     if (HEditorMouseAction && HMainEditor.SelectStart != 0 && HMainEditor.SelectEnd != 0) {
794       if (HMainEditor.SelectStart != HMainEditorBackupVar.SelectStart) {
795         if (HMainEditor.SelectStart >= HMainEditorBackupVar.SelectStart && HMainEditorBackupVar.SelectStart != 0) {
796           StartRow = (HMainEditorBackupVar.SelectStart - 1) / 0x10 + 1;
797         } else {
798           StartRow = (HMainEditor.SelectStart - 1) / 0x10 + 1;
799         }
800       } else {
801         StartRow = (HMainEditor.SelectStart - 1) / 0x10 + 1;
802       }
803 
804       if (HMainEditor.SelectEnd <= HMainEditorBackupVar.SelectEnd) {
805         EndRow = (HMainEditorBackupVar.SelectEnd - 1) / 0x10 + 1;
806       } else {
807         EndRow = (HMainEditor.SelectEnd - 1) / 0x10 + 1;
808       }
809       //
810       // swap
811       //
812       if (StartRow > EndRow) {
813         Tmp       = StartRow;
814         StartRow  = EndRow;
815         EndRow    = Tmp;
816       }
817 
818       FStartRow = StartRow;
819 
820       StartRow  = 2 + StartRow - HBufferImage.LowVisibleRow;
821       EndRow    = 2 + EndRow - HBufferImage.LowVisibleRow;
822 
823     } else {
824       //
825       // not mouse selection actions
826       //
827       FStartRow = HBufferImage.LowVisibleRow;
828       StartRow  = 2;
829       EndRow    = (HMainEditor.ScreenSize.Row - 1);
830     }
831     //
832     // no line
833     //
834     if (HBufferImage.Lines == NULL) {
835       HBufferImageRestoreMousePosition ();
836       HBufferImageRestorePosition ();
837       gST->ConOut->EnableCursor (gST->ConOut, TRUE);
838       return EFI_SUCCESS;
839     }
840     //
841     // get the first line that will be displayed
842     //
843     Line = HMoveLine (FStartRow - HBufferImage.BufferPosition.Row);
844     if (Line == NULL) {
845       gST->ConOut->EnableCursor (gST->ConOut, TRUE);
846       return EFI_LOAD_ERROR;
847     }
848 
849     Link  = &(Line->Link);
850     Row   = StartRow;
851     do {
852       Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
853 
854       //
855       // print line at row
856       //
857       HBufferImagePrintLine (
858         Line,
859         Row,
860         HBufferImage.LowVisibleRow + Row - 2,
861         Orig,
862         New
863         );
864 
865       Link = Link->ForwardLink;
866       Row++;
867     } while (Link != HBufferImage.ListHead && Row <= EndRow);
868 
869     while (Row <= EndRow) {
870       EditorClearLine (Row, HMainEditor.ScreenSize.Column, HMainEditor.ScreenSize.Row);
871       Row++;
872     }
873     //
874     // while not file end and not screen full
875     //
876   }
877 
878   HBufferImageRestoreMousePosition ();
879   HBufferImageRestorePosition ();
880 
881   HBufferImageNeedRefresh         = FALSE;
882   HBufferImageOnlyLineNeedRefresh = FALSE;
883   gST->ConOut->EnableCursor (gST->ConOut, TRUE);
884 
885   return EFI_SUCCESS;
886 }
887 
888 /**
889   Read an image into a buffer friom a source.
890 
891   @param[in] FileName     Pointer to the file name.  OPTIONAL and ignored if not FileTypeFileBuffer.
892   @param[in] DiskName     Pointer to the disk name.  OPTIONAL and ignored if not FileTypeDiskBuffer.
893   @param[in] DiskOffset   Offset into the disk.  OPTIONAL and ignored if not FileTypeDiskBuffer.
894   @param[in] DiskSize     Size of the disk buffer.  OPTIONAL and ignored if not FileTypeDiskBuffer.
895   @param[in] MemOffset    Offset into the Memory.  OPTIONAL and ignored if not FileTypeMemBuffer.
896   @param[in] MemSize      Size of the Memory buffer.  OPTIONAL and ignored if not FileTypeMemBuffer.
897   @param[in] BufferType   The type of buffer to save.  IGNORED.
898   @param[in] Recover      TRUE for recovermode, FALSE otherwise.
899 
900   @return EFI_SUCCESS     The operation was successful.
901 **/
902 EFI_STATUS
903 HBufferImageRead (
904   IN CONST CHAR16                   *FileName,
905   IN CONST CHAR16                   *DiskName,
906   IN UINTN                          DiskOffset,
907   IN UINTN                          DiskSize,
908   IN UINTN                          MemOffset,
909   IN UINTN                          MemSize,
910   IN EDIT_FILE_TYPE                 BufferType,
911   IN BOOLEAN                        Recover
912   )
913 {
914   EFI_STATUS                      Status;
915   EDIT_FILE_TYPE                  BufferTypeBackup;
916 
917   //
918   // variable initialization
919   //
920   Status = EFI_SUCCESS;
921   HBufferImage.BufferType = BufferType;
922 
923   //
924   // three types of buffer supported
925   //   file buffer
926   //   disk buffer
927   //   memory buffer
928   //
929   BufferTypeBackup = HBufferImage.BufferType;
930 
931   switch (BufferType) {
932   case FileTypeFileBuffer:
933     Status = HFileImageRead (FileName, Recover);
934     break;
935 
936   case FileTypeDiskBuffer:
937     Status = HDiskImageRead (DiskName, DiskOffset, DiskSize, Recover);
938     break;
939 
940   case FileTypeMemBuffer:
941     Status = HMemImageRead (MemOffset, MemSize, Recover);
942     break;
943 
944   default:
945     Status = EFI_NOT_FOUND;
946     break;
947   }
948 
949   if (EFI_ERROR (Status)) {
950     HBufferImage.BufferType = BufferTypeBackup;
951   }
952 
953   return Status;
954 }
955 
956 /**
957   Save the current image.
958 
959   @param[in] FileName     Pointer to the file name.  OPTIONAL and ignored if not FileTypeFileBuffer.
960   @param[in] DiskName     Pointer to the disk name.  OPTIONAL and ignored if not FileTypeDiskBuffer.
961   @param[in] DiskOffset   Offset into the disk.  OPTIONAL and ignored if not FileTypeDiskBuffer.
962   @param[in] DiskSize     Size of the disk buffer.  OPTIONAL and ignored if not FileTypeDiskBuffer.
963   @param[in] MemOffset    Offset into the Memory.  OPTIONAL and ignored if not FileTypeMemBuffer.
964   @param[in] MemSize      Size of the Memory buffer.  OPTIONAL and ignored if not FileTypeMemBuffer.
965   @param[in] BufferType   The type of buffer to save.  IGNORED.
966 
967   @return EFI_SUCCESS     The operation was successful.
968 **/
969 EFI_STATUS
970 HBufferImageSave (
971   IN CHAR16                         *FileName,
972   IN CHAR16                         *DiskName,
973   IN UINTN                          DiskOffset,
974   IN UINTN                          DiskSize,
975   IN UINTN                          MemOffset,
976   IN UINTN                          MemSize,
977   IN EDIT_FILE_TYPE                 BufferType
978   )
979 {
980   EFI_STATUS                      Status;
981   EDIT_FILE_TYPE                  BufferTypeBackup;
982 
983   //
984   // variable initialization
985   //
986   Status            = EFI_SUCCESS;
987   BufferTypeBackup  = HBufferImage.BufferType;
988 
989   switch (HBufferImage.BufferType) {
990   //
991   // file buffer
992   //
993   case FileTypeFileBuffer:
994     Status = HFileImageSave (FileName);
995     break;
996 
997   //
998   // disk buffer
999   //
1000   case FileTypeDiskBuffer:
1001     Status = HDiskImageSave (DiskName, DiskOffset, DiskSize);
1002     break;
1003 
1004   //
1005   // memory buffer
1006   //
1007   case FileTypeMemBuffer:
1008     Status = HMemImageSave (MemOffset, MemSize);
1009     break;
1010 
1011   default:
1012     Status = EFI_NOT_FOUND;
1013     break;
1014   }
1015 
1016   if (EFI_ERROR (Status)) {
1017     HBufferImage.BufferType = BufferTypeBackup;
1018   }
1019 
1020   return Status;
1021 }
1022 
1023 /**
1024   Create a new line and append it to the line list.
1025     Fields affected:
1026     NumLines
1027     Lines
1028 
1029   @retval NULL    create line failed.
1030   @return         the line created.
1031 
1032 **/
1033 HEFI_EDITOR_LINE *
1034 HBufferImageCreateLine (
1035   VOID
1036   )
1037 {
1038   HEFI_EDITOR_LINE  *Line;
1039 
1040   //
1041   // allocate for line structure
1042   //
1043   Line = AllocateZeroPool (sizeof (HEFI_EDITOR_LINE));
1044   if (Line == NULL) {
1045     return NULL;
1046   }
1047 
1048   Line->Signature = EFI_EDITOR_LINE_LIST;
1049   Line->Size      = 0;
1050 
1051   HBufferImage.NumLines++;
1052 
1053   //
1054   // insert to line list
1055   //
1056   InsertTailList (HBufferImage.ListHead, &Line->Link);
1057 
1058   if (HBufferImage.Lines == NULL) {
1059     HBufferImage.Lines = CR (
1060                           HBufferImage.ListHead->ForwardLink,
1061                           HEFI_EDITOR_LINE,
1062                           Link,
1063                           EFI_EDITOR_LINE_LIST
1064                           );
1065   }
1066 
1067   return Line;
1068 }
1069 
1070 /**
1071   Free the current image.
1072 
1073   @retval EFI_SUCCESS   The operation was successful.
1074 **/
1075 EFI_STATUS
1076 HBufferImageFree (
1077   VOID
1078   )
1079 {
1080   //
1081   // free all lines
1082   //
1083   HBufferImageFreeLines ();
1084 
1085   return EFI_SUCCESS;
1086 }
1087 
1088 /**
1089   change char to int value based on Hex.
1090 
1091   @param[in] Char     The input char.
1092 
1093   @return The character's index value.
1094   @retval -1  The operation failed.
1095 **/
1096 INTN
1097 HBufferImageCharToHex (
1098   IN CHAR16 Char
1099   )
1100 {
1101   //
1102   // change the character to hex
1103   //
1104   if (Char >= L'0' && Char <= L'9') {
1105     return (Char - L'0');
1106   }
1107 
1108   if (Char >= L'a' && Char <= L'f') {
1109     return (Char - L'a' + 10);
1110   }
1111 
1112   if (Char >= L'A' && Char <= L'F') {
1113     return (Char - L'A' + 10);
1114   }
1115 
1116   return -1;
1117 }
1118 
1119 /**
1120   Add character.
1121 
1122   @param[in] Char -- input char.
1123 
1124   @retval EFI_SUCCESS             The operation was successful.
1125   @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.
1126 **/
1127 EFI_STATUS
1128 HBufferImageAddChar (
1129   IN  CHAR16  Char
1130   )
1131 {
1132   HEFI_EDITOR_LINE  *Line;
1133   HEFI_EDITOR_LINE  *NewLine;
1134   INTN              Value;
1135   UINT8             Old;
1136   UINTN             FRow;
1137   UINTN             FCol;
1138   BOOLEAN           High;
1139 
1140   Value = HBufferImageCharToHex (Char);
1141 
1142   //
1143   // invalid input
1144   //
1145   if (Value == -1) {
1146     return EFI_SUCCESS;
1147   }
1148 
1149   Line  = HBufferImage.CurrentLine;
1150   FRow  = HBufferImage.BufferPosition.Row;
1151   FCol  = HBufferImage.BufferPosition.Column;
1152   High  = HBufferImage.HighBits;
1153 
1154   //
1155   // only needs to refresh current line
1156   //
1157   HBufferImageOnlyLineNeedRefresh = TRUE;
1158 
1159   //
1160   // not a full line and beyond the last character
1161   //
1162   if (FCol > Line->Size) {
1163     //
1164     // cursor always at high 4 bits
1165     // and always put input to the low 4 bits
1166     //
1167     Line->Buffer[Line->Size] = (UINT8) Value;
1168     Line->Size++;
1169     High = FALSE;
1170   } else {
1171 
1172     Old = Line->Buffer[FCol - 1];
1173 
1174     //
1175     // always put the input to the low 4 bits
1176     //
1177     Old                     = (UINT8) (Old & 0x0f);
1178     Old                     = (UINT8) (Old << 4);
1179     Old                     = (UINT8) (Value + Old);
1180     Line->Buffer[FCol - 1]  = Old;
1181 
1182     //
1183     // at the low 4 bits of the last character of a full line
1184     // so if no next line, need to create a new line
1185     //
1186     if (!High && FCol == 0x10) {
1187 
1188       HBufferImageOnlyLineNeedRefresh = FALSE;
1189       HBufferImageNeedRefresh         = TRUE;
1190 
1191       if (Line->Link.ForwardLink == HBufferImage.ListHead) {
1192         //
1193         // last line
1194         //
1195         // create a new line
1196         //
1197         NewLine = HBufferImageCreateLine ();
1198         if (NewLine == NULL) {
1199           return EFI_OUT_OF_RESOURCES;
1200         }
1201         //
1202         // end of NULL
1203         //
1204       }
1205       //
1206       // end of == ListHead
1207       //
1208     }
1209     //
1210     // end of == 0x10
1211     //
1212     // if already at end of this line, scroll it to the start of next line
1213     //
1214     if (FCol == 0x10 && !High) {
1215       //
1216       // definitely has next line
1217       //
1218       FRow++;
1219       FCol  = 1;
1220       High  = TRUE;
1221     } else {
1222       //
1223       // if not at end of this line, just move to next column
1224       //
1225       if (!High) {
1226         FCol++;
1227       }
1228 
1229       if (High) {
1230         High = FALSE;
1231       } else {
1232         High = TRUE;
1233       }
1234 
1235     }
1236     //
1237     // end of ==FALSE
1238     //
1239   }
1240   //
1241   // move cursor to right
1242   //
1243   HBufferImageMovePosition (FRow, FCol, High);
1244 
1245   if (!HBufferImage.Modified) {
1246     HBufferImage.Modified = TRUE;
1247   }
1248 
1249   return EFI_SUCCESS;
1250 }
1251 
1252 /**
1253   Delete the previous character.
1254 
1255   @retval EFI_SUCCESS   The operationw as successful.
1256 **/
1257 EFI_STATUS
1258 HBufferImageDoBackspace (
1259   VOID
1260   )
1261 {
1262   HEFI_EDITOR_LINE  *Line;
1263 
1264   UINTN             FileColumn;
1265   UINTN             FPos;
1266   BOOLEAN           LastLine;
1267 
1268   //
1269   // variable initialization
1270   //
1271   LastLine = FALSE;
1272 
1273   //
1274   // already the first character
1275   //
1276   if (HBufferImage.BufferPosition.Row == 1 && HBufferImage.BufferPosition.Column == 1) {
1277     return EFI_SUCCESS;
1278   }
1279 
1280   FPos        = (HBufferImage.BufferPosition.Row - 1) * 0x10 + HBufferImage.BufferPosition.Column - 1;
1281 
1282   FileColumn  = HBufferImage.BufferPosition.Column;
1283 
1284   Line        = HBufferImage.CurrentLine;
1285   LastLine    = FALSE;
1286   if (Line->Link.ForwardLink == HBufferImage.ListHead && FileColumn > 1) {
1287     LastLine = TRUE;
1288   }
1289 
1290   HBufferImageDeleteCharacterFromBuffer (FPos - 1, 1, NULL);
1291 
1292   //
1293   // if is the last line
1294   // then only this line need to be refreshed
1295   //
1296   if (LastLine) {
1297     HBufferImageNeedRefresh         = FALSE;
1298     HBufferImageOnlyLineNeedRefresh = TRUE;
1299   } else {
1300     HBufferImageNeedRefresh         = TRUE;
1301     HBufferImageOnlyLineNeedRefresh = FALSE;
1302   }
1303 
1304   if (!HBufferImage.Modified) {
1305     HBufferImage.Modified = TRUE;
1306   }
1307 
1308   return EFI_SUCCESS;
1309 }
1310 
1311 /**
1312   ASCII key + Backspace + return.
1313 
1314   @param[in] Char               The input char.
1315 
1316   @retval EFI_SUCCESS           The operation was successful.
1317   @retval EFI_LOAD_ERROR        A load error occurred.
1318   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
1319 **/
1320 EFI_STATUS
1321 HBufferImageDoCharInput (
1322   IN  CHAR16  Char
1323   )
1324 {
1325   EFI_STATUS  Status;
1326 
1327   Status = EFI_SUCCESS;
1328 
1329   switch (Char) {
1330   case 0:
1331     break;
1332 
1333   case 0x08:
1334     Status = HBufferImageDoBackspace ();
1335     break;
1336 
1337   case 0x09:
1338   case 0x0a:
1339   case 0x0d:
1340     //
1341     // Tabs, Returns are thought as nothing
1342     //
1343     break;
1344 
1345   default:
1346     //
1347     // DEAL WITH ASCII CHAR, filter out thing like ctrl+f
1348     //
1349     if (Char > 127 || Char < 32) {
1350       Status = StatusBarSetStatusString (L"Unknown Command");
1351     } else {
1352       Status = HBufferImageAddChar (Char);
1353     }
1354 
1355     break;
1356   }
1357 
1358   return Status;
1359 }
1360 
1361 /**
1362   Check user specified FileRow is above current screen.
1363 
1364   @param[in] FileRow  Row of file position ( start from 1 ).
1365 
1366   @retval TRUE   It is above the current screen.
1367   @retval FALSE  It is not above the current screen.
1368 
1369 **/
1370 BOOLEAN
1371 HAboveCurrentScreen (
1372   IN  UINTN FileRow
1373   )
1374 {
1375   if (FileRow < HBufferImage.LowVisibleRow) {
1376     return TRUE;
1377   }
1378 
1379   return FALSE;
1380 }
1381 
1382 /**
1383   Check user specified FileRow is under current screen.
1384 
1385   @param[in] FileRow    Row of file position ( start from 1 ).
1386 
1387   @retval TRUE      It is under the current screen.
1388   @retval FALSE     It is not under the current screen.
1389 
1390 **/
1391 BOOLEAN
1392 HUnderCurrentScreen (
1393   IN  UINTN FileRow
1394   )
1395 {
1396   if (FileRow > HBufferImage.LowVisibleRow + (HMainEditor.ScreenSize.Row - 2) - 1) {
1397     return TRUE;
1398   }
1399 
1400   return FALSE;
1401 }
1402 
1403 /**
1404   According to cursor's file position, adjust screen display.
1405 
1406   @param[in] NewFilePosRow    Row of file position ( start from 1 ).
1407   @param[in] NewFilePosCol    Column of file position ( start from 1 ).
1408   @param[in] HighBits         Cursor will on high4 bits or low4 bits.
1409 **/
1410 VOID
1411 HBufferImageMovePosition (
1412   IN UINTN    NewFilePosRow,
1413   IN UINTN    NewFilePosCol,
1414   IN BOOLEAN  HighBits
1415   )
1416 {
1417   INTN    RowGap;
1418   UINTN   Abs;
1419   BOOLEAN Above;
1420   BOOLEAN Under;
1421   UINTN   NewDisplayCol;
1422 
1423   //
1424   // CALCULATE gap between current file position and new file position
1425   //
1426   RowGap                = NewFilePosRow - HBufferImage.BufferPosition.Row;
1427 
1428   Under                 = HUnderCurrentScreen (NewFilePosRow);
1429   Above                 = HAboveCurrentScreen (NewFilePosRow);
1430 
1431   HBufferImage.HighBits = HighBits;
1432 
1433   //
1434   // if is below current screen
1435   //
1436   if (Under) {
1437     //
1438     // display row will be unchanged
1439     //
1440     HBufferImage.BufferPosition.Row = NewFilePosRow;
1441   } else {
1442     if (Above) {
1443       //
1444       // has enough above line, so display row unchanged
1445       // not has enough above lines, so the first line is
1446       // at the first display line
1447       //
1448       if (NewFilePosRow < (HBufferImage.DisplayPosition.Row - 2 + 1)) {
1449         HBufferImage.DisplayPosition.Row = NewFilePosRow + 2 - 1;
1450       }
1451 
1452       HBufferImage.BufferPosition.Row = NewFilePosRow;
1453     } else {
1454       //
1455       // in current screen
1456       //
1457       HBufferImage.BufferPosition.Row = NewFilePosRow;
1458       if (RowGap <= 0) {
1459         Abs = (UINTN)ABS(RowGap);
1460         HBufferImage.DisplayPosition.Row -= Abs;
1461       } else {
1462         HBufferImage.DisplayPosition.Row += RowGap;
1463       }
1464 
1465     }
1466   }
1467 
1468   HBufferImage.LowVisibleRow = HBufferImage.BufferPosition.Row - (HBufferImage.DisplayPosition.Row - 2);
1469 
1470   //
1471   // always in current screen
1472   //
1473   HBufferImage.BufferPosition.Column  = NewFilePosCol;
1474 
1475   NewDisplayCol                       = 10 + (NewFilePosCol - 1) * 3;
1476   if (NewFilePosCol > 0x8) {
1477     NewDisplayCol++;
1478   }
1479 
1480   if (!HighBits) {
1481     NewDisplayCol++;
1482   }
1483 
1484   HBufferImage.DisplayPosition.Column = NewDisplayCol;
1485 
1486   //
1487   // let CurrentLine point to correct line;
1488   //
1489   HBufferImage.CurrentLine = HMoveCurrentLine (RowGap);
1490 
1491 }
1492 
1493 /**
1494   Scroll cursor to right.
1495 
1496   @retval EFI_SUCCESS   The operation was successful.
1497 **/
1498 EFI_STATUS
1499 HBufferImageScrollRight (
1500   VOID
1501   )
1502 {
1503   HEFI_EDITOR_LINE  *Line;
1504   UINTN             FRow;
1505   UINTN             FCol;
1506 
1507   //
1508   // scroll right will always move to the high4 bits of the next character
1509   //
1510   HBufferImageNeedRefresh         = FALSE;
1511   HBufferImageOnlyLineNeedRefresh = FALSE;
1512 
1513   Line = HBufferImage.CurrentLine;
1514 
1515   FRow = HBufferImage.BufferPosition.Row;
1516   FCol = HBufferImage.BufferPosition.Column;
1517 
1518   //
1519   // this line is not full and no next line
1520   //
1521   if (FCol > Line->Size) {
1522     return EFI_SUCCESS;
1523   }
1524   //
1525   // if already at end of this line, scroll it to the start of next line
1526   //
1527   if (FCol == 0x10) {
1528     //
1529     // has next line
1530     //
1531     if (Line->Link.ForwardLink != HBufferImage.ListHead) {
1532       FRow++;
1533       FCol = 1;
1534 
1535     } else {
1536       return EFI_SUCCESS;
1537     }
1538   } else {
1539     //
1540     // if not at end of this line, just move to next column
1541     //
1542     FCol++;
1543 
1544   }
1545 
1546   HBufferImageMovePosition (FRow, FCol, TRUE);
1547 
1548   return EFI_SUCCESS;
1549 }
1550 
1551 /**
1552   Scroll cursor to left.
1553 
1554   @retval EFI_SUCCESS   The operation was successful.
1555 **/
1556 EFI_STATUS
1557 HBufferImageScrollLeft (
1558   VOID
1559   )
1560 {
1561 
1562   HEFI_EDITOR_LINE  *Line;
1563   UINTN             FRow;
1564   UINTN             FCol;
1565 
1566   HBufferImageNeedRefresh         = FALSE;
1567   HBufferImageOnlyLineNeedRefresh = FALSE;
1568 
1569   Line = HBufferImage.CurrentLine;
1570 
1571   FRow = HBufferImage.BufferPosition.Row;
1572   FCol = HBufferImage.BufferPosition.Column;
1573 
1574   //
1575   // if already at start of this line, so move to the end of previous line
1576   //
1577   if (FCol <= 1) {
1578     //
1579     // has previous line
1580     //
1581     if (Line->Link.BackLink != HBufferImage.ListHead) {
1582       FRow--;
1583       Line  = CR (Line->Link.BackLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
1584       FCol  = Line->Size;
1585     } else {
1586       return EFI_SUCCESS;
1587     }
1588   } else {
1589     //
1590     // if not at start of this line, just move to previous column
1591     //
1592     FCol--;
1593   }
1594 
1595   HBufferImageMovePosition (FRow, FCol, TRUE);
1596 
1597   return EFI_SUCCESS;
1598 }
1599 
1600 /**
1601   Scroll cursor to the next line
1602 
1603   @retval EFI_SUCCESS   The operation was successful.
1604 **/
1605 EFI_STATUS
1606 HBufferImageScrollDown (
1607   VOID
1608   )
1609 {
1610   HEFI_EDITOR_LINE  *Line;
1611   UINTN             FRow;
1612   UINTN             FCol;
1613   BOOLEAN           HighBits;
1614 
1615   Line      = HBufferImage.CurrentLine;
1616 
1617   FRow      = HBufferImage.BufferPosition.Row;
1618   FCol      = HBufferImage.BufferPosition.Column;
1619   HighBits  = HBufferImage.HighBits;
1620 
1621   //
1622   // has next line
1623   //
1624   if (Line->Link.ForwardLink != HBufferImage.ListHead) {
1625     FRow++;
1626     Line = CR (Line->Link.ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
1627 
1628     //
1629     // if the next line is not that long, so move to end of next line
1630     //
1631     if (FCol > Line->Size) {
1632       FCol      = Line->Size + 1;
1633       HighBits  = TRUE;
1634     }
1635 
1636   } else {
1637     return EFI_SUCCESS;
1638   }
1639 
1640   HBufferImageMovePosition (FRow, FCol, HighBits);
1641 
1642   return EFI_SUCCESS;
1643 }
1644 
1645 /**
1646   Scroll cursor to previous line
1647 
1648   @retval EFI_SUCCESS   The operation was successful.
1649 **/
1650 EFI_STATUS
1651 HBufferImageScrollUp (
1652   VOID
1653   )
1654 {
1655   HEFI_EDITOR_LINE  *Line;
1656   UINTN             FRow;
1657   UINTN             FCol;
1658 
1659   Line  = HBufferImage.CurrentLine;
1660 
1661   FRow  = HBufferImage.BufferPosition.Row;
1662   FCol  = HBufferImage.BufferPosition.Column;
1663 
1664   //
1665   // has previous line
1666   //
1667   if (Line->Link.BackLink != HBufferImage.ListHead) {
1668     FRow--;
1669 
1670   } else {
1671     return EFI_SUCCESS;
1672   }
1673 
1674   HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits);
1675 
1676   return EFI_SUCCESS;
1677 }
1678 
1679 /**
1680   Scroll cursor to next page
1681 
1682   @retval EFI_SUCCESS   The operation was successful.
1683 **/
1684 EFI_STATUS
1685 HBufferImagePageDown (
1686   VOID
1687   )
1688 {
1689   HEFI_EDITOR_LINE  *Line;
1690   UINTN             FRow;
1691   UINTN             FCol;
1692   UINTN             Gap;
1693   BOOLEAN           HighBits;
1694 
1695   Line      = HBufferImage.CurrentLine;
1696 
1697   FRow      = HBufferImage.BufferPosition.Row;
1698   FCol      = HBufferImage.BufferPosition.Column;
1699   HighBits  = HBufferImage.HighBits;
1700 
1701   //
1702   // has next page
1703   //
1704   if (HBufferImage.NumLines >= FRow + (HMainEditor.ScreenSize.Row - 2)) {
1705     Gap = (HMainEditor.ScreenSize.Row - 2);
1706   } else {
1707     //
1708     // MOVE CURSOR TO LAST LINE
1709     //
1710     Gap = HBufferImage.NumLines - FRow;
1711   }
1712   //
1713   // get correct line
1714   //
1715   Line = HMoveLine (Gap);
1716 
1717   //
1718   // if that line, is not that long, so move to the end of that line
1719   //
1720   if (Line != NULL && FCol > Line->Size) {
1721     FCol      = Line->Size + 1;
1722     HighBits  = TRUE;
1723   }
1724 
1725   FRow += Gap;
1726 
1727   HBufferImageMovePosition (FRow, FCol, HighBits);
1728 
1729   return EFI_SUCCESS;
1730 }
1731 
1732 /**
1733   Scroll cursor to previous page
1734 
1735   @retval EFI_SUCCESS   The operation was successful.
1736 **/
1737 EFI_STATUS
1738 HBufferImagePageUp (
1739   VOID
1740   )
1741 {
1742   UINTN             FRow;
1743   UINTN             FCol;
1744   UINTN             Gap;
1745   INTN              Retreat;
1746 
1747   FRow  = HBufferImage.BufferPosition.Row;
1748   FCol  = HBufferImage.BufferPosition.Column;
1749 
1750   //
1751   // has previous page
1752   //
1753   if (FRow > (HMainEditor.ScreenSize.Row - 2)) {
1754     Gap = (HMainEditor.ScreenSize.Row - 2);
1755   } else {
1756     //
1757     // the first line of file will displayed on the first line of screen
1758     //
1759     Gap = FRow - 1;
1760   }
1761 
1762   Retreat = Gap;
1763   Retreat = -Retreat;
1764 
1765   FRow -= Gap;
1766 
1767   HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits);
1768 
1769   return EFI_SUCCESS;
1770 }
1771 
1772 /**
1773   Scroll cursor to start of line
1774 
1775   @retval EFI_SUCCESS  The operation was successful.
1776 **/
1777 EFI_STATUS
1778 HBufferImageHome (
1779   VOID
1780   )
1781 {
1782   UINTN             FRow;
1783   UINTN             FCol;
1784   BOOLEAN           HighBits;
1785 
1786   //
1787   // curosr will at the high bit
1788   //
1789   FRow      = HBufferImage.BufferPosition.Row;
1790   FCol      = 1;
1791   HighBits  = TRUE;
1792 
1793   //
1794   // move cursor position
1795   //
1796   HBufferImageMovePosition (FRow, FCol, HighBits);
1797 
1798   return EFI_SUCCESS;
1799 }
1800 
1801 /**
1802   Scroll cursor to end of line.
1803 
1804   @retval EFI_SUCCESS  Teh operation was successful.
1805 **/
1806 EFI_STATUS
1807 HBufferImageEnd (
1808   VOID
1809   )
1810 {
1811   HEFI_EDITOR_LINE  *Line;
1812   UINTN             FRow;
1813   UINTN             FCol;
1814   BOOLEAN           HighBits;
1815 
1816   //
1817   // need refresh mouse
1818   //
1819   HBufferImageMouseNeedRefresh  = TRUE;
1820 
1821   Line                          = HBufferImage.CurrentLine;
1822 
1823   FRow                          = HBufferImage.BufferPosition.Row;
1824 
1825   if (Line->Size == 0x10) {
1826     FCol      = Line->Size;
1827     HighBits  = FALSE;
1828   } else {
1829     FCol      = Line->Size + 1;
1830     HighBits  = TRUE;
1831   }
1832   //
1833   // move cursor position
1834   //
1835   HBufferImageMovePosition (FRow, FCol, HighBits);
1836 
1837   return EFI_SUCCESS;
1838 }
1839 
1840 /**
1841   Get the size of the open buffer.
1842 
1843   @retval The size in bytes.
1844 **/
1845 UINTN
1846 HBufferImageGetTotalSize (
1847   VOID
1848   )
1849 {
1850   UINTN             Size;
1851 
1852   HEFI_EDITOR_LINE  *Line;
1853 
1854   //
1855   // calculate the total size of whole line list's buffer
1856   //
1857   if (HBufferImage.Lines == NULL) {
1858     return 0;
1859   }
1860 
1861   Line = CR (
1862           HBufferImage.ListHead->BackLink,
1863           HEFI_EDITOR_LINE,
1864           Link,
1865           EFI_EDITOR_LINE_LIST
1866           );
1867   //
1868   // one line at most 0x10
1869   //
1870   Size = 0x10 * (HBufferImage.NumLines - 1) + Line->Size;
1871 
1872   return Size;
1873 }
1874 
1875 /**
1876   Delete character from buffer.
1877 
1878   @param[in] Pos      Position, Pos starting from 0.
1879   @param[in] Count    The Count of characters to delete.
1880   @param[out] DeleteBuffer    The DeleteBuffer.
1881 
1882   @retval EFI_SUCCESS Success
1883 **/
1884 EFI_STATUS
1885 HBufferImageDeleteCharacterFromBuffer (
1886   IN  UINTN         Pos,
1887   IN  UINTN         Count,
1888   OUT UINT8         *DeleteBuffer
1889   )
1890 {
1891   UINTN             Index;
1892 
1893   VOID              *Buffer;
1894   UINT8             *BufferPtr;
1895   UINTN             Size;
1896 
1897   HEFI_EDITOR_LINE  *Line;
1898   LIST_ENTRY    *Link;
1899 
1900   UINTN             OldFCol;
1901   UINTN             OldFRow;
1902   UINTN             OldPos;
1903 
1904   UINTN             NewPos;
1905 
1906   EFI_STATUS        Status;
1907 
1908   Size      = HBufferImageGetTotalSize ();
1909 
1910   if (Size < Count) {
1911     return EFI_LOAD_ERROR;
1912   }
1913 
1914   if (Size == 0) {
1915     return EFI_SUCCESS;
1916   }
1917 
1918   //
1919   // relocate all the HBufferImage fields
1920   //
1921   OldFRow = HBufferImage.BufferPosition.Row;
1922   OldFCol = HBufferImage.BufferPosition.Column;
1923   OldPos  = (OldFRow - 1) * 0x10 + OldFCol - 1;
1924 
1925   if (Pos > 0) {
1926     //
1927     // has character before it,
1928     // so locate according to block's previous character
1929     //
1930     NewPos = Pos - 1;
1931 
1932   } else {
1933     //
1934     // has no character before it,
1935     // so locate according to block's next character
1936     //
1937     NewPos = 0;
1938   }
1939 
1940   HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE);
1941 
1942   Buffer = AllocateZeroPool (Size);
1943   if (Buffer == NULL) {
1944     return EFI_OUT_OF_RESOURCES;
1945   }
1946 
1947   HBufferImageListToBuffer (Buffer, Size);
1948 
1949   BufferPtr = (UINT8 *) Buffer;
1950 
1951   //
1952   // pass deleted buffer out
1953   //
1954   if (DeleteBuffer != NULL) {
1955     for (Index = 0; Index < Count; Index++) {
1956       DeleteBuffer[Index] = BufferPtr[Pos + Index];
1957     }
1958   }
1959   //
1960   // delete the part from Pos
1961   //
1962   for (Index = Pos; Index < Size - Count; Index++) {
1963     BufferPtr[Index] = BufferPtr[Index + Count];
1964   }
1965 
1966   Size -= Count;
1967 
1968   HBufferImageFreeLines ();
1969 
1970   Status = HBufferImageBufferToList (Buffer, Size);
1971   FreePool (Buffer);
1972 
1973   if (EFI_ERROR (Status)) {
1974     return Status;
1975   }
1976 
1977   Link = HMainEditor.BufferImage->ListHead->ForwardLink;
1978   for (Index = 0; Index < NewPos / 0x10; Index++) {
1979     Link = Link->ForwardLink;
1980   }
1981 
1982   Line                      = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
1983   HBufferImage.CurrentLine  = Line;
1984 
1985   //
1986   // if current cursor position if inside select area
1987   // then move it to the block's NEXT character
1988   //
1989   if (OldPos >= Pos && OldPos < (Pos + Count)) {
1990     NewPos = Pos;
1991   } else {
1992     if (OldPos < Pos) {
1993       NewPos = OldPos;
1994     } else {
1995       NewPos = OldPos - Count;
1996     }
1997   }
1998 
1999   HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE);
2000 
2001   return EFI_SUCCESS;
2002 }
2003 
2004 /**
2005   Add character to buffer, add before pos.
2006 
2007   @param[in] Pos        Position, Pos starting from 0.
2008   @param[in] Count      Count of characters to add.
2009   @param[in] AddBuffer  Add buffer.
2010 
2011   @retval EFI_SUCCESS   Success.
2012 **/
2013 EFI_STATUS
2014 HBufferImageAddCharacterToBuffer (
2015   IN  UINTN          Pos,
2016   IN  UINTN          Count,
2017   IN  UINT8          *AddBuffer
2018   )
2019 {
2020   INTN              Index;
2021 
2022   VOID              *Buffer;
2023   UINT8             *BufferPtr;
2024   UINTN             Size;
2025 
2026   HEFI_EDITOR_LINE  *Line;
2027 
2028   LIST_ENTRY    *Link;
2029 
2030   UINTN             OldFCol;
2031   UINTN             OldFRow;
2032   UINTN             OldPos;
2033 
2034   UINTN             NewPos;
2035 
2036   Size      = HBufferImageGetTotalSize ();
2037 
2038   //
2039   // relocate all the HBufferImage fields
2040   //
2041   OldFRow = HBufferImage.BufferPosition.Row;
2042   OldFCol = HBufferImage.BufferPosition.Column;
2043   OldPos  = (OldFRow - 1) * 0x10 + OldFCol - 1;
2044 
2045   //
2046   // move cursor before Pos
2047   //
2048   if (Pos > 0) {
2049     NewPos = Pos - 1;
2050   } else {
2051     NewPos = 0;
2052   }
2053 
2054   HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE);
2055 
2056   Buffer = AllocateZeroPool (Size + Count);
2057   if (Buffer == NULL) {
2058     return EFI_OUT_OF_RESOURCES;
2059   }
2060 
2061   HBufferImageListToBuffer (Buffer, Size);
2062 
2063   BufferPtr = (UINT8 *) Buffer;
2064 
2065   //
2066   // get a place to add
2067   //
2068   for (Index = (INTN) (Size + Count - 1); Index >= (INTN) Pos; Index--) {
2069     BufferPtr[Index] = BufferPtr[Index - Count];
2070   }
2071   //
2072   // add the buffer
2073   //
2074   for (Index = (INTN) 0; Index < (INTN) Count; Index++) {
2075     BufferPtr[Index + Pos] = AddBuffer[Index];
2076   }
2077 
2078   Size += Count;
2079 
2080   HBufferImageFreeLines ();
2081 
2082   HBufferImageBufferToList (Buffer, Size);
2083 
2084   FreePool (Buffer);
2085 
2086   Link = HMainEditor.BufferImage->ListHead->ForwardLink;
2087   for (Index = 0; Index < (INTN) NewPos / 0x10; Index++) {
2088     Link = Link->ForwardLink;
2089   }
2090 
2091   Line                      = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
2092   HBufferImage.CurrentLine  = Line;
2093 
2094   if (OldPos >= Pos) {
2095     NewPos = OldPos + Count;
2096   } else {
2097     NewPos = OldPos;
2098   }
2099 
2100   HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE);
2101 
2102   return EFI_SUCCESS;
2103 }
2104 
2105 /**
2106   Delete current character from line.
2107 
2108   @retval EFI_SUCCESS   The operationw as successful.
2109 **/
2110 EFI_STATUS
2111 HBufferImageDoDelete (
2112   VOID
2113   )
2114 {
2115 
2116   HEFI_EDITOR_LINE  *Line;
2117 
2118   BOOLEAN           LastLine;
2119   UINTN             FileColumn;
2120   UINTN             FPos;
2121 
2122   FPos        = (HBufferImage.BufferPosition.Row - 1) * 0x10 + HBufferImage.BufferPosition.Column - 1;
2123 
2124   FileColumn  = HBufferImage.BufferPosition.Column;
2125 
2126   Line        = HBufferImage.CurrentLine;
2127 
2128   //
2129   // if beyond the last character
2130   //
2131   if (FileColumn > Line->Size) {
2132     return EFI_SUCCESS;
2133   }
2134 
2135   LastLine = FALSE;
2136   if (Line->Link.ForwardLink == HBufferImage.ListHead) {
2137     LastLine = TRUE;
2138   }
2139 
2140   HBufferImageDeleteCharacterFromBuffer (FPos, 1, NULL);
2141 
2142   //
2143   // if is the last line
2144   // then only this line need to be refreshed
2145   //
2146   if (LastLine) {
2147     HBufferImageNeedRefresh         = FALSE;
2148     HBufferImageOnlyLineNeedRefresh = TRUE;
2149   } else {
2150     HBufferImageNeedRefresh         = TRUE;
2151     HBufferImageOnlyLineNeedRefresh = FALSE;
2152   }
2153 
2154   if (!HBufferImage.Modified) {
2155     HBufferImage.Modified = TRUE;
2156   }
2157 
2158   return EFI_SUCCESS;
2159 }
2160 
2161 /**
2162   Change the raw buffer to a list of lines for the UI.
2163 
2164   @param[in] Buffer   The pointer to the buffer to fill.
2165   @param[in] Bytes    The size of the buffer in bytes.
2166 
2167   @retval EFI_SUCCESS           The operation was successful.
2168   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
2169 **/
2170 EFI_STATUS
2171 HBufferImageBufferToList (
2172   IN VOID   *Buffer,
2173   IN UINTN  Bytes
2174   )
2175 {
2176   UINTN             TempI;
2177   UINTN             TempJ;
2178   UINTN             Left;
2179   HEFI_EDITOR_LINE  *Line;
2180   UINT8             *BufferPtr;
2181 
2182   TempI         = 0;
2183   Left      = 0;
2184   BufferPtr = (UINT8 *) Buffer;
2185 
2186   //
2187   // parse file content line by line
2188   //
2189   while (TempI < Bytes) {
2190     if (Bytes - TempI >= 0x10) {
2191       Left = 0x10;
2192     } else {
2193       Left = Bytes - TempI;
2194     }
2195 
2196     //
2197     // allocate a new line
2198     //
2199     Line = HBufferImageCreateLine ();
2200     if (Line == NULL) {
2201       return EFI_OUT_OF_RESOURCES;
2202     }
2203 
2204     Line->Size = Left;
2205 
2206     for (TempJ = 0; TempJ < Left; TempJ++) {
2207       Line->Buffer[TempJ] = BufferPtr[TempI];
2208       TempI++;
2209     }
2210 
2211   }
2212 
2213   //
2214   // last line is a full line, SO create a new line
2215   //
2216   if (Left == 0x10 || Bytes == 0) {
2217     Line = HBufferImageCreateLine ();
2218     if (Line == NULL) {
2219       return EFI_OUT_OF_RESOURCES;
2220     }
2221   }
2222 
2223   return EFI_SUCCESS;
2224 }
2225 
2226 /**
2227   Change the list of lines from the UI to a raw buffer.
2228 
2229   @param[in] Buffer   The pointer to the buffer to fill.
2230   @param[in] Bytes    The size of the buffer in bytes.
2231 
2232   @retval EFI_SUCCESS   The operation was successful.
2233 **/
2234 EFI_STATUS
2235 HBufferImageListToBuffer (
2236   IN VOID   *Buffer,
2237   IN UINTN  Bytes
2238   )
2239 {
2240   UINTN             Count;
2241   UINTN             Index;
2242   HEFI_EDITOR_LINE  *Line;
2243   LIST_ENTRY    *Link;
2244   UINT8             *BufferPtr;
2245 
2246   //
2247   // change the line list to a large buffer
2248   //
2249   if (HBufferImage.Lines == NULL) {
2250     return EFI_SUCCESS;
2251   }
2252 
2253   Link      = &HBufferImage.Lines->Link;
2254   Count     = 0;
2255   BufferPtr = (UINT8 *) Buffer;
2256 
2257   //
2258   // deal line by line
2259   //
2260   while (Link != HBufferImage.ListHead) {
2261 
2262     Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
2263 
2264     //@todo shouldn't this be an error???
2265     if (Count + Line->Size > Bytes) {
2266       return EFI_SUCCESS;
2267     }
2268 
2269     for (Index = 0; Index < Line->Size; Index++) {
2270       BufferPtr[Index] = Line->Buffer[Index];
2271     }
2272 
2273     Count += Line->Size;
2274     BufferPtr += Line->Size;
2275 
2276     Link = Link->ForwardLink;
2277   }
2278 
2279   return EFI_SUCCESS;
2280 }
2281 
2282 /**
2283   Move the mouse in the image buffer.
2284 
2285   @param[in] TextX    The x-coordinate.
2286   @param[in] TextY    The y-coordinate.
2287 **/
2288 VOID
2289 HBufferImageAdjustMousePosition (
2290   IN INT32 TextX,
2291   IN INT32 TextY
2292   )
2293 {
2294   UINTN TempX;
2295   UINTN TempY;
2296   UINTN AbsX;
2297   UINTN AbsY;
2298 
2299   //
2300   // TextX and TextY is mouse movement data returned by mouse driver
2301   // This function will change it to MousePosition
2302   //
2303   //
2304   // get absolute TempX value
2305   //
2306   if (TextX >= 0) {
2307     AbsX = TextX;
2308   } else {
2309     AbsX = -TextX;
2310   }
2311   //
2312   // get absolute TempY value
2313   //
2314   if (TextY >= 0) {
2315     AbsY = TextY;
2316   } else {
2317     AbsY = -TextY;
2318   }
2319 
2320   TempX = HBufferImage.MousePosition.Column;
2321   TempY = HBufferImage.MousePosition.Row;
2322 
2323   if (TextX >= 0) {
2324     TempX += TextX;
2325   } else {
2326     if (TempX >= AbsX) {
2327       TempX -= AbsX;
2328     } else {
2329       TempX = 0;
2330     }
2331   }
2332 
2333   if (TextY >= 0) {
2334     TempY += TextY;
2335   } else {
2336     if (TempY >= AbsY) {
2337       TempY -= AbsY;
2338     } else {
2339       TempY = 0;
2340     }
2341   }
2342   //
2343   // check whether new mouse column position is beyond screen
2344   // if not, adjust it
2345   //
2346   if (TempX >= 10 && TempX <= (10 + 0x10 * 3 - 1)) {
2347     HBufferImage.MousePosition.Column = TempX;
2348   } else if (TempX < 10) {
2349     HBufferImage.MousePosition.Column = 10;
2350   } else if (TempX > (10 + 0x10 * 3 - 1)) {
2351     HBufferImage.MousePosition.Column = 10 + 0x10 * 3 - 1;
2352   }
2353   //
2354   // check whether new mouse row position is beyond screen
2355   // if not, adjust it
2356   //
2357   if (TempY >= 2 && TempY <= (HMainEditor.ScreenSize.Row - 1)) {
2358     HBufferImage.MousePosition.Row = TempY;
2359   } else if (TempY < 2) {
2360     HBufferImage.MousePosition.Row = 2;
2361   } else if (TempY > (HMainEditor.ScreenSize.Row - 1)) {
2362     HBufferImage.MousePosition.Row = (HMainEditor.ScreenSize.Row - 1);
2363   }
2364 
2365 }
2366 
2367 /**
2368   Dispatch input to different handler
2369 
2370   @param[in] Key    The input key:
2371                      the keys can be:
2372                        ASCII KEY
2373                         Backspace/Delete
2374                         Direction key: up/down/left/right/pgup/pgdn
2375                         Home/End
2376                         INS
2377 
2378   @retval EFI_SUCCESS           The operation was successful.
2379   @retval EFI_LOAD_ERROR        A load error occurred.
2380   @retval EFI_OUT_OF_RESOURCES  A Memory allocation failed.
2381 **/
2382 EFI_STATUS
2383 HBufferImageHandleInput (
2384   IN  EFI_INPUT_KEY *Key
2385   )
2386 {
2387   EFI_STATUS  Status;
2388 
2389   Status = EFI_SUCCESS;
2390 
2391   switch (Key->ScanCode) {
2392   //
2393   // ordinary key
2394   //
2395   case SCAN_NULL:
2396     Status = HBufferImageDoCharInput (Key->UnicodeChar);
2397     break;
2398 
2399   //
2400   // up arrow
2401   //
2402   case SCAN_UP:
2403     Status = HBufferImageScrollUp ();
2404     break;
2405 
2406   //
2407   // down arrow
2408   //
2409   case SCAN_DOWN:
2410     Status = HBufferImageScrollDown ();
2411     break;
2412 
2413   //
2414   // right arrow
2415   //
2416   case SCAN_RIGHT:
2417     Status = HBufferImageScrollRight ();
2418     break;
2419 
2420   //
2421   // left arrow
2422   //
2423   case SCAN_LEFT:
2424     Status = HBufferImageScrollLeft ();
2425     break;
2426 
2427   //
2428   // page up
2429   //
2430   case SCAN_PAGE_UP:
2431     Status = HBufferImagePageUp ();
2432     break;
2433 
2434   //
2435   // page down
2436   //
2437   case SCAN_PAGE_DOWN:
2438     Status = HBufferImagePageDown ();
2439     break;
2440 
2441   //
2442   // delete
2443   //
2444   case SCAN_DELETE:
2445     Status = HBufferImageDoDelete ();
2446     break;
2447 
2448   //
2449   // home
2450   //
2451   case SCAN_HOME:
2452     Status = HBufferImageHome ();
2453     break;
2454 
2455   //
2456   // end
2457   //
2458   case SCAN_END:
2459     Status = HBufferImageEnd ();
2460     break;
2461 
2462   default:
2463     Status = StatusBarSetStatusString (L"Unknown Command");
2464     break;
2465   }
2466 
2467   return Status;
2468 }
2469 
2470