/** @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 - 2014, 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 & 0x7F); | |
} else { | |
gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); | |
} | |
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 & 0x7F); | |
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 & 0x7F); | |
} else { | |
gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); | |
} | |
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 & 0x7F); | |
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 & 0x7F); | |
// | |
// 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 & 0xF; | |
New.Colors.Background = Orig.Colors.Foreground & 0x7; | |
// | |
// 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 & 0x7F); | |
} | |
// | |
// 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 & 0x7F); | |
} 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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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; | |
} | |