| /** @file | |
| Defines HBufferImage - the view of the file that is visible at any point, | |
| as well as the event handlers for editing the file | |
| Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "HexEditor.h" | |
| extern EFI_HANDLE HImageHandleBackup; | |
| extern HEFI_EDITOR_FILE_IMAGE HFileImage; | |
| extern HEFI_EDITOR_DISK_IMAGE HDiskImage; | |
| extern HEFI_EDITOR_MEM_IMAGE HMemImage; | |
| extern HEFI_EDITOR_FILE_IMAGE HFileImageBackupVar; | |
| extern HEFI_EDITOR_DISK_IMAGE HDiskImageBackupVar; | |
| extern HEFI_EDITOR_MEM_IMAGE HMemImageBackupVar; | |
| extern BOOLEAN HEditorMouseAction; | |
| extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; | |
| extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditorBackupVar; | |
| HEFI_EDITOR_BUFFER_IMAGE HBufferImage; | |
| HEFI_EDITOR_BUFFER_IMAGE HBufferImageBackupVar; | |
| // | |
| // for basic initialization of HBufferImage | |
| // | |
| HEFI_EDITOR_BUFFER_IMAGE HBufferImageConst = { | |
| NULL, | |
| NULL, | |
| 0, | |
| NULL, | |
| { | |
| 0, | |
| 0 | |
| }, | |
| { | |
| 0, | |
| 0 | |
| }, | |
| { | |
| 0, | |
| 0 | |
| }, | |
| 0, | |
| TRUE, | |
| FALSE, | |
| FileTypeNone, | |
| NULL, | |
| NULL, | |
| NULL | |
| }; | |
| // | |
| // the whole edit area needs to be refreshed | |
| // | |
| BOOLEAN HBufferImageNeedRefresh; | |
| // | |
| // only the current line in edit area needs to be refresh | |
| // | |
| BOOLEAN HBufferImageOnlyLineNeedRefresh; | |
| BOOLEAN HBufferImageMouseNeedRefresh; | |
| /** | |
| Initialization function for HBufferImage | |
| @retval EFI_SUCCESS The operation was successful. | |
| @retval EFI_LOAD_ERROR A load error occured. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageInit ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // basically initialize the HBufferImage | |
| // | |
| CopyMem (&HBufferImage, &HBufferImageConst, sizeof (HBufferImage)); | |
| // | |
| // INIT listhead | |
| // | |
| HBufferImage.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY)); | |
| if (HBufferImage.ListHead == NULL) { | |
| return EFI_LOAD_ERROR; | |
| } | |
| InitializeListHead (HBufferImage.ListHead); | |
| HBufferImage.DisplayPosition.Row = 2; | |
| HBufferImage.DisplayPosition.Column = 10; | |
| HBufferImage.MousePosition.Row = 2; | |
| HBufferImage.MousePosition.Column = 10; | |
| HBufferImage.FileImage = &HFileImage; | |
| HBufferImage.DiskImage = &HDiskImage; | |
| HBufferImage.MemImage = &HMemImage; | |
| HBufferImageNeedRefresh = FALSE; | |
| HBufferImageOnlyLineNeedRefresh = FALSE; | |
| HBufferImageMouseNeedRefresh = FALSE; | |
| HBufferImageBackupVar.FileImage = &HFileImageBackupVar; | |
| HBufferImageBackupVar.DiskImage = &HDiskImageBackupVar; | |
| HBufferImageBackupVar.MemImage = &HMemImageBackupVar; | |
| Status = HFileImageInit (); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_LOAD_ERROR; | |
| } | |
| Status = HDiskImageInit (); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_LOAD_ERROR; | |
| } | |
| Status = HMemImageInit (); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_LOAD_ERROR; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Backup function for HBufferImage. Only a few fields need to be backup. | |
| This is for making the file buffer refresh as few as possible. | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageBackup ( | |
| VOID | |
| ) | |
| { | |
| HBufferImageBackupVar.MousePosition = HBufferImage.MousePosition; | |
| HBufferImageBackupVar.BufferPosition = HBufferImage.BufferPosition; | |
| HBufferImageBackupVar.Modified = HBufferImage.Modified; | |
| HBufferImageBackupVar.BufferType = HBufferImage.BufferType; | |
| HBufferImageBackupVar.LowVisibleRow = HBufferImage.LowVisibleRow; | |
| HBufferImageBackupVar.HighBits = HBufferImage.HighBits; | |
| // | |
| // three kinds of buffer supported | |
| // file buffer | |
| // disk buffer | |
| // memory buffer | |
| // | |
| switch (HBufferImage.BufferType) { | |
| case FileTypeFileBuffer: | |
| HFileImageBackup (); | |
| break; | |
| case FileTypeDiskBuffer: | |
| HDiskImageBackup (); | |
| break; | |
| case FileTypeMemBuffer: | |
| HMemImageBackup (); | |
| break; | |
| default: | |
| break; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Free all the lines in HBufferImage. | |
| Fields affected: | |
| Lines | |
| CurrentLine | |
| NumLines | |
| ListHead | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageFreeLines ( | |
| VOID | |
| ) | |
| { | |
| HFreeLines (HBufferImage.ListHead, HBufferImage.Lines); | |
| HBufferImage.Lines = NULL; | |
| HBufferImage.CurrentLine = NULL; | |
| HBufferImage.NumLines = 0; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Cleanup function for HBufferImage | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageCleanup ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // free all the lines | |
| // | |
| Status = HBufferImageFreeLines (); | |
| SHELL_FREE_NON_NULL (HBufferImage.ListHead); | |
| HBufferImage.ListHead = NULL; | |
| HFileImageCleanup (); | |
| HDiskImageCleanup (); | |
| return Status; | |
| } | |
| /** | |
| Print Line on Row | |
| @param[in] Line The lline to print. | |
| @param[in] Row The row on screen ( begin from 1 ). | |
| @param[in] FRow The FRow. | |
| @param[in] Orig The original color. | |
| @param[in] New The color to print with. | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImagePrintLine ( | |
| IN HEFI_EDITOR_LINE *Line, | |
| IN UINTN Row, | |
| IN UINTN FRow, | |
| IN HEFI_EDITOR_COLOR_UNION Orig, | |
| IN HEFI_EDITOR_COLOR_UNION New | |
| ) | |
| { | |
| UINTN Index; | |
| UINTN Pos; | |
| BOOLEAN Selected; | |
| BOOLEAN BeNewColor; | |
| UINTN RowStart; | |
| UINTN RowEnd; | |
| UINTN ColStart; | |
| UINTN ColEnd; | |
| // | |
| // variable initialization | |
| // | |
| ColStart = 0; | |
| ColEnd = 0; | |
| Selected = FALSE; | |
| // | |
| // print the selected area in opposite color | |
| // | |
| if (HMainEditor.SelectStart != 0 && HMainEditor.SelectEnd != 0) { | |
| RowStart = (HMainEditor.SelectStart - 1) / 0x10 + 1; | |
| RowEnd = (HMainEditor.SelectEnd - 1) / 0x10 + 1; | |
| ColStart = (HMainEditor.SelectStart - 1) % 0x10 + 1; | |
| ColEnd = (HMainEditor.SelectEnd - 1) % 0x10 + 1; | |
| if (FRow >= RowStart && FRow <= RowEnd) { | |
| Selected = TRUE; | |
| } | |
| if (FRow > RowStart) { | |
| ColStart = 1; | |
| } | |
| if (FRow < RowEnd) { | |
| ColEnd = 0x10; | |
| } | |
| } | |
| if (!HEditorMouseAction) { | |
| ShellPrintEx ( | |
| 0, | |
| (INT32)Row - 1, | |
| L"%8X ", | |
| ((INT32)Row - 2 + HBufferImage.LowVisibleRow - 1) * 0x10 | |
| ); | |
| } | |
| for (Index = 0; Index < 0x08 && Index < Line->Size; Index++) { | |
| BeNewColor = FALSE; | |
| if (Selected) { | |
| if (Index + 1 >= ColStart && Index + 1 <= ColEnd) { | |
| BeNewColor = TRUE; | |
| } | |
| } | |
| if (BeNewColor) { | |
| gST->ConOut->SetAttribute (gST->ConOut, New.Data); | |
| } else { | |
| gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); | |
| } | |
| Pos = 10 + (Index * 3); | |
| if (Line->Buffer[Index] < 0x10) { | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"0"); | |
| Pos++; | |
| } | |
| if (Index < 0x07) { | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]); | |
| } else { | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]); | |
| } | |
| } | |
| gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); | |
| while (Index < 0x08) { | |
| Pos = 10 + (Index * 3); | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); | |
| Index++; | |
| } | |
| while (Index < 0x10 && Index < Line->Size) { | |
| BeNewColor = FALSE; | |
| if (Selected) { | |
| if (Index + 1 >= ColStart && Index + 1 <= ColEnd) { | |
| BeNewColor = TRUE; | |
| } | |
| } | |
| if (BeNewColor) { | |
| gST->ConOut->SetAttribute (gST->ConOut, New.Data); | |
| } else { | |
| gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); | |
| } | |
| Pos = 10 + (Index * 3) + 1; | |
| if (Line->Buffer[Index] < 0x10) { | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"0"); | |
| Pos++; | |
| } | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]); | |
| Index++; | |
| } | |
| gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); | |
| while (Index < 0x10) { | |
| Pos = 10 + (Index * 3) + 1; | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); | |
| Index++; | |
| } | |
| // | |
| // restore the original color | |
| // | |
| gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); | |
| // | |
| // PRINT the buffer content | |
| // | |
| if (!HEditorMouseAction) { | |
| for (Index = 0; Index < 0x10 && Index < Line->Size; Index++) { | |
| Pos = ASCII_POSITION + Index; | |
| // | |
| // learned from shelle.h -- IsValidChar | |
| // | |
| if (Line->Buffer[Index] >= L' ') { | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%c", (CHAR16) Line->Buffer[Index]); | |
| } else { | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%c", '.'); | |
| } | |
| } | |
| while (Index < 0x10) { | |
| Pos = ASCII_POSITION + Index; | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); | |
| Index++; | |
| } | |
| } | |
| // | |
| // restore the abundant blank in hex edit area to original color | |
| // | |
| if (Selected) { | |
| if (ColEnd <= 7) { | |
| Pos = 10 + (ColEnd - 1) * 3 + 2; | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); | |
| } else if (ColEnd == 8) { | |
| Pos = 10 + (ColEnd - 1) * 3 + 2; | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); | |
| } else { | |
| Pos = 10 + (ColEnd - 1) * 3 + 3; | |
| ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Function to decide if a column number is stored in the high bits. | |
| @param[in] Column The column to examine. | |
| @param[out] FCol The actual column number. | |
| @retval TRUE The actual column was in high bits and is now in FCol. | |
| @retval FALSE There was not a column number in the high bits. | |
| **/ | |
| BOOLEAN | |
| HBufferImageIsAtHighBits ( | |
| IN UINTN Column, | |
| OUT UINTN *FCol | |
| ) | |
| { | |
| Column -= 10; | |
| // | |
| // NOW AFTER THE SUB, Column start from 0 | |
| // 23 AND 24 ARE BOTH BLANK | |
| // | |
| if (Column == 24) { | |
| *FCol = 0; | |
| return FALSE; | |
| } | |
| if (Column > 24) { | |
| Column--; | |
| } | |
| *FCol = (Column / 3) + 1; | |
| if (Column % 3 == 0) { | |
| return TRUE; | |
| } | |
| if ((Column % 3 == 2)) { | |
| *FCol = 0; | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Decide if a point is in the already selected area. | |
| @param[in] MouseRow The row of the point to test. | |
| @param[in] MouseCol The col of the point to test. | |
| @retval TRUE The point is in the selected area. | |
| @retval FALSE The point is not in the selected area. | |
| **/ | |
| BOOLEAN | |
| HBufferImageIsInSelectedArea ( | |
| IN UINTN MouseRow, | |
| IN UINTN MouseCol | |
| ) | |
| { | |
| UINTN FRow; | |
| UINTN RowStart; | |
| UINTN RowEnd; | |
| UINTN ColStart; | |
| UINTN ColEnd; | |
| UINTN MouseColStart; | |
| UINTN MouseColEnd; | |
| // | |
| // judge mouse position whether is in selected area | |
| // | |
| // | |
| // not select | |
| // | |
| if (HMainEditor.SelectStart == 0 || HMainEditor.SelectEnd == 0) { | |
| return FALSE; | |
| } | |
| // | |
| // calculate the select area | |
| // | |
| RowStart = (HMainEditor.SelectStart - 1) / 0x10 + 1; | |
| RowEnd = (HMainEditor.SelectEnd - 1) / 0x10 + 1; | |
| ColStart = (HMainEditor.SelectStart - 1) % 0x10 + 1; | |
| ColEnd = (HMainEditor.SelectEnd - 1) % 0x10 + 1; | |
| FRow = HBufferImage.LowVisibleRow + MouseRow - 2; | |
| if (FRow < RowStart || FRow > RowEnd) { | |
| return FALSE; | |
| } | |
| if (FRow > RowStart) { | |
| ColStart = 1; | |
| } | |
| if (FRow < RowEnd) { | |
| ColEnd = 0x10; | |
| } | |
| MouseColStart = 10 + (ColStart - 1) * 3; | |
| if (ColStart > 8) { | |
| MouseColStart++; | |
| } | |
| MouseColEnd = 10 + (ColEnd - 1) * 3 + 1; | |
| if (ColEnd > 8) { | |
| MouseColEnd++; | |
| } | |
| if (MouseCol < MouseColStart || MouseCol > MouseColEnd) { | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| /** | |
| Set mouse position according to HBufferImage.MousePosition. | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageRestoreMousePosition ( | |
| VOID | |
| ) | |
| { | |
| HEFI_EDITOR_COLOR_UNION Orig; | |
| HEFI_EDITOR_COLOR_UNION New; | |
| UINTN FRow; | |
| UINTN FColumn; | |
| BOOLEAN HasCharacter; | |
| HEFI_EDITOR_LINE *CurrentLine; | |
| HEFI_EDITOR_LINE *Line; | |
| UINT8 Value; | |
| BOOLEAN HighBits; | |
| Line = NULL; | |
| if (HMainEditor.MouseSupported) { | |
| if (HBufferImageMouseNeedRefresh) { | |
| HBufferImageMouseNeedRefresh = FALSE; | |
| // | |
| // if mouse position not moved and only mouse action | |
| // so do not need to refresh mouse position | |
| // | |
| if (( | |
| HBufferImage.MousePosition.Row == HBufferImageBackupVar.MousePosition.Row && | |
| HBufferImage.MousePosition.Column == HBufferImageBackupVar.MousePosition.Column | |
| ) && | |
| HEditorMouseAction | |
| ) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // backup the old screen attributes | |
| // | |
| Orig = HMainEditor.ColorAttributes; | |
| New.Data = 0; | |
| New.Colors.Foreground = Orig.Colors.Background; | |
| New.Colors.Background = Orig.Colors.Foreground; | |
| // | |
| // if in selected area, | |
| // so do not need to refresh mouse | |
| // | |
| if (!HBufferImageIsInSelectedArea ( | |
| HBufferImageBackupVar.MousePosition.Row, | |
| HBufferImageBackupVar.MousePosition.Column | |
| )) { | |
| gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); | |
| } else { | |
| gST->ConOut->SetAttribute (gST->ConOut, New.Data); | |
| } | |
| // | |
| // clear the old mouse position | |
| // | |
| FRow = HBufferImage.LowVisibleRow + HBufferImageBackupVar.MousePosition.Row - 2; | |
| HighBits = HBufferImageIsAtHighBits ( | |
| HBufferImageBackupVar.MousePosition.Column, | |
| &FColumn | |
| ); | |
| HasCharacter = TRUE; | |
| if (FRow > HBufferImage.NumLines || FColumn == 0) { | |
| HasCharacter = FALSE; | |
| } else { | |
| CurrentLine = HBufferImage.CurrentLine; | |
| Line = HMoveLine (FRow - HBufferImage.BufferPosition.Row); | |
| if (Line == NULL || FColumn > Line->Size) { | |
| HasCharacter = FALSE; | |
| } | |
| HBufferImage.CurrentLine = CurrentLine; | |
| } | |
| ShellPrintEx ( | |
| (INT32)HBufferImageBackupVar.MousePosition.Column - 1, | |
| (INT32)HBufferImageBackupVar.MousePosition.Row - 1, | |
| L" " | |
| ); | |
| if (HasCharacter) { | |
| if (HighBits) { | |
| Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf0); | |
| Value = (UINT8) (Value >> 4); | |
| } else { | |
| Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf); | |
| } | |
| ShellPrintEx ( | |
| (INT32)HBufferImageBackupVar.MousePosition.Column - 1, | |
| (INT32)HBufferImageBackupVar.MousePosition.Row - 1, | |
| L"%x", | |
| Value | |
| ); | |
| } | |
| if (!HBufferImageIsInSelectedArea ( | |
| HBufferImage.MousePosition.Row, | |
| HBufferImage.MousePosition.Column | |
| )) { | |
| gST->ConOut->SetAttribute (gST->ConOut, New.Data); | |
| } else { | |
| gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); | |
| } | |
| // | |
| // clear the old mouse position | |
| // | |
| FRow = HBufferImage.LowVisibleRow + HBufferImage.MousePosition.Row - 2; | |
| HighBits = HBufferImageIsAtHighBits ( | |
| HBufferImage.MousePosition.Column, | |
| &FColumn | |
| ); | |
| HasCharacter = TRUE; | |
| if (FRow > HBufferImage.NumLines || FColumn == 0) { | |
| HasCharacter = FALSE; | |
| } else { | |
| CurrentLine = HBufferImage.CurrentLine; | |
| Line = HMoveLine (FRow - HBufferImage.BufferPosition.Row); | |
| if (Line == NULL || FColumn > Line->Size) { | |
| HasCharacter = FALSE; | |
| } | |
| HBufferImage.CurrentLine = CurrentLine; | |
| } | |
| ShellPrintEx ( | |
| (INT32)HBufferImage.MousePosition.Column - 1, | |
| (INT32)HBufferImage.MousePosition.Row - 1, | |
| L" " | |
| ); | |
| if (HasCharacter) { | |
| if (HighBits) { | |
| Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf0); | |
| Value = (UINT8) (Value >> 4); | |
| } else { | |
| Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf); | |
| } | |
| ShellPrintEx ( | |
| (INT32)HBufferImage.MousePosition.Column - 1, | |
| (INT32)HBufferImage.MousePosition.Row - 1, | |
| L"%x", | |
| Value | |
| ); | |
| } | |
| // | |
| // end of HasCharacter | |
| // | |
| gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); | |
| } | |
| // | |
| // end of MouseNeedRefresh | |
| // | |
| } | |
| // | |
| // end of MouseSupported | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Set cursor position according to HBufferImage.DisplayPosition. | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageRestorePosition ( | |
| VOID | |
| ) | |
| { | |
| // | |
| // set cursor position | |
| // | |
| gST->ConOut->SetCursorPosition ( | |
| gST->ConOut, | |
| HBufferImage.DisplayPosition.Column - 1, | |
| HBufferImage.DisplayPosition.Row - 1 | |
| ); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Refresh function for HBufferImage. | |
| @retval EFI_SUCCESS The operation was successful. | |
| @retval EFI_LOAD_ERROR A Load error occured. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageRefresh ( | |
| VOID | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| HEFI_EDITOR_LINE *Line; | |
| UINTN Row; | |
| HEFI_EDITOR_COLOR_UNION Orig; | |
| HEFI_EDITOR_COLOR_UNION New; | |
| UINTN StartRow; | |
| UINTN EndRow; | |
| UINTN FStartRow; | |
| UINTN Tmp; | |
| Orig = HMainEditor.ColorAttributes; | |
| New.Data = 0; | |
| New.Colors.Foreground = Orig.Colors.Background; | |
| New.Colors.Background = Orig.Colors.Foreground; | |
| // | |
| // if it's the first time after editor launch, so should refresh | |
| // | |
| if (HEditorFirst == FALSE) { | |
| // | |
| // no definite required refresh | |
| // and file position displayed on screen has not been changed | |
| // | |
| if (!HBufferImageNeedRefresh && | |
| !HBufferImageOnlyLineNeedRefresh && | |
| HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow | |
| ) { | |
| HBufferImageRestoreMousePosition (); | |
| HBufferImageRestorePosition (); | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| gST->ConOut->EnableCursor (gST->ConOut, FALSE); | |
| // | |
| // only need to refresh current line | |
| // | |
| if (HBufferImageOnlyLineNeedRefresh && HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow) { | |
| HBufferImagePrintLine ( | |
| HBufferImage.CurrentLine, | |
| HBufferImage.DisplayPosition.Row, | |
| HBufferImage.BufferPosition.Row, | |
| Orig, | |
| New | |
| ); | |
| } else { | |
| // | |
| // the whole edit area need refresh | |
| // | |
| if (HEditorMouseAction && HMainEditor.SelectStart != 0 && HMainEditor.SelectEnd != 0) { | |
| if (HMainEditor.SelectStart != HMainEditorBackupVar.SelectStart) { | |
| if (HMainEditor.SelectStart >= HMainEditorBackupVar.SelectStart && HMainEditorBackupVar.SelectStart != 0) { | |
| StartRow = (HMainEditorBackupVar.SelectStart - 1) / 0x10 + 1; | |
| } else { | |
| StartRow = (HMainEditor.SelectStart - 1) / 0x10 + 1; | |
| } | |
| } else { | |
| StartRow = (HMainEditor.SelectStart - 1) / 0x10 + 1; | |
| } | |
| if (HMainEditor.SelectEnd <= HMainEditorBackupVar.SelectEnd) { | |
| EndRow = (HMainEditorBackupVar.SelectEnd - 1) / 0x10 + 1; | |
| } else { | |
| EndRow = (HMainEditor.SelectEnd - 1) / 0x10 + 1; | |
| } | |
| // | |
| // swap | |
| // | |
| if (StartRow > EndRow) { | |
| Tmp = StartRow; | |
| StartRow = EndRow; | |
| EndRow = Tmp; | |
| } | |
| FStartRow = StartRow; | |
| StartRow = 2 + StartRow - HBufferImage.LowVisibleRow; | |
| EndRow = 2 + EndRow - HBufferImage.LowVisibleRow; | |
| } else { | |
| // | |
| // not mouse selection actions | |
| // | |
| FStartRow = HBufferImage.LowVisibleRow; | |
| StartRow = 2; | |
| EndRow = (HMainEditor.ScreenSize.Row - 1); | |
| } | |
| // | |
| // no line | |
| // | |
| if (HBufferImage.Lines == NULL) { | |
| HBufferImageRestoreMousePosition (); | |
| HBufferImageRestorePosition (); | |
| gST->ConOut->EnableCursor (gST->ConOut, TRUE); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // get the first line that will be displayed | |
| // | |
| Line = HMoveLine (FStartRow - HBufferImage.BufferPosition.Row); | |
| if (Line == NULL) { | |
| gST->ConOut->EnableCursor (gST->ConOut, TRUE); | |
| return EFI_LOAD_ERROR; | |
| } | |
| Link = &(Line->Link); | |
| Row = StartRow; | |
| do { | |
| Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); | |
| // | |
| // print line at row | |
| // | |
| HBufferImagePrintLine ( | |
| Line, | |
| Row, | |
| HBufferImage.LowVisibleRow + Row - 2, | |
| Orig, | |
| New | |
| ); | |
| Link = Link->ForwardLink; | |
| Row++; | |
| } while (Link != HBufferImage.ListHead && Row <= EndRow); | |
| while (Row <= EndRow) { | |
| EditorClearLine (Row, HMainEditor.ScreenSize.Column, HMainEditor.ScreenSize.Row); | |
| Row++; | |
| } | |
| // | |
| // while not file end and not screen full | |
| // | |
| } | |
| HBufferImageRestoreMousePosition (); | |
| HBufferImageRestorePosition (); | |
| HBufferImageNeedRefresh = FALSE; | |
| HBufferImageOnlyLineNeedRefresh = FALSE; | |
| gST->ConOut->EnableCursor (gST->ConOut, TRUE); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Read an image into a buffer friom a source. | |
| @param[in] FileName Pointer to the file name. OPTIONAL and ignored if not FileTypeFileBuffer. | |
| @param[in] DiskName Pointer to the disk name. OPTIONAL and ignored if not FileTypeDiskBuffer. | |
| @param[in] DiskOffset Offset into the disk. OPTIONAL and ignored if not FileTypeDiskBuffer. | |
| @param[in] DiskSize Size of the disk buffer. OPTIONAL and ignored if not FileTypeDiskBuffer. | |
| @param[in] MemOffset Offset into the Memory. OPTIONAL and ignored if not FileTypeMemBuffer. | |
| @param[in] MemSize Size of the Memory buffer. OPTIONAL and ignored if not FileTypeMemBuffer. | |
| @param[in] BufferType The type of buffer to save. IGNORED. | |
| @param[in] Recover TRUE for recovermode, FALSE otherwise. | |
| @return EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HBufferImageRead ( | |
| IN CONST CHAR16 *FileName, | |
| IN CONST CHAR16 *DiskName, | |
| IN UINTN DiskOffset, | |
| IN UINTN DiskSize, | |
| IN UINTN MemOffset, | |
| IN UINTN MemSize, | |
| IN EDIT_FILE_TYPE BufferType, | |
| IN BOOLEAN Recover | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EDIT_FILE_TYPE BufferTypeBackup; | |
| // | |
| // variable initialization | |
| // | |
| Status = EFI_SUCCESS; | |
| HBufferImage.BufferType = BufferType; | |
| // | |
| // three types of buffer supported | |
| // file buffer | |
| // disk buffer | |
| // memory buffer | |
| // | |
| BufferTypeBackup = HBufferImage.BufferType; | |
| switch (BufferType) { | |
| case FileTypeFileBuffer: | |
| Status = HFileImageRead (FileName, Recover); | |
| break; | |
| case FileTypeDiskBuffer: | |
| Status = HDiskImageRead (DiskName, DiskOffset, DiskSize, Recover); | |
| break; | |
| case FileTypeMemBuffer: | |
| Status = HMemImageRead (MemOffset, MemSize, Recover); | |
| break; | |
| default: | |
| Status = EFI_NOT_FOUND; | |
| break; | |
| } | |
| if (EFI_ERROR (Status)) { | |
| HBufferImage.BufferType = BufferTypeBackup; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Save the current image. | |
| @param[in] FileName Pointer to the file name. OPTIONAL and ignored if not FileTypeFileBuffer. | |
| @param[in] DiskName Pointer to the disk name. OPTIONAL and ignored if not FileTypeDiskBuffer. | |
| @param[in] DiskOffset Offset into the disk. OPTIONAL and ignored if not FileTypeDiskBuffer. | |
| @param[in] DiskSize Size of the disk buffer. OPTIONAL and ignored if not FileTypeDiskBuffer. | |
| @param[in] MemOffset Offset into the Memory. OPTIONAL and ignored if not FileTypeMemBuffer. | |
| @param[in] MemSize Size of the Memory buffer. OPTIONAL and ignored if not FileTypeMemBuffer. | |
| @param[in] BufferType The type of buffer to save. IGNORED. | |
| @return EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageSave ( | |
| IN CHAR16 *FileName, | |
| IN CHAR16 *DiskName, | |
| IN UINTN DiskOffset, | |
| IN UINTN DiskSize, | |
| IN UINTN MemOffset, | |
| IN UINTN MemSize, | |
| IN EDIT_FILE_TYPE BufferType | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EDIT_FILE_TYPE BufferTypeBackup; | |
| // | |
| // variable initialization | |
| // | |
| Status = EFI_SUCCESS; | |
| BufferTypeBackup = HBufferImage.BufferType; | |
| switch (HBufferImage.BufferType) { | |
| // | |
| // file buffer | |
| // | |
| case FileTypeFileBuffer: | |
| Status = HFileImageSave (FileName); | |
| break; | |
| // | |
| // disk buffer | |
| // | |
| case FileTypeDiskBuffer: | |
| Status = HDiskImageSave (DiskName, DiskOffset, DiskSize); | |
| break; | |
| // | |
| // memory buffer | |
| // | |
| case FileTypeMemBuffer: | |
| Status = HMemImageSave (MemOffset, MemSize); | |
| break; | |
| default: | |
| Status = EFI_NOT_FOUND; | |
| break; | |
| } | |
| if (EFI_ERROR (Status)) { | |
| HBufferImage.BufferType = BufferTypeBackup; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Create a new line and append it to the line list. | |
| Fields affected: | |
| NumLines | |
| Lines | |
| @retval NULL create line failed. | |
| @return the line created. | |
| **/ | |
| HEFI_EDITOR_LINE * | |
| HBufferImageCreateLine ( | |
| VOID | |
| ) | |
| { | |
| HEFI_EDITOR_LINE *Line; | |
| // | |
| // allocate for line structure | |
| // | |
| Line = AllocateZeroPool (sizeof (HEFI_EDITOR_LINE)); | |
| if (Line == NULL) { | |
| return NULL; | |
| } | |
| Line->Signature = EFI_EDITOR_LINE_LIST; | |
| Line->Size = 0; | |
| HBufferImage.NumLines++; | |
| // | |
| // insert to line list | |
| // | |
| InsertTailList (HBufferImage.ListHead, &Line->Link); | |
| if (HBufferImage.Lines == NULL) { | |
| HBufferImage.Lines = CR ( | |
| HBufferImage.ListHead->ForwardLink, | |
| HEFI_EDITOR_LINE, | |
| Link, | |
| EFI_EDITOR_LINE_LIST | |
| ); | |
| } | |
| return Line; | |
| } | |
| /** | |
| Free the current image. | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageFree ( | |
| VOID | |
| ) | |
| { | |
| // | |
| // free all lines | |
| // | |
| HBufferImageFreeLines (); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| change char to int value based on Hex. | |
| @param[in] Char The input char. | |
| @return The character's index value. | |
| @retval -1 The operation failed. | |
| **/ | |
| INTN | |
| EFIAPI | |
| HBufferImageCharToHex ( | |
| IN CHAR16 Char | |
| ) | |
| { | |
| // | |
| // change the character to hex | |
| // | |
| if (Char >= L'0' && Char <= L'9') { | |
| return (INTN) (Char - L'0'); | |
| } | |
| if (Char >= L'a' && Char <= L'f') { | |
| return (INTN) (Char - L'a' + 10); | |
| } | |
| if (Char >= L'A' && Char <= L'F') { | |
| return (INTN) (Char - L'A' + 10); | |
| } | |
| return -1; | |
| } | |
| /** | |
| Add character. | |
| @param[in] Char -- input char. | |
| @retval EFI_SUCCESS The operation was successful. | |
| @retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HBufferImageAddChar ( | |
| IN CHAR16 Char | |
| ) | |
| { | |
| HEFI_EDITOR_LINE *Line; | |
| HEFI_EDITOR_LINE *NewLine; | |
| INTN Value; | |
| UINT8 Old; | |
| UINTN FRow; | |
| UINTN FCol; | |
| BOOLEAN High; | |
| Value = HBufferImageCharToHex (Char); | |
| // | |
| // invalid input | |
| // | |
| if (Value == -1) { | |
| return EFI_SUCCESS; | |
| } | |
| Line = HBufferImage.CurrentLine; | |
| FRow = HBufferImage.BufferPosition.Row; | |
| FCol = HBufferImage.BufferPosition.Column; | |
| High = HBufferImage.HighBits; | |
| // | |
| // only needs to refresh current line | |
| // | |
| HBufferImageOnlyLineNeedRefresh = TRUE; | |
| // | |
| // not a full line and beyond the last character | |
| // | |
| if (FCol > Line->Size) { | |
| // | |
| // cursor always at high 4 bits | |
| // and always put input to the low 4 bits | |
| // | |
| Line->Buffer[Line->Size] = (UINT8) Value; | |
| Line->Size++; | |
| High = FALSE; | |
| } else { | |
| Old = Line->Buffer[FCol - 1]; | |
| // | |
| // always put the input to the low 4 bits | |
| // | |
| Old = (UINT8) (Old & 0x0f); | |
| Old = (UINT8) (Old << 4); | |
| Old = (UINT8) (Value + Old); | |
| Line->Buffer[FCol - 1] = Old; | |
| // | |
| // at the low 4 bits of the last character of a full line | |
| // so if no next line, need to create a new line | |
| // | |
| if (!High && FCol == 0x10) { | |
| HBufferImageOnlyLineNeedRefresh = FALSE; | |
| HBufferImageNeedRefresh = TRUE; | |
| if (Line->Link.ForwardLink == HBufferImage.ListHead) { | |
| // | |
| // last line | |
| // | |
| // create a new line | |
| // | |
| NewLine = HBufferImageCreateLine (); | |
| if (NewLine == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // end of NULL | |
| // | |
| } | |
| // | |
| // end of == ListHead | |
| // | |
| } | |
| // | |
| // end of == 0x10 | |
| // | |
| // if already at end of this line, scroll it to the start of next line | |
| // | |
| if (FCol == 0x10 && !High) { | |
| // | |
| // definitely has next line | |
| // | |
| FRow++; | |
| FCol = 1; | |
| High = TRUE; | |
| } else { | |
| // | |
| // if not at end of this line, just move to next column | |
| // | |
| if (!High) { | |
| FCol++; | |
| } | |
| if (High) { | |
| High = FALSE; | |
| } else { | |
| High = TRUE; | |
| } | |
| } | |
| // | |
| // end of ==FALSE | |
| // | |
| } | |
| // | |
| // move cursor to right | |
| // | |
| HBufferImageMovePosition (FRow, FCol, High); | |
| if (!HBufferImage.Modified) { | |
| HBufferImage.Modified = TRUE; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Delete the previous character. | |
| @retval EFI_SUCCESS The operationw as successful. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HBufferImageDoBackspace ( | |
| VOID | |
| ) | |
| { | |
| HEFI_EDITOR_LINE *Line; | |
| UINTN FileColumn; | |
| UINTN FPos; | |
| BOOLEAN LastLine; | |
| // | |
| // variable initialization | |
| // | |
| LastLine = FALSE; | |
| // | |
| // already the first character | |
| // | |
| if (HBufferImage.BufferPosition.Row == 1 && HBufferImage.BufferPosition.Column == 1) { | |
| return EFI_SUCCESS; | |
| } | |
| FPos = (HBufferImage.BufferPosition.Row - 1) * 0x10 + HBufferImage.BufferPosition.Column - 1; | |
| FileColumn = HBufferImage.BufferPosition.Column; | |
| Line = HBufferImage.CurrentLine; | |
| LastLine = FALSE; | |
| if (Line->Link.ForwardLink == HBufferImage.ListHead && FileColumn > 1) { | |
| LastLine = TRUE; | |
| } | |
| HBufferImageDeleteCharacterFromBuffer (FPos - 1, 1, NULL); | |
| // | |
| // if is the last line | |
| // then only this line need to be refreshed | |
| // | |
| if (LastLine) { | |
| HBufferImageNeedRefresh = FALSE; | |
| HBufferImageOnlyLineNeedRefresh = TRUE; | |
| } else { | |
| HBufferImageNeedRefresh = TRUE; | |
| HBufferImageOnlyLineNeedRefresh = FALSE; | |
| } | |
| if (!HBufferImage.Modified) { | |
| HBufferImage.Modified = TRUE; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| ASCII key + Backspace + return. | |
| @param[in] Char The input char. | |
| @retval EFI_SUCCESS The operation was successful. | |
| @retval EFI_LOAD_ERROR A load error occured. | |
| @retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HBufferImageDoCharInput ( | |
| IN CHAR16 Char | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = EFI_SUCCESS; | |
| switch (Char) { | |
| case 0: | |
| break; | |
| case 0x08: | |
| Status = HBufferImageDoBackspace (); | |
| break; | |
| case 0x09: | |
| case 0x0a: | |
| case 0x0d: | |
| // | |
| // Tabs, Returns are thought as nothing | |
| // | |
| break; | |
| default: | |
| // | |
| // DEAL WITH ASCII CHAR, filter out thing like ctrl+f | |
| // | |
| if (Char > 127 || Char < 32) { | |
| Status = StatusBarSetStatusString (L"Unknown Command"); | |
| } else { | |
| Status = HBufferImageAddChar (Char); | |
| } | |
| break; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Check user specified FileRow is above current screen. | |
| @param[in] FileRow Row of file position ( start from 1 ). | |
| @retval TRUE It is above the current screen. | |
| @retval FALSE It is not above the current screen. | |
| **/ | |
| BOOLEAN | |
| HAboveCurrentScreen ( | |
| IN UINTN FileRow | |
| ) | |
| { | |
| if (FileRow < HBufferImage.LowVisibleRow) { | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Check user specified FileRow is under current screen. | |
| @param[in] FileRow Row of file position ( start from 1 ). | |
| @retval TRUE It is under the current screen. | |
| @retval FALSE It is not under the current screen. | |
| **/ | |
| BOOLEAN | |
| HUnderCurrentScreen ( | |
| IN UINTN FileRow | |
| ) | |
| { | |
| if (FileRow > HBufferImage.LowVisibleRow + (HMainEditor.ScreenSize.Row - 2) - 1) { | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| According to cursor's file position, adjust screen display. | |
| @param[in] NewFilePosRow Row of file position ( start from 1 ). | |
| @param[in] NewFilePosCol Column of file position ( start from 1 ). | |
| @param[in] HighBits Cursor will on high4 bits or low4 bits. | |
| **/ | |
| VOID | |
| HBufferImageMovePosition ( | |
| IN UINTN NewFilePosRow, | |
| IN UINTN NewFilePosCol, | |
| IN BOOLEAN HighBits | |
| ) | |
| { | |
| INTN RowGap; | |
| UINTN Abs; | |
| BOOLEAN Above; | |
| BOOLEAN Under; | |
| UINTN NewDisplayCol; | |
| // | |
| // CALCULATE gap between current file position and new file position | |
| // | |
| RowGap = NewFilePosRow - HBufferImage.BufferPosition.Row; | |
| Under = HUnderCurrentScreen (NewFilePosRow); | |
| Above = HAboveCurrentScreen (NewFilePosRow); | |
| HBufferImage.HighBits = HighBits; | |
| // | |
| // if is below current screen | |
| // | |
| if (Under) { | |
| // | |
| // display row will be unchanged | |
| // | |
| HBufferImage.BufferPosition.Row = NewFilePosRow; | |
| } else { | |
| if (Above) { | |
| // | |
| // has enough above line, so display row unchanged | |
| // not has enough above lines, so the first line is | |
| // at the first display line | |
| // | |
| if (NewFilePosRow < (HBufferImage.DisplayPosition.Row - 2 + 1)) { | |
| HBufferImage.DisplayPosition.Row = NewFilePosRow + 2 - 1; | |
| } | |
| HBufferImage.BufferPosition.Row = NewFilePosRow; | |
| } else { | |
| // | |
| // in current screen | |
| // | |
| HBufferImage.BufferPosition.Row = NewFilePosRow; | |
| if (RowGap <= 0) { | |
| Abs = (UINTN)ABS(RowGap); | |
| HBufferImage.DisplayPosition.Row -= Abs; | |
| } else { | |
| HBufferImage.DisplayPosition.Row += RowGap; | |
| } | |
| } | |
| } | |
| HBufferImage.LowVisibleRow = HBufferImage.BufferPosition.Row - (HBufferImage.DisplayPosition.Row - 2); | |
| // | |
| // always in current screen | |
| // | |
| HBufferImage.BufferPosition.Column = NewFilePosCol; | |
| NewDisplayCol = 10 + (NewFilePosCol - 1) * 3; | |
| if (NewFilePosCol > 0x8) { | |
| NewDisplayCol++; | |
| } | |
| if (!HighBits) { | |
| NewDisplayCol++; | |
| } | |
| HBufferImage.DisplayPosition.Column = NewDisplayCol; | |
| // | |
| // let CurrentLine point to correct line; | |
| // | |
| HBufferImage.CurrentLine = HMoveCurrentLine (RowGap); | |
| } | |
| /** | |
| Scroll cursor to right. | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageScrollRight ( | |
| VOID | |
| ) | |
| { | |
| HEFI_EDITOR_LINE *Line; | |
| UINTN FRow; | |
| UINTN FCol; | |
| // | |
| // scroll right will always move to the high4 bits of the next character | |
| // | |
| HBufferImageNeedRefresh = FALSE; | |
| HBufferImageOnlyLineNeedRefresh = FALSE; | |
| Line = HBufferImage.CurrentLine; | |
| FRow = HBufferImage.BufferPosition.Row; | |
| FCol = HBufferImage.BufferPosition.Column; | |
| // | |
| // this line is not full and no next line | |
| // | |
| if (FCol > Line->Size) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // if already at end of this line, scroll it to the start of next line | |
| // | |
| if (FCol == 0x10) { | |
| // | |
| // has next line | |
| // | |
| if (Line->Link.ForwardLink != HBufferImage.ListHead) { | |
| FRow++; | |
| FCol = 1; | |
| } else { | |
| return EFI_SUCCESS; | |
| } | |
| } else { | |
| // | |
| // if not at end of this line, just move to next column | |
| // | |
| FCol++; | |
| } | |
| HBufferImageMovePosition (FRow, FCol, TRUE); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Scroll cursor to left. | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageScrollLeft ( | |
| VOID | |
| ) | |
| { | |
| HEFI_EDITOR_LINE *Line; | |
| UINTN FRow; | |
| UINTN FCol; | |
| HBufferImageNeedRefresh = FALSE; | |
| HBufferImageOnlyLineNeedRefresh = FALSE; | |
| Line = HBufferImage.CurrentLine; | |
| FRow = HBufferImage.BufferPosition.Row; | |
| FCol = HBufferImage.BufferPosition.Column; | |
| // | |
| // if already at start of this line, so move to the end of previous line | |
| // | |
| if (FCol <= 1) { | |
| // | |
| // has previous line | |
| // | |
| if (Line->Link.BackLink != HBufferImage.ListHead) { | |
| FRow--; | |
| Line = CR (Line->Link.BackLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); | |
| FCol = Line->Size; | |
| } else { | |
| return EFI_SUCCESS; | |
| } | |
| } else { | |
| // | |
| // if not at start of this line, just move to previous column | |
| // | |
| FCol--; | |
| } | |
| HBufferImageMovePosition (FRow, FCol, TRUE); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Scroll cursor to the next line | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageScrollDown ( | |
| VOID | |
| ) | |
| { | |
| HEFI_EDITOR_LINE *Line; | |
| UINTN FRow; | |
| UINTN FCol; | |
| BOOLEAN HighBits; | |
| Line = HBufferImage.CurrentLine; | |
| FRow = HBufferImage.BufferPosition.Row; | |
| FCol = HBufferImage.BufferPosition.Column; | |
| HighBits = HBufferImage.HighBits; | |
| // | |
| // has next line | |
| // | |
| if (Line->Link.ForwardLink != HBufferImage.ListHead) { | |
| FRow++; | |
| Line = CR (Line->Link.ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); | |
| // | |
| // if the next line is not that long, so move to end of next line | |
| // | |
| if (FCol > Line->Size) { | |
| FCol = Line->Size + 1; | |
| HighBits = TRUE; | |
| } | |
| } else { | |
| return EFI_SUCCESS; | |
| } | |
| HBufferImageMovePosition (FRow, FCol, HighBits); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Scroll cursor to previous line | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageScrollUp ( | |
| VOID | |
| ) | |
| { | |
| HEFI_EDITOR_LINE *Line; | |
| UINTN FRow; | |
| UINTN FCol; | |
| Line = HBufferImage.CurrentLine; | |
| FRow = HBufferImage.BufferPosition.Row; | |
| FCol = HBufferImage.BufferPosition.Column; | |
| // | |
| // has previous line | |
| // | |
| if (Line->Link.BackLink != HBufferImage.ListHead) { | |
| FRow--; | |
| } else { | |
| return EFI_SUCCESS; | |
| } | |
| HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Scroll cursor to next page | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImagePageDown ( | |
| VOID | |
| ) | |
| { | |
| HEFI_EDITOR_LINE *Line; | |
| UINTN FRow; | |
| UINTN FCol; | |
| UINTN Gap; | |
| BOOLEAN HighBits; | |
| Line = HBufferImage.CurrentLine; | |
| FRow = HBufferImage.BufferPosition.Row; | |
| FCol = HBufferImage.BufferPosition.Column; | |
| HighBits = HBufferImage.HighBits; | |
| // | |
| // has next page | |
| // | |
| if (HBufferImage.NumLines >= FRow + (HMainEditor.ScreenSize.Row - 2)) { | |
| Gap = (HMainEditor.ScreenSize.Row - 2); | |
| } else { | |
| // | |
| // MOVE CURSOR TO LAST LINE | |
| // | |
| Gap = HBufferImage.NumLines - FRow; | |
| } | |
| // | |
| // get correct line | |
| // | |
| Line = HMoveLine (Gap); | |
| // | |
| // if that line, is not that long, so move to the end of that line | |
| // | |
| if (Line != NULL && FCol > Line->Size) { | |
| FCol = Line->Size + 1; | |
| HighBits = TRUE; | |
| } | |
| FRow += Gap; | |
| HBufferImageMovePosition (FRow, FCol, HighBits); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Scroll cursor to previous page | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImagePageUp ( | |
| VOID | |
| ) | |
| { | |
| UINTN FRow; | |
| UINTN FCol; | |
| UINTN Gap; | |
| INTN Retreat; | |
| FRow = HBufferImage.BufferPosition.Row; | |
| FCol = HBufferImage.BufferPosition.Column; | |
| // | |
| // has previous page | |
| // | |
| if (FRow > (HMainEditor.ScreenSize.Row - 2)) { | |
| Gap = (HMainEditor.ScreenSize.Row - 2); | |
| } else { | |
| // | |
| // the first line of file will displayed on the first line of screen | |
| // | |
| Gap = FRow - 1; | |
| } | |
| Retreat = Gap; | |
| Retreat = -Retreat; | |
| FRow -= Gap; | |
| HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Scroll cursor to start of line | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageHome ( | |
| VOID | |
| ) | |
| { | |
| UINTN FRow; | |
| UINTN FCol; | |
| BOOLEAN HighBits; | |
| // | |
| // curosr will at the high bit | |
| // | |
| FRow = HBufferImage.BufferPosition.Row; | |
| FCol = 1; | |
| HighBits = TRUE; | |
| // | |
| // move cursor position | |
| // | |
| HBufferImageMovePosition (FRow, FCol, HighBits); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Scroll cursor to end of line. | |
| @retval EFI_SUCCESS Teh operation was successful. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageEnd ( | |
| VOID | |
| ) | |
| { | |
| HEFI_EDITOR_LINE *Line; | |
| UINTN FRow; | |
| UINTN FCol; | |
| BOOLEAN HighBits; | |
| // | |
| // need refresh mouse | |
| // | |
| HBufferImageMouseNeedRefresh = TRUE; | |
| Line = HBufferImage.CurrentLine; | |
| FRow = HBufferImage.BufferPosition.Row; | |
| if (Line->Size == 0x10) { | |
| FCol = Line->Size; | |
| HighBits = FALSE; | |
| } else { | |
| FCol = Line->Size + 1; | |
| HighBits = TRUE; | |
| } | |
| // | |
| // move cursor position | |
| // | |
| HBufferImageMovePosition (FRow, FCol, HighBits); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Get the size of the open buffer. | |
| @retval The size in bytes. | |
| **/ | |
| UINTN | |
| HBufferImageGetTotalSize ( | |
| VOID | |
| ) | |
| { | |
| UINTN Size; | |
| HEFI_EDITOR_LINE *Line; | |
| // | |
| // calculate the total size of whole line list's buffer | |
| // | |
| if (HBufferImage.Lines == NULL) { | |
| return 0; | |
| } | |
| Line = CR ( | |
| HBufferImage.ListHead->BackLink, | |
| HEFI_EDITOR_LINE, | |
| Link, | |
| EFI_EDITOR_LINE_LIST | |
| ); | |
| // | |
| // one line at most 0x10 | |
| // | |
| Size = 0x10 * (HBufferImage.NumLines - 1) + Line->Size; | |
| return Size; | |
| } | |
| /** | |
| Delete character from buffer. | |
| @param[in] Pos Position, Pos starting from 0. | |
| @param[in] Count The Count of characters to delete. | |
| @param[out] DeleteBuffer The DeleteBuffer. | |
| @retval EFI_SUCCESS Success | |
| **/ | |
| EFI_STATUS | |
| HBufferImageDeleteCharacterFromBuffer ( | |
| IN UINTN Pos, | |
| IN UINTN Count, | |
| OUT UINT8 *DeleteBuffer | |
| ) | |
| { | |
| UINTN Index; | |
| VOID *Buffer; | |
| UINT8 *BufferPtr; | |
| UINTN Size; | |
| HEFI_EDITOR_LINE *Line; | |
| LIST_ENTRY *Link; | |
| UINTN OldFCol; | |
| UINTN OldFRow; | |
| UINTN OldPos; | |
| UINTN NewPos; | |
| EFI_STATUS Status; | |
| Size = HBufferImageGetTotalSize (); | |
| if (Size < Count) { | |
| return EFI_LOAD_ERROR; | |
| } | |
| if (Size == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // relocate all the HBufferImage fields | |
| // | |
| OldFRow = HBufferImage.BufferPosition.Row; | |
| OldFCol = HBufferImage.BufferPosition.Column; | |
| OldPos = (OldFRow - 1) * 0x10 + OldFCol - 1; | |
| if (Pos > 0) { | |
| // | |
| // has character before it, | |
| // so locate according to block's previous character | |
| // | |
| NewPos = Pos - 1; | |
| } else { | |
| // | |
| // has no character before it, | |
| // so locate according to block's next character | |
| // | |
| NewPos = 0; | |
| } | |
| HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); | |
| Buffer = AllocateZeroPool (Size); | |
| if (Buffer == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| HBufferImageListToBuffer (Buffer, Size); | |
| BufferPtr = (UINT8 *) Buffer; | |
| // | |
| // pass deleted buffer out | |
| // | |
| if (DeleteBuffer != NULL) { | |
| for (Index = 0; Index < Count; Index++) { | |
| DeleteBuffer[Index] = BufferPtr[Pos + Index]; | |
| } | |
| } | |
| // | |
| // delete the part from Pos | |
| // | |
| for (Index = Pos; Index < Size - Count; Index++) { | |
| BufferPtr[Index] = BufferPtr[Index + Count]; | |
| } | |
| Size -= Count; | |
| HBufferImageFreeLines (); | |
| Status = HBufferImageBufferToList (Buffer, Size); | |
| FreePool (Buffer); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Link = HMainEditor.BufferImage->ListHead->ForwardLink; | |
| for (Index = 0; Index < NewPos / 0x10; Index++) { | |
| Link = Link->ForwardLink; | |
| } | |
| Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); | |
| HBufferImage.CurrentLine = Line; | |
| // | |
| // if current cursor position if inside select area | |
| // then move it to the block's NEXT character | |
| // | |
| if (OldPos >= Pos && OldPos < (Pos + Count)) { | |
| NewPos = Pos; | |
| } else { | |
| if (OldPos < Pos) { | |
| NewPos = OldPos; | |
| } else { | |
| NewPos = OldPos - Count; | |
| } | |
| } | |
| HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Add character to buffer, add before pos. | |
| @param[in] Pos Position, Pos starting from 0. | |
| @param[in] Count Count of characters to add. | |
| @param[in] AddBuffer Add buffer. | |
| @retval EFI_SUCCESS Success. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageAddCharacterToBuffer ( | |
| IN UINTN Pos, | |
| IN UINTN Count, | |
| IN UINT8 *AddBuffer | |
| ) | |
| { | |
| INTN Index; | |
| VOID *Buffer; | |
| UINT8 *BufferPtr; | |
| UINTN Size; | |
| HEFI_EDITOR_LINE *Line; | |
| LIST_ENTRY *Link; | |
| UINTN OldFCol; | |
| UINTN OldFRow; | |
| UINTN OldPos; | |
| UINTN NewPos; | |
| Size = HBufferImageGetTotalSize (); | |
| // | |
| // relocate all the HBufferImage fields | |
| // | |
| OldFRow = HBufferImage.BufferPosition.Row; | |
| OldFCol = HBufferImage.BufferPosition.Column; | |
| OldPos = (OldFRow - 1) * 0x10 + OldFCol - 1; | |
| // | |
| // move cursor before Pos | |
| // | |
| if (Pos > 0) { | |
| NewPos = Pos - 1; | |
| } else { | |
| NewPos = 0; | |
| } | |
| HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); | |
| Buffer = AllocateZeroPool (Size + Count); | |
| if (Buffer == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| HBufferImageListToBuffer (Buffer, Size); | |
| BufferPtr = (UINT8 *) Buffer; | |
| // | |
| // get a place to add | |
| // | |
| for (Index = (INTN) (Size + Count - 1); Index >= (INTN) Pos; Index--) { | |
| BufferPtr[Index] = BufferPtr[Index - Count]; | |
| } | |
| // | |
| // add the buffer | |
| // | |
| for (Index = (INTN) 0; Index < (INTN) Count; Index++) { | |
| BufferPtr[Index + Pos] = AddBuffer[Index]; | |
| } | |
| Size += Count; | |
| HBufferImageFreeLines (); | |
| HBufferImageBufferToList (Buffer, Size); | |
| FreePool (Buffer); | |
| Link = HMainEditor.BufferImage->ListHead->ForwardLink; | |
| for (Index = 0; Index < (INTN) NewPos / 0x10; Index++) { | |
| Link = Link->ForwardLink; | |
| } | |
| Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); | |
| HBufferImage.CurrentLine = Line; | |
| if (OldPos >= Pos) { | |
| NewPos = OldPos + Count; | |
| } else { | |
| NewPos = OldPos; | |
| } | |
| HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Delete current character from line. | |
| @retval EFI_SUCCESS The operationw as successful. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HBufferImageDoDelete ( | |
| VOID | |
| ) | |
| { | |
| HEFI_EDITOR_LINE *Line; | |
| BOOLEAN LastLine; | |
| UINTN FileColumn; | |
| UINTN FPos; | |
| FPos = (HBufferImage.BufferPosition.Row - 1) * 0x10 + HBufferImage.BufferPosition.Column - 1; | |
| FileColumn = HBufferImage.BufferPosition.Column; | |
| Line = HBufferImage.CurrentLine; | |
| // | |
| // if beyond the last character | |
| // | |
| if (FileColumn > Line->Size) { | |
| return EFI_SUCCESS; | |
| } | |
| LastLine = FALSE; | |
| if (Line->Link.ForwardLink == HBufferImage.ListHead) { | |
| LastLine = TRUE; | |
| } | |
| HBufferImageDeleteCharacterFromBuffer (FPos, 1, NULL); | |
| // | |
| // if is the last line | |
| // then only this line need to be refreshed | |
| // | |
| if (LastLine) { | |
| HBufferImageNeedRefresh = FALSE; | |
| HBufferImageOnlyLineNeedRefresh = TRUE; | |
| } else { | |
| HBufferImageNeedRefresh = TRUE; | |
| HBufferImageOnlyLineNeedRefresh = FALSE; | |
| } | |
| if (!HBufferImage.Modified) { | |
| HBufferImage.Modified = TRUE; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Change the raw buffer to a list of lines for the UI. | |
| @param[in] Buffer The pointer to the buffer to fill. | |
| @param[in] Bytes The size of the buffer in bytes. | |
| @retval EFI_SUCCESS The operation was successful. | |
| @retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HBufferImageBufferToList ( | |
| IN VOID *Buffer, | |
| IN UINTN Bytes | |
| ) | |
| { | |
| UINTN TempI; | |
| UINTN TempJ; | |
| UINTN Left; | |
| HEFI_EDITOR_LINE *Line; | |
| UINT8 *BufferPtr; | |
| TempI = 0; | |
| Left = 0; | |
| BufferPtr = (UINT8 *) Buffer; | |
| // | |
| // parse file content line by line | |
| // | |
| while (TempI < Bytes) { | |
| if (Bytes - TempI >= 0x10) { | |
| Left = 0x10; | |
| } else { | |
| Left = Bytes - TempI; | |
| } | |
| // | |
| // allocate a new line | |
| // | |
| Line = HBufferImageCreateLine (); | |
| if (Line == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| Line->Size = Left; | |
| for (TempJ = 0; TempJ < Left; TempJ++) { | |
| Line->Buffer[TempJ] = BufferPtr[TempI]; | |
| TempI++; | |
| } | |
| } | |
| // | |
| // last line is a full line, SO create a new line | |
| // | |
| if (Left == 0x10 || Bytes == 0) { | |
| Line = HBufferImageCreateLine (); | |
| if (Line == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Change the list of lines from the UI to a raw buffer. | |
| @param[in] Buffer The pointer to the buffer to fill. | |
| @param[in] Bytes The size of the buffer in bytes. | |
| @retval EFI_SUCCESS The operation was successful. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HBufferImageListToBuffer ( | |
| IN VOID *Buffer, | |
| IN UINTN Bytes | |
| ) | |
| { | |
| UINTN Count; | |
| UINTN Index; | |
| HEFI_EDITOR_LINE *Line; | |
| LIST_ENTRY *Link; | |
| UINT8 *BufferPtr; | |
| // | |
| // change the line list to a large buffer | |
| // | |
| if (HBufferImage.Lines == NULL) { | |
| return EFI_SUCCESS; | |
| } | |
| Link = &HBufferImage.Lines->Link; | |
| Count = 0; | |
| BufferPtr = (UINT8 *) Buffer; | |
| // | |
| // deal line by line | |
| // | |
| while (Link != HBufferImage.ListHead) { | |
| Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); | |
| //@todo shouldn't this be an error??? | |
| if (Count + Line->Size > Bytes) { | |
| return EFI_SUCCESS; | |
| } | |
| for (Index = 0; Index < Line->Size; Index++) { | |
| BufferPtr[Index] = Line->Buffer[Index]; | |
| } | |
| Count += Line->Size; | |
| BufferPtr += Line->Size; | |
| Link = Link->ForwardLink; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Move the mouse in the image buffer. | |
| @param[in] TextX The x-coordinate. | |
| @param[in] TextY The y-coordinate. | |
| **/ | |
| VOID | |
| EFIAPI | |
| HBufferImageAdjustMousePosition ( | |
| IN INT32 TextX, | |
| IN INT32 TextY | |
| ) | |
| { | |
| UINTN TempX; | |
| UINTN TempY; | |
| UINTN AbsX; | |
| UINTN AbsY; | |
| // | |
| // TextX and TextY is mouse movement data returned by mouse driver | |
| // This function will change it to MousePosition | |
| // | |
| // | |
| // get absolute TempX value | |
| // | |
| if (TextX >= 0) { | |
| AbsX = TextX; | |
| } else { | |
| AbsX = -TextX; | |
| } | |
| // | |
| // get absolute TempY value | |
| // | |
| if (TextY >= 0) { | |
| AbsY = TextY; | |
| } else { | |
| AbsY = -TextY; | |
| } | |
| TempX = HBufferImage.MousePosition.Column; | |
| TempY = HBufferImage.MousePosition.Row; | |
| if (TextX >= 0) { | |
| TempX += TextX; | |
| } else { | |
| if (TempX >= AbsX) { | |
| TempX -= AbsX; | |
| } else { | |
| TempX = 0; | |
| } | |
| } | |
| if (TextY >= 0) { | |
| TempY += TextY; | |
| } else { | |
| if (TempY >= AbsY) { | |
| TempY -= AbsY; | |
| } else { | |
| TempY = 0; | |
| } | |
| } | |
| // | |
| // check whether new mouse column position is beyond screen | |
| // if not, adjust it | |
| // | |
| if (TempX >= 10 && TempX <= (10 + 0x10 * 3 - 1)) { | |
| HBufferImage.MousePosition.Column = TempX; | |
| } else if (TempX < 10) { | |
| HBufferImage.MousePosition.Column = 10; | |
| } else if (TempX > (10 + 0x10 * 3 - 1)) { | |
| HBufferImage.MousePosition.Column = 10 + 0x10 * 3 - 1; | |
| } | |
| // | |
| // check whether new mouse row position is beyond screen | |
| // if not, adjust it | |
| // | |
| if (TempY >= 2 && TempY <= (HMainEditor.ScreenSize.Row - 1)) { | |
| HBufferImage.MousePosition.Row = TempY; | |
| } else if (TempY < 2) { | |
| HBufferImage.MousePosition.Row = 2; | |
| } else if (TempY > (HMainEditor.ScreenSize.Row - 1)) { | |
| HBufferImage.MousePosition.Row = (HMainEditor.ScreenSize.Row - 1); | |
| } | |
| } | |
| /** | |
| Dispatch input to different handler | |
| @param[in] Key The input key: | |
| the keys can be: | |
| ASCII KEY | |
| Backspace/Delete | |
| Direction key: up/down/left/right/pgup/pgdn | |
| Home/End | |
| INS | |
| @retval EFI_SUCCESS The operation was successful. | |
| @retval EFI_LOAD_ERROR A load error occured. | |
| @retval EFI_OUT_OF_RESOURCES A Memory allocation failed. | |
| **/ | |
| EFI_STATUS | |
| HBufferImageHandleInput ( | |
| IN EFI_INPUT_KEY *Key | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = EFI_SUCCESS; | |
| switch (Key->ScanCode) { | |
| // | |
| // ordinary key | |
| // | |
| case SCAN_NULL: | |
| Status = HBufferImageDoCharInput (Key->UnicodeChar); | |
| break; | |
| // | |
| // up arrow | |
| // | |
| case SCAN_UP: | |
| Status = HBufferImageScrollUp (); | |
| break; | |
| // | |
| // down arrow | |
| // | |
| case SCAN_DOWN: | |
| Status = HBufferImageScrollDown (); | |
| break; | |
| // | |
| // right arrow | |
| // | |
| case SCAN_RIGHT: | |
| Status = HBufferImageScrollRight (); | |
| break; | |
| // | |
| // left arrow | |
| // | |
| case SCAN_LEFT: | |
| Status = HBufferImageScrollLeft (); | |
| break; | |
| // | |
| // page up | |
| // | |
| case SCAN_PAGE_UP: | |
| Status = HBufferImagePageUp (); | |
| break; | |
| // | |
| // page down | |
| // | |
| case SCAN_PAGE_DOWN: | |
| Status = HBufferImagePageDown (); | |
| break; | |
| // | |
| // delete | |
| // | |
| case SCAN_DELETE: | |
| Status = HBufferImageDoDelete (); | |
| break; | |
| // | |
| // home | |
| // | |
| case SCAN_HOME: | |
| Status = HBufferImageHome (); | |
| break; | |
| // | |
| // end | |
| // | |
| case SCAN_END: | |
| Status = HBufferImageEnd (); | |
| break; | |
| default: | |
| Status = StatusBarSetStatusString (L"Unknown Command"); | |
| break; | |
| } | |
| return Status; | |
| } | |