From: jcarsey Date: Fri, 25 Mar 2011 21:15:07 +0000 (+0000) Subject: add Edit and HexEdit commands. X-Git-Tag: edk2-stable201903~15043 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=632820d1cf1ce7a18ef354255eaeae6fdbf383b9 add Edit and HexEdit commands. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11436 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c new file mode 100644 index 0000000000..c4dbf80c96 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c @@ -0,0 +1,158 @@ +/** @file + Main file for Edit shell Debug1 function. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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 "UefiShellDebug1CommandsLib.h" +#include "TextEditor.h" + +/** + Function for 'edit' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEdit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CHAR16 *Buffer; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + LIST_ENTRY *Package; + CONST CHAR16 *Cwd; + CHAR16 *Nfs; + CHAR16 *Spot; +// SHELL_FILE_HANDLE TempHandle; + + Buffer = NULL; + ShellStatus = SHELL_SUCCESS; + Nfs = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Cwd = gEfiShellProtocol->GetCurDir(NULL); + if (Cwd == NULL) { + Cwd = ShellGetEnvironmentVariable(L"path"); + if (Cwd != NULL) { + Nfs = StrnCatGrow(&Nfs, NULL, Cwd+3, 0); + if (Nfs != NULL) { + Spot = StrStr(Nfs, L";"); + if (Spot != NULL) { + *Spot = CHAR_NULL; + } + Spot = StrStr(Nfs, L"\\"); + if (Spot != NULL) { + Spot[1] = CHAR_NULL; + } + gEfiShellProtocol->SetCurDir(NULL, Nfs); + FreePool(Nfs); + } + } + } + + Status = MainEditorInit (); + + if (EFI_ERROR (Status)) { + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_INIT_FAILED), gShellDebug1HiiHandle); + } else { + MainEditorBackup (); + + // + // if editor launched with file named + // + if (ShellCommandLineGetCount(Package) == 2) { + FileBufferSetFileName (ShellCommandLineGetRawValue(Package, 1)); +// if (EFI_ERROR(ShellFileExists(MainEditor.FileBuffer->FileName))) { +// Status = ShellOpenFileByName(MainEditor.FileBuffer->FileName, &TempHandle, EFI_FILE_MODE_CREATE|EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); +// if (!EFI_ERROR(Status)) { +// ShellCloseFile(&TempHandle); +// } +// } + } + + Status = FileBufferRead (MainEditor.FileBuffer->FileName, FALSE); + if (!EFI_ERROR (Status)) { + MainEditorRefresh (); + + Status = MainEditorKeyInput (); + } + + if (Status != EFI_OUT_OF_RESOURCES) { + // + // back up the status string + // + Buffer = CatSPrint (NULL, L"%s", StatusBarGetString()); + } + + MainEditorCleanup (); + + // + // print editor exit code on screen + // + if (Status == EFI_SUCCESS) { + } else if (Status == EFI_OUT_OF_RESOURCES) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_GEN_OUT_MEM), gShellDebug1HiiHandle); + } else { + if (Buffer != NULL) { + if (StrCmp (Buffer, L"") != 0) { + // + // print out the status string + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_BUFFER), gShellDebug1HiiHandle, Buffer); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_UNKNOWN_EDITOR_ERR), gShellDebug1HiiHandle); + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_UNKNOWN_EDITOR_ERR), gShellDebug1HiiHandle); + } + } + + if (Status != EFI_OUT_OF_RESOURCES) { + SHELL_FREE_NON_NULL (Buffer); + } + } + } + ShellCommandLineFreeVarList (Package); + } + return ShellStatus; +} diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c new file mode 100644 index 0000000000..5843c7807d --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c @@ -0,0 +1,3353 @@ +/** @file + Implements filebuffer interface functions. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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 "TextEditor.h" +#include +#include + +EFI_EDITOR_FILE_BUFFER FileBuffer; +EFI_EDITOR_FILE_BUFFER FileBufferBackupVar; + +// +// for basic initialization of FileBuffer +// +EFI_EDITOR_FILE_BUFFER FileBufferConst = { + NULL, + FileTypeUnicode, + NULL, + NULL, + 0, + { + 0, + 0 + }, + { + 0, + 0 + }, + { + 0, + 0 + }, + { + 0, + 0 + }, + FALSE, + TRUE, + FALSE, + NULL +}; + +// +// the whole edit area needs to be refreshed +// +STATIC BOOLEAN FileBufferNeedRefresh; + +// +// only the current line in edit area needs to be refresh +// +BOOLEAN FileBufferOnlyLineNeedRefresh; + +BOOLEAN FileBufferMouseNeedRefresh; + +extern BOOLEAN EditorMouseAction; + +/** + Initialization function for FileBuffer. + + @param EFI_SUCCESS The initialization was successful. + @param EFI_LOAD_ERROR A default name could not be created. + @param EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferInit ( + VOID + ) +{ + // + // basically initialize the FileBuffer + // + CopyMem (&FileBuffer , &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER)); + CopyMem (&FileBufferBackupVar, &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER)); + + // + // set default FileName + // + FileBuffer.FileName = EditGetDefaultFileName (L"txt"); + if (FileBuffer.FileName == NULL) { + return EFI_LOAD_ERROR; + } + + FileBuffer.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY)); + if (FileBuffer.ListHead == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (FileBuffer.ListHead); + + FileBuffer.DisplayPosition.Row = 2; + FileBuffer.DisplayPosition.Column = 1; + FileBuffer.LowVisibleRange.Row = 2; + FileBuffer.LowVisibleRange.Column = 1; + + FileBufferNeedRefresh = FALSE; + FileBufferMouseNeedRefresh = FALSE; + FileBufferOnlyLineNeedRefresh = FALSE; + + return EFI_SUCCESS; +} + +/** + Backup function for FileBuffer. Only backup the following items: + Mouse/Cursor position + File Name, Type, ReadOnly, Modified + Insert Mode + + This is for making the file buffer refresh as few as possible. + + @retval EFI_SUCCESS The backup operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferBackup ( + VOID + ) +{ + FileBufferBackupVar.MousePosition = FileBuffer.MousePosition; + + SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName); + FileBufferBackupVar.FileName = NULL; + FileBufferBackupVar.FileName = StrnCatGrow (&FileBufferBackupVar.FileName, NULL, FileBuffer.FileName, 0); + + FileBufferBackupVar.ModeInsert = FileBuffer.ModeInsert; + FileBufferBackupVar.FileType = FileBuffer.FileType; + + FileBufferBackupVar.FilePosition = FileBuffer.FilePosition; + FileBufferBackupVar.LowVisibleRange = FileBuffer.LowVisibleRange; + + FileBufferBackupVar.FileModified = FileBuffer.FileModified; + FileBufferBackupVar.ReadOnly = FileBuffer.ReadOnly; + + return EFI_SUCCESS; +} + +/** + Advance to the next Count lines + + @param[in] Count The line number to advance by. + @param[in] CurrentLine The pointer to the current line structure. + @param[in] LineList The pointer to the linked list of lines. + + @retval NULL There was an error. + @return The line structure after the advance. +**/ +EFI_EDITOR_LINE * +EFIAPI +InternalEditorMiscLineAdvance ( + IN CONST UINTN Count, + IN CONST EFI_EDITOR_LINE *CurrentLine, + IN CONST LIST_ENTRY *LineList + ) + +{ + UINTN Index; + CONST EFI_EDITOR_LINE *Line; + + if (CurrentLine == NULL || LineList == NULL) { + return NULL; + } + + for (Line = CurrentLine, Index = 0; Index < Count; Index++) { + // + // if already last line + // + if (Line->Link.ForwardLink == LineList) { + return NULL; + } + + Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + } + + return ((EFI_EDITOR_LINE *)Line); +} + +/** + Retreat to the previous Count lines. + + @param[in] Count The line number to retreat by. + @param[in] CurrentLine The pointer to the current line structure. + @param[in] LineList The pointer to the linked list of lines. + + @retval NULL There was an error. + @return The line structure after the retreat. +**/ +EFI_EDITOR_LINE * +EFIAPI +InternalEditorMiscLineRetreat ( + IN CONST UINTN Count, + IN CONST EFI_EDITOR_LINE *CurrentLine, + IN CONST LIST_ENTRY *LineList + ) + +{ + UINTN Index; + CONST EFI_EDITOR_LINE *Line; + + if (CurrentLine == NULL || LineList == NULL) { + return NULL; + } + + for (Line = CurrentLine, Index = 0; Index < Count; Index++) { + // + // already the first line + // + if (Line->Link.BackLink == LineList) { + return NULL; + } + + Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + } + + return ((EFI_EDITOR_LINE *)Line); +} + +/** + Advance/Retreat lines + + @param[in] Count line number to advance/retreat + >0 : advance + <0 : retreat + + @retval NULL An error occured. + @return The line after advance/retreat. +**/ +EFI_EDITOR_LINE * +MoveLine ( + IN CONST INTN Count + ) +{ + EFI_EDITOR_LINE *Line; + UINTN AbsCount; + + // + // if < 0, then retreat + // if > 0, the advance + // + if (Count <= 0) { + AbsCount = -Count; + Line = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead); + } else { + Line = InternalEditorMiscLineAdvance (Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead); + } + + return Line; +} + +/** + Function to update the 'screen' to display the mouse position. + + @retval EFI_SUCCESS The backup operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferRestoreMousePosition ( + VOID + ) +{ + EFI_EDITOR_COLOR_UNION Orig; + EFI_EDITOR_COLOR_UNION New; + UINTN FRow; + UINTN FColumn; + BOOLEAN HasCharacter; + EFI_EDITOR_LINE *CurrentLine; + EFI_EDITOR_LINE *Line; + CHAR16 Value; + + // + // variable initialization + // + Line = NULL; + + if (MainEditor.MouseSupported) { + + if (FileBufferMouseNeedRefresh) { + + FileBufferMouseNeedRefresh = FALSE; + + // + // if mouse position not moved and only mouse action + // so do not need to refresh mouse position + // + if ((FileBuffer.MousePosition.Row == FileBufferBackupVar.MousePosition.Row && + FileBuffer.MousePosition.Column == FileBufferBackupVar.MousePosition.Column) + && EditorMouseAction) { + return EFI_SUCCESS; + } + // + // backup the old screen attributes + // + Orig = MainEditor.ColorAttributes; + New.Colors.Foreground = Orig.Colors.Background; + New.Colors.Background = Orig.Colors.Foreground; + + // + // clear the old mouse position + // + FRow = FileBuffer.LowVisibleRange.Row + FileBufferBackupVar.MousePosition.Row - 2; + + FColumn = FileBuffer.LowVisibleRange.Column + FileBufferBackupVar.MousePosition.Column - 1; + + HasCharacter = TRUE; + if (FRow > FileBuffer.NumLines) { + HasCharacter = FALSE; + } else { + CurrentLine = FileBuffer.CurrentLine; + Line = MoveLine (FRow - FileBuffer.FilePosition.Row); + + if (FColumn > Line->Size) { + HasCharacter = FALSE; + } + + FileBuffer.CurrentLine = CurrentLine; + } + + ShellPrintEx ( + (INT32)FileBufferBackupVar.MousePosition.Column - 1, + (INT32)FileBufferBackupVar.MousePosition.Row - 1, + L" " + ); + + if (HasCharacter) { + Value = (Line->Buffer[FColumn - 1]); + ShellPrintEx ( + (INT32)FileBufferBackupVar.MousePosition.Column - 1, + (INT32)FileBufferBackupVar.MousePosition.Row - 1, + L"%c", + Value + ); + } + // + // set the new mouse position + // + gST->ConOut->SetAttribute (gST->ConOut, New.Data); + + // + // clear the old mouse position + // + FRow = FileBuffer.LowVisibleRange.Row + FileBuffer.MousePosition.Row - 2; + FColumn = FileBuffer.LowVisibleRange.Column + FileBuffer.MousePosition.Column - 1; + + HasCharacter = TRUE; + if (FRow > FileBuffer.NumLines) { + HasCharacter = FALSE; + } else { + CurrentLine = FileBuffer.CurrentLine; + Line = MoveLine (FRow - FileBuffer.FilePosition.Row); + + if (FColumn > Line->Size) { + HasCharacter = FALSE; + } + + FileBuffer.CurrentLine = CurrentLine; + } + + ShellPrintEx ( + (INT32)FileBuffer.MousePosition.Column - 1, + (INT32)FileBuffer.MousePosition.Row - 1, + L" " + ); + + if (HasCharacter) { + Value = Line->Buffer[FColumn - 1]; + ShellPrintEx ( + (INT32)FileBuffer.MousePosition.Column - 1, + (INT32)FileBuffer.MousePosition.Row - 1, + L"%c", + Value + ); + } + // + // end of HasCharacter + // + gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); + } + // + // end of MouseNeedRefresh + // + } + // + // end of MouseSupported + // + return EFI_SUCCESS; +} + +/** + Free all the lines in FileBuffer + Fields affected: + Lines + CurrentLine + NumLines + ListHead + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferFreeLines ( + VOID + ) +{ + LIST_ENTRY *Link; + EFI_EDITOR_LINE *Line; + + // + // free all the lines + // + if (FileBuffer.Lines != NULL) { + + Line = FileBuffer.Lines; + Link = &(Line->Link); + do { + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + Link = Link->ForwardLink; + + // + // free line's buffer and line itself + // + LineFree (Line); + } while (Link != FileBuffer.ListHead); + } + // + // clean the line list related structure + // + FileBuffer.Lines = NULL; + FileBuffer.CurrentLine = NULL; + FileBuffer.NumLines = 0; + + FileBuffer.ListHead->ForwardLink = FileBuffer.ListHead; + FileBuffer.ListHead->BackLink = FileBuffer.ListHead; + + return EFI_SUCCESS; +} + +/** + Cleanup function for FileBuffer. + + @retval EFI_SUCCESS The cleanup was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferCleanup ( + VOID + ) +{ + EFI_STATUS Status; + + SHELL_FREE_NON_NULL (FileBuffer.FileName); + + // + // free all the lines + // + Status = FileBufferFreeLines (); + + SHELL_FREE_NON_NULL (FileBuffer.ListHead); + FileBuffer.ListHead = NULL; + + SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName); + return Status; + +} + +/** + Print a line specified by Line on a row specified by Row of the screen. + + @param[in] Line The line to print. + @param[in] Row The row on the screen to print onto (begin from 1). + + @retval EFI_SUCCESS The printing was successful. +**/ +EFI_STATUS +FileBufferPrintLine ( + IN CONST EFI_EDITOR_LINE *Line, + IN CONST UINTN Row + ) +{ + + CHAR16 *Buffer; + UINTN Limit; + CHAR16 PrintLine[200]; + + // + // print start from correct character + // + Buffer = Line->Buffer + FileBuffer.LowVisibleRange.Column - 1; + + Limit = Line->Size - FileBuffer.LowVisibleRange.Column + 1; + if (Limit > Line->Size) { + Limit = 0; + } + + StrnCpy (PrintLine, Buffer, Limit > MainEditor.ScreenSize.Column ? MainEditor.ScreenSize.Column : Limit); + for (; Limit < MainEditor.ScreenSize.Column; Limit++) { + PrintLine[Limit] = L' '; + } + + PrintLine[MainEditor.ScreenSize.Column] = CHAR_NULL; + + ShellPrintEx ( + 0, + (INT32)Row - 1, + L"%s", + PrintLine + ); + + return EFI_SUCCESS; +} + +/** + Set the cursor position according to FileBuffer.DisplayPosition. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferRestorePosition ( + VOID + ) +{ + // + // set cursor position + // + return (gST->ConOut->SetCursorPosition ( + gST->ConOut, + FileBuffer.DisplayPosition.Column - 1, + FileBuffer.DisplayPosition.Row - 1 + )); +} + +/** + Refresh the screen with whats in the buffer. + + @retval EFI_SUCCESS The refresh was successful. + @retval EFI_LOAD_ERROR There was an error finding what to write. +**/ +EFI_STATUS +EFIAPI +FileBufferRefresh ( + VOID + ) +{ + LIST_ENTRY *Link; + EFI_EDITOR_LINE *Line; + UINTN Row; + + // + // if it's the first time after editor launch, so should refresh + // + if (!EditorFirst) { + // + // no definite required refresh + // and file position displayed on screen has not been changed + // + if (!FileBufferNeedRefresh && + !FileBufferOnlyLineNeedRefresh && + FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row && + FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column + ) { + + FileBufferRestoreMousePosition (); + FileBufferRestorePosition (); + + return EFI_SUCCESS; + } + } + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + // + // only need to refresh current line + // + if (FileBufferOnlyLineNeedRefresh && + FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row && + FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column + ) { + + EditorClearLine (FileBuffer.DisplayPosition.Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row); + FileBufferPrintLine ( + FileBuffer.CurrentLine, + FileBuffer.DisplayPosition.Row + ); + } else { + // + // the whole edit area need refresh + // + + // + // no line + // + if (FileBuffer.Lines == NULL) { + FileBufferRestoreMousePosition (); + FileBufferRestorePosition (); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + return EFI_SUCCESS; + } + // + // get the first line that will be displayed + // + Line = MoveLine (FileBuffer.LowVisibleRange.Row - FileBuffer.FilePosition.Row); + if (Line == NULL) { + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + return EFI_LOAD_ERROR; + } + + Link = &(Line->Link); + Row = 2; + do { + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + // + // print line at row + // + FileBufferPrintLine (Line, Row); + + Link = Link->ForwardLink; + Row++; + } while (Link != FileBuffer.ListHead && Row <= (MainEditor.ScreenSize.Row - 4)); + // + // while not file end and not screen full + // + while (Row <= (MainEditor.ScreenSize.Row - 4)) { + EditorClearLine (Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row); + Row++; + } + } + + FileBufferRestoreMousePosition (); + FileBufferRestorePosition (); + + FileBufferNeedRefresh = FALSE; + FileBufferOnlyLineNeedRefresh = FALSE; + + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; +} + +/** + Create a new line and append it to the line list. + Fields affected: + NumLines + Lines + + @retval NULL The create line failed. + @return The line created. +**/ +EFI_EDITOR_LINE * +EFIAPI +FileBufferCreateLine ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + + // + // allocate a line structure + // + Line = AllocateZeroPool (sizeof (EFI_EDITOR_LINE)); + if (Line == NULL) { + return NULL; + } + // + // initialize the structure + // + Line->Signature = LINE_LIST_SIGNATURE; + Line->Size = 0; + Line->TotalSize = 0; + Line->Type = NewLineTypeDefault; + + // + // initial buffer of the line is "\0" + // + ASSERT(CHAR_NULL == CHAR_NULL); + Line->Buffer = CatSPrint (NULL, L"\0"); + if (Line->Buffer == NULL) { + return NULL; + } + + FileBuffer.NumLines++; + + // + // insert the line into line list + // + InsertTailList (FileBuffer.ListHead, &Line->Link); + + if (FileBuffer.Lines == NULL) { + FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + } + + return Line; +} + +/** + Set FileName field in FileBuffer. + + @param Str The file name to set. + + @retval EFI_SUCCESS The filename was successfully set. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER Str is not a valid filename. +**/ +EFI_STATUS +EFIAPI +FileBufferSetFileName ( + IN CONST CHAR16 *Str + ) +{ + // + // Verify the parameters + // + if (!IsValidFileName(Str)) { + return (EFI_INVALID_PARAMETER); + } + // + // free the old file name + // + SHELL_FREE_NON_NULL (FileBuffer.FileName); + + // + // Allocate and set the new name + // + FileBuffer.FileName = CatSPrint (NULL, L"%s", Str); + if (FileBuffer.FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} +/** + Free the existing file lines and reset the modified flag. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferFree ( + VOID + ) +{ + // + // free all the lines + // + FileBufferFreeLines (); + FileBuffer.FileModified = FALSE; + + return EFI_SUCCESS; +} + + +/** + Read a file from disk into the FileBuffer. + + @param[in] FileName The filename to read. + @param[in] Recover TRUE if is for recover mode, no information printouts. + + @retval EFI_SUCCESS The load was successful. + @retval EFI_LOAD_ERROR The load failed. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER FileName is a directory. +**/ +EFI_STATUS +EFIAPI +FileBufferRead ( + IN CONST CHAR16 *FileName, + IN CONST BOOLEAN Recover + ) +{ + EFI_EDITOR_LINE *Line; + EE_NEWLINE_TYPE Type; + UINTN LoopVar1; + UINTN LoopVar2; + UINTN LineSize; + VOID *Buffer; + CHAR16 *UnicodeBuffer; + UINT8 *AsciiBuffer; + UINTN FileSize; + SHELL_FILE_HANDLE FileHandle; + BOOLEAN CreateFile; + EFI_STATUS Status; + UINTN LineSizeBackup; + EFI_FILE_INFO *Info; + + Line = NULL; + LoopVar1 = 0; + FileSize = 0; + UnicodeBuffer = NULL; + Type = NewLineTypeDefault; + FileHandle = NULL; + CreateFile = FALSE; + + // + // in this function, when you return error ( except EFI_OUT_OF_RESOURCES ) + // you should set status string via StatusBarSetStatusString(L"blah") + // since this function maybe called before the editorhandleinput loop + // so any error will cause editor return + // so if you want to print the error status + // you should set the status string + // + + // + // try to open the file + // + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0); + + if (!EFI_ERROR(Status)) { + CreateFile = FALSE; + if (FileHandle == NULL) { + StatusBarSetStatusString (L"Disk Error"); + return EFI_LOAD_ERROR; + } + + Info = ShellGetFileInfo(FileHandle); + + if (Info->Attribute & EFI_FILE_DIRECTORY) { + StatusBarSetStatusString (L"Directory Can Not Be Edited"); + FreePool (Info); + return EFI_INVALID_PARAMETER; + } + + if (Info->Attribute & EFI_FILE_READ_ONLY) { + FileBuffer.ReadOnly = TRUE; + } else { + FileBuffer.ReadOnly = FALSE; + } + // + // get file size + // + FileSize = (UINTN) Info->FileSize; + + FreePool (Info); + } else if (Status == EFI_NOT_FOUND) { + // + // file not exists. add create and try again + // + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + if (EFI_ERROR (Status)) { + if (Status == EFI_WRITE_PROTECTED || + Status == EFI_ACCESS_DENIED || + Status == EFI_NO_MEDIA || + Status == EFI_MEDIA_CHANGED + ) { + StatusBarSetStatusString (L"Access Denied"); + } else if (Status == EFI_DEVICE_ERROR || Status == EFI_VOLUME_CORRUPTED || Status == EFI_VOLUME_FULL) { + StatusBarSetStatusString (L"Disk Error"); + } else { + StatusBarSetStatusString (L"Invalid File Name or Current-working-directory"); + } + + return Status; + } else { + // + // it worked. now delete it and move on with the name (now validated) + // + Status = ShellDeleteFile (&FileHandle); + if (Status == EFI_WARN_DELETE_FAILURE) { + Status = EFI_ACCESS_DENIED; + } + FileHandle = NULL; + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Access Denied"); + return Status; + } + } + // + // file doesn't exist, so set CreateFile to TRUE + // + CreateFile = TRUE; + FileBuffer.ReadOnly = FALSE; + + // + // all the check ends + // so now begin to set file name, free lines + // + if (StrCmp (FileName, FileBuffer.FileName) != 0) { + FileBufferSetFileName (FileName); + } + // + // free the old lines + // + FileBufferFree (); + + } + // + // the file exists + // + if (!CreateFile) { + // + // allocate buffer to read file + // + Buffer = AllocateZeroPool (FileSize); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // read file into Buffer + // + Status = ShellReadFile (FileHandle, &FileSize, Buffer); + ShellCloseFile(&FileHandle); + FileHandle = NULL; + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read File Failed"); + SHELL_FREE_NON_NULL (Buffer); + return EFI_LOAD_ERROR; + } + // + // nothing in this file + // + if (FileSize == 0) { + SHELL_FREE_NON_NULL (Buffer); + // + // since has no head, so only can be an ASCII file + // + FileBuffer.FileType = FileTypeAscii; + + goto Done; + } + + AsciiBuffer = Buffer; + + if (FileSize < 2) { + // + // size < Unicode file header, so only can be ASCII file + // + FileBuffer.FileType = FileTypeAscii; + } else { + // + // Unicode file + // + if (*(UINT16 *) Buffer == EFI_UNICODE_BYTE_ORDER_MARK) { + // + // Unicode file's size should be even + // + if ((FileSize % 2) != 0) { + StatusBarSetStatusString (L"File Format Wrong"); + SHELL_FREE_NON_NULL (Buffer); + return EFI_LOAD_ERROR; + } + + FileSize /= 2; + + FileBuffer.FileType = FileTypeUnicode; + UnicodeBuffer = Buffer; + + // + // pass this 0xff and 0xfe + // + UnicodeBuffer++; + FileSize--; + } else { + FileBuffer.FileType = FileTypeAscii; + } + // + // end of AsciiBuffer == + // + } + // + // end of FileSize < 2 + // all the check ends + // so now begin to set file name, free lines + // + if (StrCmp (FileName, FileBuffer.FileName) != 0) { + FileBufferSetFileName (FileName); + } + + // + // free the old lines + // + FileBufferFree (); + + // + // parse file content line by line + // + for (LoopVar1 = 0; LoopVar1 < FileSize; LoopVar1++) { + Type = NewLineTypeUnknown; + + for (LineSize = LoopVar1; LineSize < FileSize; LineSize++) { + if (FileBuffer.FileType == FileTypeAscii) { + if (AsciiBuffer[LineSize] == CHAR_CARRIAGE_RETURN) { + Type = NewLineTypeCarriageReturn; + + // + // has LF following + // + if (LineSize < FileSize - 1) { + if (AsciiBuffer[LineSize + 1] == CHAR_LINEFEED) { + Type = NewLineTypeCarriageReturnLineFeed; + } + } + + break; + } else if (AsciiBuffer[LineSize] == CHAR_LINEFEED) { + Type = NewLineTypeLineFeed; + + // + // has CR following + // + if (LineSize < FileSize - 1) { + if (AsciiBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) { + Type = NewLineTypeLineFeedCarriageReturn; + } + } + + break; + } + } else { + if (UnicodeBuffer[LineSize] == CHAR_CARRIAGE_RETURN) { + Type = NewLineTypeCarriageReturn; + + // + // has LF following + // + if (LineSize < FileSize - 1) { + if (UnicodeBuffer[LineSize + 1] == CHAR_LINEFEED) { + Type = NewLineTypeCarriageReturnLineFeed; + } + } + + break; + } else if (UnicodeBuffer[LineSize] == CHAR_LINEFEED) { + Type = NewLineTypeLineFeed; + + // + // has CR following + // + if (LineSize < FileSize - 1) { + if (UnicodeBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) { + Type = NewLineTypeLineFeedCarriageReturn; + } + } + + break; + } + } + // + // endif == ASCII + // + } + // + // end of for LineSize + // + // if the type is wrong, then exit + // + if (Type == NewLineTypeUnknown) { + // + // Now if Type is NewLineTypeUnknown, it should be file end + // + Type = NewLineTypeDefault; + } + + LineSizeBackup = LineSize; + + // + // create a new line + // + Line = FileBufferCreateLine (); + if (Line == NULL) { + SHELL_FREE_NON_NULL (Buffer); + return EFI_OUT_OF_RESOURCES; + } + // + // calculate file length + // + LineSize -= LoopVar1; + + // + // Unicode and one CHAR_NULL + // + SHELL_FREE_NON_NULL (Line->Buffer); + Line->Buffer = AllocateZeroPool (LineSize * 2 + 2); + + if (Line->Buffer == NULL) { + RemoveEntryList (&Line->Link); + return EFI_OUT_OF_RESOURCES; + } + // + // copy this line to Line->Buffer + // + for (LoopVar2 = 0; LoopVar2 < LineSize; LoopVar2++) { + if (FileBuffer.FileType == FileTypeAscii) { + Line->Buffer[LoopVar2] = (CHAR16) AsciiBuffer[LoopVar1]; + } else { + Line->Buffer[LoopVar2] = UnicodeBuffer[LoopVar1]; + } + + LoopVar1++; + } + // + // LoopVar1 now points to where CHAR_CARRIAGE_RETURN or CHAR_LINEFEED; + // + Line->Buffer[LineSize] = 0; + + Line->Size = LineSize; + Line->TotalSize = LineSize; + Line->Type = Type; + + if (Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) { + LoopVar1++; + } + + // + // last character is a return, SO create a new line + // + if (((Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) && LineSizeBackup == FileSize - 2) || + ((Type == NewLineTypeLineFeed || Type == NewLineTypeCarriageReturn) && LineSizeBackup == FileSize - 1) + ) { + Line = FileBufferCreateLine (); + if (Line == NULL) { + SHELL_FREE_NON_NULL (Buffer); + return EFI_OUT_OF_RESOURCES; + } + } + // + // end of if + // + } + // + // end of LoopVar1 + // + SHELL_FREE_NON_NULL (Buffer); + + } + // + // end of if CreateFile + // +Done: + + FileBuffer.DisplayPosition.Row = 2; + FileBuffer.DisplayPosition.Column = 1; + FileBuffer.LowVisibleRange.Row = 1; + FileBuffer.LowVisibleRange.Column = 1; + FileBuffer.FilePosition.Row = 1; + FileBuffer.FilePosition.Column = 1; + FileBuffer.MousePosition.Row = 2; + FileBuffer.MousePosition.Column = 1; + + if (!Recover) { + UnicodeBuffer = CatSPrint (NULL, L"%d Lines Read", FileBuffer.NumLines); + if (UnicodeBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (UnicodeBuffer); + FreePool (UnicodeBuffer); + } +/* + // + // check whether we have fs?: in filename + // + LoopVar1 = 0; + FSMappingPtr = NULL; + while (FileName[LoopVar1] != 0) { + if (FileName[LoopVar1] == L':') { + FSMappingPtr = &FileName[LoopVar1]; + break; + } + + LoopVar1++; + } + + if (FSMappingPtr == NULL) { + CurDir = ShellGetCurrentDir (NULL); + } else { + LoopVar1 = 0; + LoopVar2 = 0; + while (FileName[LoopVar1] != 0) { + if (FileName[LoopVar1] == L':') { + break; + } + + FSMapping[LoopVar2++] = FileName[LoopVar1]; + + LoopVar1++; + } + + FSMapping[LoopVar2] = 0; + CurDir = ShellGetCurrentDir (FSMapping); + } + + if (CurDir != NULL) { + for (LoopVar1 = 0; LoopVar1 < StrLen (CurDir) && CurDir[LoopVar1] != ':'; LoopVar1++); + + CurDir[LoopVar1] = 0; + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ShellGetMap (CurDir); + FreePool (CurDir); + } else { + return EFI_LOAD_ERROR; + } + + Status = LibDevicePathToInterface ( + &gEfiSimpleFileSystemProtocolGuid, + DevicePath, + (VOID **) &Vol + ); + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + + Status = Vol->OpenVolume (Vol, &RootFs); + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + // + // Get volume information of file system + // + Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + 100; + VolumeInfo = (EFI_FILE_SYSTEM_INFO *) AllocateZeroPool (Size); + Status = RootFs->GetInfo (RootFs, &gEfiFileSystemInfoGuid, &Size, VolumeInfo); + if (EFI_ERROR (Status)) { + RootFs->Close (RootFs); + return EFI_LOAD_ERROR; + } + + if (VolumeInfo->ReadOnly) { + StatusBarSetStatusString (L"WARNING: Volume Read Only"); + } + + FreePool (VolumeInfo); + RootFs->Close (RootFs); + } +// +*/ + // + // has line + // + if (FileBuffer.Lines != 0) { + FileBuffer.CurrentLine = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + } else { + // + // create a dummy line + // + Line = FileBufferCreateLine (); + if (Line == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + FileBuffer.CurrentLine = Line; + } + + FileBuffer.FileModified = FALSE; + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + FileBufferMouseNeedRefresh = TRUE; + + + return EFI_SUCCESS; +} + +/** + According to FileBuffer.NewLineType & FileBuffer.FileType, + get the return buffer and size. + + @param[in] Type The type of line. + @param[out] Buffer The buffer to fill. + @param[out] Size The amount of the buffer used on return. +**/ +VOID +EFIAPI +GetNewLine ( + IN CONST EE_NEWLINE_TYPE Type, + OUT CHAR8 *Buffer, + OUT UINT8 *Size + ) +{ + UINT8 NewLineSize; + + // + // give new line buffer, + // and will judge unicode or ascii + // + NewLineSize = 0; + + // + // not legal new line type + // + if (Type != NewLineTypeLineFeed && Type != NewLineTypeCarriageReturn && Type != NewLineTypeCarriageReturnLineFeed && Type != NewLineTypeLineFeedCarriageReturn) { + *Size = 0; + return ; + } + // + // use_cr: give 0x0d + // + if (Type == NewLineTypeCarriageReturn) { + if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { + Buffer[0] = 0x0d; + Buffer[1] = 0; + NewLineSize = 2; + } else { + Buffer[0] = 0x0d; + NewLineSize = 1; + } + + *Size = NewLineSize; + return ; + } + // + // use_lf: give 0x0a + // + if (Type == NewLineTypeLineFeed) { + if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { + Buffer[0] = 0x0a; + Buffer[1] = 0; + NewLineSize = 2; + } else { + Buffer[0] = 0x0a; + NewLineSize = 1; + } + + *Size = NewLineSize; + return ; + } + // + // use_crlf: give 0x0d 0x0a + // + if (Type == NewLineTypeCarriageReturnLineFeed) { + if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { + Buffer[0] = 0x0d; + Buffer[1] = 0; + Buffer[2] = 0x0a; + Buffer[3] = 0; + + NewLineSize = 4; + } else { + Buffer[0] = 0x0d; + Buffer[1] = 0x0a; + NewLineSize = 2; + } + + *Size = NewLineSize; + return ; + } + // + // use_lfcr: give 0x0a 0x0d + // + if (Type == NewLineTypeLineFeedCarriageReturn) { + if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { + Buffer[0] = 0x0a; + Buffer[1] = 0; + Buffer[2] = 0x0d; + Buffer[3] = 0; + + NewLineSize = 4; + } else { + Buffer[0] = 0x0a; + Buffer[1] = 0x0d; + NewLineSize = 2; + } + + *Size = NewLineSize; + return ; + } + +} + +/** + Change a Unicode string to an ASCII string. + + @param[in] UStr The Unicode string. + @param[in] Lenght The maximum size of AStr. + @param[out] AStr ASCII string to pass out. + + @return The actuall length. +**/ +UINTN +EFIAPI +UnicodeToAscii ( + IN CONST CHAR16 *UStr, + IN CONST UINTN Length, + OUT CHAR8 *AStr + ) +{ + UINTN Index; + + // + // just buffer copy, not character copy + // + for (Index = 0; Index < Length; Index++) { + *AStr++ = (CHAR8) *UStr++; + } + + return Index; +} + +/** + Save lines in FileBuffer to disk + + @param[in] FileName The file name for writing. + + @retval EFI_SUCCESS Data was written. + @retval EFI_LOAD_ERROR + @retval EFI_OUT_OF_RESOURCES There were not enough resources to write the file. +**/ +EFI_STATUS +EFIAPI +FileBufferSave ( + IN CONST CHAR16 *FileName + ) +{ + SHELL_FILE_HANDLE FileHandle; + LIST_ENTRY *Link; + EFI_EDITOR_LINE *Line; + CHAR16 *Str; + + EFI_STATUS Status; + UINTN Length; + UINTN NumLines; + CHAR8 NewLineBuffer[4]; + UINT8 NewLineSize; + + EFI_FILE_INFO *Info; + + UINT64 Attribute; + + EE_NEWLINE_TYPE Type; + + UINTN TotalSize; + // + // 2M + // + CHAR8 *Cache; + UINTN LeftSize; + UINTN Size; + CHAR8 *Ptr; + + Length = 0; + // + // 2M + // + TotalSize = 0x200000; + + Attribute = 0; + + + + // + // if is the old file + // + if (StrCmp (FileName, FileBuffer.FileName) == 0) { + // + // file has not been modified + // + if (!FileBuffer.FileModified) { + return EFI_SUCCESS; + } + + // + // if file is read-only, set error + // + if (FileBuffer.ReadOnly) { + StatusBarSetStatusString (L"Read Only File Can Not Be Saved"); + return EFI_SUCCESS; + } + } + + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); + + if (!EFI_ERROR (Status)) { + Info = ShellGetFileInfo(FileHandle); + + if (Info != NULL && Info->Attribute & EFI_FILE_DIRECTORY) { + StatusBarSetStatusString (L"Directory Can Not Be Saved"); + ShellCloseFile(FileHandle); + FreePool(Info); + return EFI_LOAD_ERROR; + } + + if (Info != NULL) { + Attribute = Info->Attribute & ~EFI_FILE_READ_ONLY; + FreePool(Info); + } + + // + // if file exits, so delete it + // + Status = ShellDeleteFile (&FileHandle); + if (EFI_ERROR (Status) || Status == EFI_WARN_DELETE_FAILURE) { + StatusBarSetStatusString (L"Write File Failed"); + return EFI_LOAD_ERROR; + } + } + + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, Attribute); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Create File Failed"); + return EFI_LOAD_ERROR; + } + + // + // if file is Unicode file, write Unicode header to it. + // + if (FileBuffer.FileType == FileTypeUnicode) { + Length = 2; + Status = ShellWriteFile (FileHandle, &Length, (VOID*)&gUnicodeFileTag); + if (EFI_ERROR (Status)) { + ShellDeleteFile (&FileHandle); + return EFI_LOAD_ERROR; + } + } + + Cache = AllocateZeroPool (TotalSize); + if (Cache == NULL) { + ShellDeleteFile (&FileHandle); + return EFI_OUT_OF_RESOURCES; + } + + // + // write all the lines back to disk + // + NumLines = 0; + Type = NewLineTypeCarriageReturnLineFeed; + + Ptr = Cache; + LeftSize = TotalSize; + + for (Link = FileBuffer.ListHead->ForwardLink; Link != FileBuffer.ListHead; Link = Link->ForwardLink) { + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + if (Line->Type != NewLineTypeDefault) { + Type = Line->Type; + } + // + // newline character is at most 4 bytes ( two Unicode characters ) + // + Length = 4; + if (Line->Buffer != NULL && Line->Size != 0) { + if (FileBuffer.FileType == FileTypeAscii) { + Length += Line->Size; + } else { + Length += (Line->Size * 2); + } + // + // end if FileTypeAscii + // + } + + // + // no cache room left, so write cache to disk + // + if (LeftSize < Length) { + Size = TotalSize - LeftSize; + Status = ShellWriteFile (FileHandle, &Size, Cache); + if (EFI_ERROR (Status)) { + ShellDeleteFile (&FileHandle); + FreePool (Cache); + return EFI_LOAD_ERROR; + } + Ptr = Cache; + LeftSize = TotalSize; + } + + if (Line->Buffer != NULL && Line->Size != 0) { + if (FileBuffer.FileType == FileTypeAscii) { + UnicodeToAscii (Line->Buffer, Line->Size, Ptr); + Length = Line->Size; + } else { + Length = (Line->Size * 2); + CopyMem (Ptr, (CHAR8 *) Line->Buffer, Length); + } + // + // end if FileTypeAscii + // + Ptr += Length; + LeftSize -= Length; + + } + // + // end of if Line -> Buffer != NULL && Line -> Size != 0 + // + // if not the last line , write return buffer to disk + // + if (Link->ForwardLink != FileBuffer.ListHead) { + GetNewLine (Type, NewLineBuffer, &NewLineSize); + CopyMem (Ptr, (CHAR8 *) NewLineBuffer, NewLineSize); + + Ptr += NewLineSize; + LeftSize -= NewLineSize; + } + + NumLines++; + } + + if (TotalSize != LeftSize) { + Size = TotalSize - LeftSize; + Status = ShellWriteFile (FileHandle, &Size, Cache); + if (EFI_ERROR (Status)) { + ShellDeleteFile (&FileHandle); + FreePool (Cache); + return EFI_LOAD_ERROR; + } + } + + FreePool (Cache); + + ShellCloseFile(&FileHandle); + + FileBuffer.FileModified = FALSE; + + // + // set status string + // + Str = CatSPrint (NULL, L"%d Lines Wrote", NumLines); + if (Str == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (Str); + SHELL_FREE_NON_NULL (Str); + + // + // now everything is ready , you can set the new file name to filebuffer + // + if (StrCmp (FileName, FileBuffer.FileName) != 0) { + // + // not the same + // + FileBufferSetFileName (FileName); + if (FileBuffer.FileName == NULL) { + ShellDeleteFile (&FileHandle); + return EFI_OUT_OF_RESOURCES; + } + } + + FileBuffer.ReadOnly = FALSE; + return EFI_SUCCESS; +} + +/** + Scroll cursor to left 1 character position. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferScrollLeft ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = FileBuffer.CurrentLine; + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.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 != FileBuffer.ListHead) { + FRow--; + Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + FCol = Line->Size + 1; + } else { + return EFI_SUCCESS; + } + } else { + // + // if not at start of this line, just move to previous column + // + FCol--; + } + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Delete a char in line + + @param[in,out] Line The line to delete in. + @param[in] Pos Position to delete the char at ( start from 0 ). +**/ +VOID +EFIAPI +LineDeleteAt ( + IN OUT EFI_EDITOR_LINE *Line, + IN UINTN Pos + ) +{ + UINTN Index; + + // + // move the latter characters front + // + for (Index = Pos - 1; Index < Line->Size; Index++) { + Line->Buffer[Index] = Line->Buffer[Index + 1]; + } + + Line->Size--; +} + +/** + Concatenate Src into Dest. + + @param[in,out] Dest Destination string + @param[in] Src Src String. +**/ +VOID +EFIAPI +LineCat ( + IN OUT EFI_EDITOR_LINE *Dest, + IN EFI_EDITOR_LINE *Src + ) +{ + CHAR16 *Str; + UINTN Size; + + Size = Dest->Size; + + Dest->Buffer[Size] = 0; + + // + // concatenate the two strings + // + Str = CatSPrint (NULL, L"%s%s", Dest->Buffer, Src->Buffer); + if (Str == NULL) { + Dest->Buffer = NULL; + return ; + } + + Dest->Size = Size + Src->Size; + Dest->TotalSize = Dest->Size; + + FreePool (Dest->Buffer); + FreePool (Src->Buffer); + + // + // put str to dest->buffer + // + Dest->Buffer = Str; +} + +/** + Delete the previous character. + + @retval EFI_SUCCESS The delete was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferDoBackspace ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + EFI_EDITOR_LINE *End; + LIST_ENTRY *Link; + UINTN FileColumn; + + FileColumn = FileBuffer.FilePosition.Column; + + Line = FileBuffer.CurrentLine; + + // + // the first column + // + if (FileColumn == 1) { + // + // the first row + // + if (FileBuffer.FilePosition.Row == 1) { + return EFI_SUCCESS; + } + + FileBufferScrollLeft (); + + Line = FileBuffer.CurrentLine; + Link = Line->Link.ForwardLink; + End = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + // + // concatenate this line with previous line + // + LineCat (Line, End); + if (Line->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // remove End from line list + // + RemoveEntryList (&End->Link); + FreePool (End); + + FileBuffer.NumLines--; + + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + + } else { + // + // just delete the previous character + // + LineDeleteAt (Line, FileColumn - 1); + FileBufferScrollLeft (); + FileBufferOnlyLineNeedRefresh = TRUE; + } + + if (!FileBuffer.FileModified) { + FileBuffer.FileModified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Add a return into line at current position. + + @retval EFI_SUCCESS The insetrion of the character was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferDoReturn ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + EFI_EDITOR_LINE *NewLine; + UINTN FileColumn; + UINTN Index; + CHAR16 *Buffer; + UINTN Row; + UINTN Col; + + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + + Line = FileBuffer.CurrentLine; + + FileColumn = FileBuffer.FilePosition.Column; + + NewLine = AllocateZeroPool (sizeof (EFI_EDITOR_LINE)); + if (NewLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NewLine->Signature = LINE_LIST_SIGNATURE; + NewLine->Size = Line->Size - FileColumn + 1; + NewLine->TotalSize = NewLine->Size; + NewLine->Buffer = CatSPrint (NULL, L"\0"); + if (NewLine->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NewLine->Type = NewLineTypeDefault; + + if (NewLine->Size > 0) { + // + // UNICODE + CHAR_NULL + // + Buffer = AllocateZeroPool (2 * (NewLine->Size + 1)); + if (Buffer == NULL) { + FreePool (NewLine->Buffer); + FreePool (NewLine); + return EFI_OUT_OF_RESOURCES; + } + + FreePool (NewLine->Buffer); + + NewLine->Buffer = Buffer; + + for (Index = 0; Index < NewLine->Size; Index++) { + NewLine->Buffer[Index] = Line->Buffer[Index + FileColumn - 1]; + } + + NewLine->Buffer[NewLine->Size] = CHAR_NULL; + + Line->Buffer[FileColumn - 1] = CHAR_NULL; + Line->Size = FileColumn - 1; + } + // + // increase NumLines + // + FileBuffer.NumLines++; + + // + // insert it into the correct position of line list + // + NewLine->Link.BackLink = &(Line->Link); + NewLine->Link.ForwardLink = Line->Link.ForwardLink; + Line->Link.ForwardLink->BackLink = &(NewLine->Link); + Line->Link.ForwardLink = &(NewLine->Link); + + // + // move cursor to the start of next line + // + Row = FileBuffer.FilePosition.Row + 1; + Col = 1; + + FileBufferMovePosition (Row, Col); + + // + // set file is modified + // + if (!FileBuffer.FileModified) { + FileBuffer.FileModified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Delete current character from current line. This is the effect caused + by the 'del' key. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FileBufferDoDelete ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + EFI_EDITOR_LINE *Next; + LIST_ENTRY *Link; + UINTN FileColumn; + + Line = FileBuffer.CurrentLine; + FileColumn = FileBuffer.FilePosition.Column; + + // + // the last column + // + if (FileColumn >= Line->Size + 1) { + // + // the last line + // + if (Line->Link.ForwardLink == FileBuffer.ListHead) { + return EFI_SUCCESS; + } + // + // since last character, + // so will add the next line to this line + // + Link = Line->Link.ForwardLink; + Next = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + LineCat (Line, Next); + if (Line->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + RemoveEntryList (&Next->Link); + FreePool (Next); + + FileBuffer.NumLines--; + + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + + } else { + // + // just delete current character + // + LineDeleteAt (Line, FileColumn); + FileBufferOnlyLineNeedRefresh = TRUE; + } + + if (!FileBuffer.FileModified) { + FileBuffer.FileModified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Scroll cursor to right 1 character. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferScrollRight ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = FileBuffer.CurrentLine; + if (Line->Buffer == NULL) { + return EFI_SUCCESS; + } + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // if already at end of this line, scroll it to the start of next line + // + if (FCol > Line->Size) { + // + // has next line + // + if (Line->Link.ForwardLink != FileBuffer.ListHead) { + FRow++; + FCol = 1; + } else { + return EFI_SUCCESS; + } + } else { + // + // if not at end of this line, just move to next column + // + FCol++; + } + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Insert a char into line + + + @param[in] Line The line to insert into. + @param[in] Char The char to insert. + @param[in] Pos The position to insert the char at ( start from 0 ). + @param[in] StrSize The current string size ( include CHAR_NULL ),unit is Unicode character. + + @return The new string size ( include CHAR_NULL ) ( unit is Unicode character ). +**/ +UINTN +EFIAPI +LineStrInsert ( + IN EFI_EDITOR_LINE *Line, + IN CHAR16 Char, + IN UINTN Pos, + IN UINTN StrSize + ) +{ + UINTN Index; + CHAR16 *TempStringPtr; + CHAR16 *Str; + + Index = (StrSize) * 2; + + Str = Line->Buffer; + + // + // do not have free space + // + if (Line->TotalSize <= Line->Size) { + Str = ReallocatePool (Index, Index + 16, Str); + if (Str == NULL) { + return 0; + } + + Line->TotalSize += 8; + } + // + // move the later part of the string one character right + // + TempStringPtr = Str; + for (Index = StrSize; Index > Pos; Index--) { + TempStringPtr[Index] = TempStringPtr[Index - 1]; + } + // + // insert char into it. + // + TempStringPtr[Index] = Char; + + Line->Buffer = Str; + Line->Size++; + + return StrSize + 1; +} + +/** + Add a character to the current line. + + @param[in] Char The Character to input. + + @retval EFI_SUCCESS The input was succesful. +**/ +EFI_STATUS +EFIAPI +FileBufferAddChar ( + IN CHAR16 Char + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FilePos; + + Line = FileBuffer.CurrentLine; + + // + // only needs to refresh current line + // + FileBufferOnlyLineNeedRefresh = TRUE; + + // + // when is insert mode, or cursor is at end of this line, + // so insert this character + // or replace the character. + // + FilePos = FileBuffer.FilePosition.Column - 1; + if (FileBuffer.ModeInsert || FilePos + 1 > Line->Size) { + LineStrInsert (Line, Char, FilePos, Line->Size + 1); + } else { + Line->Buffer[FilePos] = Char; + } + // + // move cursor to right + // + FileBufferScrollRight (); + + if (!FileBuffer.FileModified) { + FileBuffer.FileModified = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Handles inputs from characters (ASCII key + Backspace + return) + + @param[in] Char The input character. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR There was an error. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferDoCharInput ( + IN CONST CHAR16 Char + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + switch (Char) { + case CHAR_NULL: + break; + + case CHAR_BACKSPACE: + Status = FileBufferDoBackspace (); + break; + + case CHAR_TAB: + // + // Tabs are ignored + // + break; + + case CHAR_LINEFEED: + case CHAR_CARRIAGE_RETURN: + Status = FileBufferDoReturn (); + break; + + default: + // + // DEAL WITH ASCII CHAR, filter out thing like ctrl+f + // + if (Char > 127 || Char < 32) { + Status = StatusBarSetStatusString (L"Unknown Command"); + } else { + Status = FileBufferAddChar (Char); + } + + break; + + } + + return Status; +} + +/** + Scroll cursor to the next line. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferScrollDown ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = FileBuffer.CurrentLine; + if (Line->Buffer == NULL) { + return EFI_SUCCESS; + } + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // has next line + // + if (Line->Link.ForwardLink != FileBuffer.ListHead) { + FRow++; + Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + // + // if the next line is not that long, so move to end of next line + // + if (FCol > Line->Size) { + FCol = Line->Size + 1; + } + + } else { + return EFI_SUCCESS; + } + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Scroll the cursor to previous line. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferScrollUp ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = FileBuffer.CurrentLine; + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // has previous line + // + if (Line->Link.BackLink != FileBuffer.ListHead) { + FRow--; + Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + // + // if previous line is not that long, so move to the end of previous line + // + if (FCol > Line->Size) { + FCol = Line->Size + 1; + } + + } else { + return EFI_SUCCESS; + } + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to next page. + + @retval EFI_SUCCESS The operation wa successful. +**/ +EFI_STATUS +EFIAPI +FileBufferPageDown ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + UINTN Gap; + + Line = FileBuffer.CurrentLine; + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // has next page + // + if (FileBuffer.NumLines >= FRow + (MainEditor.ScreenSize.Row - 5)) { + Gap = (MainEditor.ScreenSize.Row - 5); + } else { + // + // MOVE CURSOR TO LAST LINE + // + Gap = FileBuffer.NumLines - FRow; + } + // + // get correct line + // + Line = MoveLine (Gap); + + // + // if that line, is not that long, so move to the end of that line + // + if (FCol > Line->Size) { + FCol = Line->Size + 1; + } + + FRow += Gap; + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to previous screen. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferPageUp ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + UINTN Gap; + INTN Retreat; + + Line = FileBuffer.CurrentLine; + + FRow = FileBuffer.FilePosition.Row; + FCol = FileBuffer.FilePosition.Column; + + // + // has previous page + // + if (FRow > (MainEditor.ScreenSize.Row - 5)) { + Gap = (MainEditor.ScreenSize.Row - 5); + } else { + // + // the first line of file will displayed on the first line of screen + // + Gap = FRow - 1; + } + + Retreat = Gap; + Retreat = -Retreat; + + // + // get correct line + // + Line = MoveLine (Retreat); + + // + // if that line is not that long, so move to the end of that line + // + if (FCol > Line->Size) { + FCol = Line->Size + 1; + } + + FRow -= Gap; + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Scroll cursor to end of the current line. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferEnd ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + + Line = FileBuffer.CurrentLine; + + FRow = FileBuffer.FilePosition.Row; + + // + // goto the last column of the line + // + FCol = Line->Size + 1; + + FileBufferMovePosition (FRow, FCol); + + return EFI_SUCCESS; +} + +/** + Dispatch input to different handler + @param[in] Key The input key. One of: + ASCII KEY + Backspace/Delete + Return + Direction key: up/down/left/right/pgup/pgdn + Home/End + INS + + @retval EFI_SUCCESS The dispatch was done successfully. + @retval EFI_LOAD_ERROR The dispatch was not successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferHandleInput ( + IN CONST EFI_INPUT_KEY *Key + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + switch (Key->ScanCode) { + // + // ordinary key input + // + case SCAN_NULL: + if (!FileBuffer.ReadOnly) { + Status = FileBufferDoCharInput (Key->UnicodeChar); + } else { + Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + } + + break; + + // + // up arrow + // + case SCAN_UP: + Status = FileBufferScrollUp (); + break; + + // + // down arrow + // + case SCAN_DOWN: + Status = FileBufferScrollDown (); + break; + + // + // right arrow + // + case SCAN_RIGHT: + Status = FileBufferScrollRight (); + break; + + // + // left arrow + // + case SCAN_LEFT: + Status = FileBufferScrollLeft (); + break; + + // + // page up + // + case SCAN_PAGE_UP: + Status = FileBufferPageUp (); + break; + + // + // page down + // + case SCAN_PAGE_DOWN: + Status = FileBufferPageDown (); + break; + + // + // delete + // + case SCAN_DELETE: + if (!FileBuffer.ReadOnly) { + Status = FileBufferDoDelete (); + } else { + Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + } + + break; + + // + // home + // + case SCAN_HOME: + FileBufferMovePosition (FileBuffer.FilePosition.Row, 1); + Status = EFI_SUCCESS; + break; + + // + // end + // + case SCAN_END: + Status = FileBufferEnd (); + break; + + // + // insert + // + case SCAN_INSERT: + FileBuffer.ModeInsert = (BOOLEAN)!FileBuffer.ModeInsert; + Status = EFI_SUCCESS; + break; + + default: + Status = StatusBarSetStatusString (L"Unknown Command"); + break; + } + + return Status; +} + +/** + Check user specified FileRow is above current screen. + + @param[in] FileRow The 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 +EFIAPI +AboveCurrentScreen ( + IN UINTN FileRow + ) +{ + // + // if is to the above of the screen + // + if (FileRow < FileBuffer.LowVisibleRange.Row) { + return TRUE; + } + + return FALSE; +} + +/** + Check user specified FileRow is under current screen. + + @param[in] FileRow The 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 +EFIAPI +UnderCurrentScreen ( + IN UINTN FileRow + ) +{ + // + // if is to the under of the screen + // + if (FileRow > FileBuffer.LowVisibleRange.Row + (MainEditor.ScreenSize.Row - 5) - 1) { + return TRUE; + } + + return FALSE; +} + +/** + Check user specified FileCol is left to current screen. + + @param[in] FileCol The column of file position ( start from 1 ). + + @retval TRUE It is to the left. + @retval FALSE It is not to the left. +**/ +BOOLEAN +EFIAPI +LeftCurrentScreen ( + IN UINTN FileCol + ) +{ + // + // if is to the left of the screen + // + if (FileCol < FileBuffer.LowVisibleRange.Column) { + return TRUE; + } + + return FALSE; +} + +/** + Check user specified FileCol is right to current screen. + + @param[in] FileCol The column of file position ( start from 1 ). + + @retval TRUE It is to the right. + @retval FALSE It is not to the right. +**/ +BOOLEAN +EFIAPI +RightCurrentScreen ( + IN UINTN FileCol + ) +{ + // + // if is to the right of the screen + // + if (FileCol > FileBuffer.LowVisibleRange.Column + MainEditor.ScreenSize.Column - 1) { + return TRUE; + } + + return FALSE; +} + +/** + Advance/Retreat lines and set CurrentLine in FileBuffer to it + + @param[in] Count The line number to advance/retreat + >0 : advance + <0: retreat + + @retval NULL An error occured. + @return The line after advance/retreat. +**/ +EFI_EDITOR_LINE * +EFIAPI +MoveCurrentLine ( + IN INTN Count + ) +{ + EFI_EDITOR_LINE *Line; + UINTN AbsCount; + + if (Count <= 0) { + AbsCount = -Count; + Line = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead); + } else { + Line = InternalEditorMiscLineAdvance (Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead); + } + + if (Line == NULL) { + return NULL; + } + + MainEditor.FileBuffer->CurrentLine = Line; + + return Line; +} + +/** + According to cursor's file position, adjust screen display + + @param[in] NewFilePosRow The row of file position ( start from 1 ). + @param[in] NewFilePosCol The column of file position ( start from 1 ). +**/ +VOID +EFIAPI +FileBufferMovePosition ( + IN CONST UINTN NewFilePosRow, + IN CONST UINTN NewFilePosCol + ) +{ + INTN RowGap; + INTN ColGap; + UINTN Abs; + BOOLEAN Above; + BOOLEAN Under; + BOOLEAN Right; + BOOLEAN Left; + + // + // CALCULATE gap between current file position and new file position + // + RowGap = NewFilePosRow - FileBuffer.FilePosition.Row; + ColGap = NewFilePosCol - FileBuffer.FilePosition.Column; + + Under = UnderCurrentScreen (NewFilePosRow); + Above = AboveCurrentScreen (NewFilePosRow); + // + // if is below current screen + // + if (Under) { + // + // display row will be unchanged + // + FileBuffer.FilePosition.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 < (FileBuffer.DisplayPosition.Row - 1)) { + FileBuffer.DisplayPosition.Row = NewFilePosRow + 1; + } + + FileBuffer.FilePosition.Row = NewFilePosRow; + } else { + // + // in current screen + // + FileBuffer.FilePosition.Row = NewFilePosRow; + if (RowGap < 0) { + Abs = -RowGap; + FileBuffer.DisplayPosition.Row -= Abs; + } else { + FileBuffer.DisplayPosition.Row += RowGap; + } + } + } + + FileBuffer.LowVisibleRange.Row = FileBuffer.FilePosition.Row - (FileBuffer.DisplayPosition.Row - 2); + + Right = RightCurrentScreen (NewFilePosCol); + Left = LeftCurrentScreen (NewFilePosCol); + + // + // if right to current screen + // + if (Right) { + // + // display column will be changed to end + // + FileBuffer.DisplayPosition.Column = MainEditor.ScreenSize.Column; + FileBuffer.FilePosition.Column = NewFilePosCol; + } else { + if (Left) { + // + // has enough left characters , so display row unchanged + // not has enough left characters, + // so the first character is at the first display column + // + if (NewFilePosCol < (FileBuffer.DisplayPosition.Column)) { + FileBuffer.DisplayPosition.Column = NewFilePosCol; + } + + FileBuffer.FilePosition.Column = NewFilePosCol; + } else { + // + // in current screen + // + FileBuffer.FilePosition.Column = NewFilePosCol; + if (ColGap < 0) { + Abs = -ColGap; + FileBuffer.DisplayPosition.Column -= Abs; + } else { + FileBuffer.DisplayPosition.Column += ColGap; + } + } + } + + FileBuffer.LowVisibleRange.Column = FileBuffer.FilePosition.Column - (FileBuffer.DisplayPosition.Column - 1); + + // + // let CurrentLine point to correct line; + // + FileBuffer.CurrentLine = MoveCurrentLine (RowGap); + +} + +/** + Cut current line out and return a pointer to it. + + @param[out] CutLine Upon a successful return pointer to the pointer to + the allocated cut line. + + @retval EFI_SUCCESS The cut was successful. + @retval EFI_NOT_FOUND There was no selection to cut. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferCutLine ( + OUT EFI_EDITOR_LINE **CutLine + ) +{ + EFI_EDITOR_LINE *Line; + EFI_EDITOR_LINE *NewLine; + UINTN Row; + UINTN Col; + + if (FileBuffer.ReadOnly) { + StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + return EFI_SUCCESS; + } + + Line = FileBuffer.CurrentLine; + + // + // if is the last dummy line, SO CAN not cut + // + if (StrCmp (Line->Buffer, L"\0") == 0 && Line->Link.ForwardLink == FileBuffer.ListHead + // + // last line + // + ) { + // + // LAST LINE AND NOTHING ON THIS LINE, SO CUT NOTHING + // + StatusBarSetStatusString (L"Nothing to Cut"); + return EFI_NOT_FOUND; + } + // + // if is the last line, so create a dummy line + // + if (Line->Link.ForwardLink == FileBuffer.ListHead) { + // + // last line + // create a new line + // + NewLine = FileBufferCreateLine (); + if (NewLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + FileBuffer.NumLines--; + Row = FileBuffer.FilePosition.Row; + Col = 1; + // + // move home + // + FileBuffer.CurrentLine = CR ( + FileBuffer.CurrentLine->Link.ForwardLink, + EFI_EDITOR_LINE, + Link, + LINE_LIST_SIGNATURE + ); + + RemoveEntryList (&Line->Link); + + FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + FileBufferMovePosition (Row, Col); + + FileBuffer.FileModified = TRUE; + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + + *CutLine = Line; + + return EFI_SUCCESS; +} + +/** + Paste a line into line list. + + @retval EFI_SUCCESS The paste was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferPasteLine ( + VOID + ) +{ + EFI_EDITOR_LINE *Line; + EFI_EDITOR_LINE *NewLine; + UINTN Row; + UINTN Col; + + // + // if nothing is on clip board + // then do nothing + // + if (MainEditor.CutLine == NULL) { + return EFI_SUCCESS; + } + // + // read only file can not be pasted on + // + if (FileBuffer.ReadOnly) { + StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + return EFI_SUCCESS; + } + + NewLine = LineDup (MainEditor.CutLine); + if (NewLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // insert it above current line + // + Line = FileBuffer.CurrentLine; + NewLine->Link.BackLink = Line->Link.BackLink; + NewLine->Link.ForwardLink = &Line->Link; + + Line->Link.BackLink->ForwardLink = &NewLine->Link; + Line->Link.BackLink = &NewLine->Link; + + FileBuffer.NumLines++; + FileBuffer.CurrentLine = NewLine; + + FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + Col = 1; + // + // move home + // + Row = FileBuffer.FilePosition.Row; + + FileBufferMovePosition (Row, Col); + + // + // after paste, set some value so that refresh knows to do something + // + FileBuffer.FileModified = TRUE; + FileBufferNeedRefresh = TRUE; + FileBufferOnlyLineNeedRefresh = FALSE; + + return EFI_SUCCESS; +} + +/** + Search string from current position on in file + + @param[in] Str The search string. + @param[in] Offset The offset from current position. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_NOT_FOUND The string Str was not found. +**/ +EFI_STATUS +EFIAPI +FileBufferSearch ( + IN CONST CHAR16 *Str, + IN CONST UINTN Offset + ) +{ + CHAR16 *Current; + UINTN Position; + UINTN Row; + UINTN Column; + EFI_EDITOR_LINE *Line; + CHAR16 *CharPos; + LIST_ENTRY *Link; + BOOLEAN Found; + + Column = 0; + + // + // search if in current line + // + Current = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1 + Offset; + + if (Current >= (FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size)) { + // + // the end + // + Current = FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size; + } + + CharPos = StrStr (Current, Str); + if (CharPos != NULL) { + Position = CharPos - Current; + } else { + Position = 0; + } + + // + // found + // + if (Position != 0) { + Column = (Position - 1) + FileBuffer.FilePosition.Column + Offset; + Row = FileBuffer.FilePosition.Row; + Found = TRUE; + } else { + // + // not found so find through next lines + // + Link = FileBuffer.CurrentLine->Link.ForwardLink; + + Row = FileBuffer.FilePosition.Row + 1; + while (Link != FileBuffer.ListHead) { + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); +// Position = StrStr (Line->Buffer, Str); + CharPos = StrStr (Line->Buffer, Str); + if (CharPos != NULL) { + Position = CharPos - Line->Buffer; + } + if (Position != 0) { + // + // found + // + Column = Position; + break; + } + + Row++; + Link = Link->ForwardLink; + } + + if (Link == FileBuffer.ListHead) { + Found = FALSE; + } else { + Found = TRUE; + } + } + + if (!Found) { + return EFI_NOT_FOUND; + } + + FileBufferMovePosition (Row, Column); + + // + // call refresh to fresh edit area, + // because the outer may loop to find multiply occurrence of this string + // + FileBufferRefresh (); + + return EFI_SUCCESS; +} + +/** + Replace SearchLen characters from current position on with Replace. + + This will modify the current buffer at the current position. + + @param[in] Replace The string to replace. + @param[in] SearchLen Search string's length. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferReplace ( + IN CONST CHAR16 *Replace, + IN CONST UINTN SearchLen + ) +{ + UINTN ReplaceLen; + UINTN Index; + CHAR16 *Buffer; + UINTN NewSize; + UINTN OldSize; + UINTN Gap; + + ReplaceLen = StrLen (Replace); + + OldSize = FileBuffer.CurrentLine->Size + 1; + // + // include CHAR_NULL + // + NewSize = OldSize + (ReplaceLen - SearchLen); + + if (ReplaceLen > SearchLen) { + // + // do not have the enough space + // + if (FileBuffer.CurrentLine->TotalSize + 1 <= NewSize) { + FileBuffer.CurrentLine->Buffer = ReallocatePool ( + 2 * OldSize, + 2 * NewSize, + FileBuffer.CurrentLine->Buffer + ); + FileBuffer.CurrentLine->TotalSize = NewSize - 1; + } + + if (FileBuffer.CurrentLine->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // the end CHAR_NULL character; + // + Buffer = FileBuffer.CurrentLine->Buffer + (NewSize - 1); + Gap = ReplaceLen - SearchLen; + + // + // keep the latter part + // + for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - SearchLen + 2); Index++) { + *Buffer = *(Buffer - Gap); + Buffer--; + } + // + // set replace into it + // + Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column; + for (Index = 0; Index < ReplaceLen; Index++) { + Buffer[Index] = Replace[Index]; + } + } + + if (ReplaceLen < SearchLen) { + Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column; + + for (Index = 0; Index < ReplaceLen; Index++) { + Buffer[Index] = Replace[Index]; + } + + Buffer += ReplaceLen; + Gap = SearchLen - ReplaceLen; + + // + // set replace into it + // + for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - ReplaceLen + 2); Index++) { + *Buffer = *(Buffer + Gap); + Buffer++; + } + } + + if (ReplaceLen == SearchLen) { + Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column; + for (Index = 0; Index < ReplaceLen; Index++) { + Buffer[Index] = Replace[Index]; + } + } + + FileBuffer.CurrentLine->Size += (ReplaceLen - SearchLen); + + FileBufferOnlyLineNeedRefresh = TRUE; + + FileBuffer.FileModified = TRUE; + + MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row); + FileBufferRestorePosition (); + FileBufferRefresh (); + + return EFI_SUCCESS; +} + +/** + Move the mouse cursor position. + + @param[in] TextX The new x-coordinate. + @param[in] TextY The new y-coordinate. +**/ +VOID +EFIAPI +FileBufferAdjustMousePosition ( + IN CONST INT32 TextX, + IN CONST INT32 TextY + ) +{ + UINTN CoordinateX; + UINTN CoordinateY; + UINTN AbsX; + UINTN AbsY; + + // + // TextX and TextY is mouse movement data returned by mouse driver + // This function will change it to MousePosition + // + // + // get absolute value + // + + AbsX = ABS(TextX); + AbsY = ABS(TextY); + + CoordinateX = FileBuffer.MousePosition.Column; + CoordinateY = FileBuffer.MousePosition.Row; + + if (TextX >= 0) { + CoordinateX += TextX; + } else { + if (CoordinateX >= AbsX) { + CoordinateX -= AbsX; + } else { + CoordinateX = 0; + } + } + + if (TextY >= 0) { + CoordinateY += TextY; + } else { + if (CoordinateY >= AbsY) { + CoordinateY -= AbsY; + } else { + CoordinateY = 0; + } + } + // + // check whether new mouse column position is beyond screen + // if not, adjust it + // + if (CoordinateX >= 1 && CoordinateX <= MainEditor.ScreenSize.Column) { + FileBuffer.MousePosition.Column = CoordinateX; + } else if (CoordinateX < 1) { + FileBuffer.MousePosition.Column = 1; + } else if (CoordinateX > MainEditor.ScreenSize.Column) { + FileBuffer.MousePosition.Column = MainEditor.ScreenSize.Column; + } + // + // check whether new mouse row position is beyond screen + // if not, adjust it + // + if (CoordinateY >= 2 && CoordinateY <= (MainEditor.ScreenSize.Row - 4)) { + FileBuffer.MousePosition.Row = CoordinateY; + } else if (CoordinateY < 2) { + FileBuffer.MousePosition.Row = 2; + } else if (CoordinateY > (MainEditor.ScreenSize.Row - 4)) { + FileBuffer.MousePosition.Row = (MainEditor.ScreenSize.Row - 4); + } + +} + +/** + Search and replace operation. + + @param[in] SearchStr The string to search for. + @param[in] ReplaceStr The string to replace with. + @param[in] Offset The column to start at. +**/ +EFI_STATUS +EFIAPI +FileBufferReplaceAll ( + IN CHAR16 *SearchStr, + IN CHAR16 *ReplaceStr, + IN UINTN Offset + ) +{ + CHAR16 *Buffer; + UINTN Position; + UINTN Column; + UINTN ReplaceLen; + UINTN SearchLen; + UINTN Index; + UINTN NewSize; + UINTN OldSize; + UINTN Gap; + EFI_EDITOR_LINE *Line; + LIST_ENTRY *Link; + CHAR16 *CharPos; + + SearchLen = StrLen (SearchStr); + ReplaceLen = StrLen (ReplaceStr); + + Column = FileBuffer.FilePosition.Column + Offset - 1; + + if (Column > FileBuffer.CurrentLine->Size) { + Column = FileBuffer.CurrentLine->Size; + } + + Link = &(FileBuffer.CurrentLine->Link); + + while (Link != FileBuffer.ListHead) { + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + CharPos = StrStr (Line->Buffer + Column, SearchStr); + if (CharPos != NULL) { + Position = CharPos - Line->Buffer;// + Column; + // + // found + // + if (ReplaceLen > SearchLen) { + OldSize = Line->Size + 1; + // + // include CHAR_NULL + // + NewSize = OldSize + (ReplaceLen - SearchLen); + + // + // do not have the enough space + // + if (Line->TotalSize + 1 <= NewSize) { + Line->Buffer = ReallocatePool ( + 2 * OldSize, + 2 * NewSize, + Line->Buffer + ); + Line->TotalSize = NewSize - 1; + } + + if (Line->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // the end CHAR_NULL character; + // + Buffer = Line->Buffer + (NewSize - 1); + Gap = ReplaceLen - SearchLen; + + // + // keep the latter part + // + for (Index = 0; Index < (Line->Size - Position - SearchLen + 1); Index++) { + *Buffer = *(Buffer - Gap); + Buffer--; + } + + } else if (ReplaceLen < SearchLen){ + Buffer = Line->Buffer + Position + ReplaceLen; + Gap = SearchLen - ReplaceLen; + + for (Index = 0; Index < (Line->Size - Position - ReplaceLen + 1); Index++) { + *Buffer = *(Buffer + Gap); + Buffer++; + } + } else { + ASSERT(ReplaceLen == SearchLen); + } + // + // set replace into it + // + Buffer = Line->Buffer + Position; + for (Index = 0; Index < ReplaceLen; Index++) { + Buffer[Index] = ReplaceStr[Index]; + } + + Line->Size += (ReplaceLen - SearchLen); + Column += ReplaceLen; + } else { + // + // not found + // + Column = 0; + Link = Link->ForwardLink; + } + } + // + // call refresh to fresh edit area + // + FileBuffer.FileModified = TRUE; + FileBufferNeedRefresh = TRUE; + FileBufferRefresh (); + + return EFI_SUCCESS; +} + +/** + Set the modified state to TRUE. +**/ +VOID +EFIAPI +FileBufferSetModified ( + VOID + ) +{ + FileBuffer.FileModified = TRUE; +} + diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h new file mode 100644 index 0000000000..9d4a08d7a3 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h @@ -0,0 +1,263 @@ +/** @file + Declares filebuffer interface functions. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef _LIB_FILE_BUFFER_H_ +#define _LIB_FILE_BUFFER_H_ + +#include "TextEditorTypes.h" + +/** + Initialization function for FileBuffer. + + @param EFI_SUCCESS The initialization was successful. + @param EFI_LOAD_ERROR A default name could not be created. + @param EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferInit ( + VOID + ); + +/** + Cleanup function for FileBuffer. + + @retval EFI_SUCCESS The cleanup was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferCleanup ( + VOID + ); + +/** + Refresh the screen with whats in the buffer. + + @retval EFI_SUCCESS The refresh was successful. + @retval EFI_LOAD_ERROR There was an error finding what to write. +**/ +EFI_STATUS +EFIAPI +FileBufferRefresh ( + VOID + ); + +/** + Dispatch input to different handler + @param[in] Key The input key. One of: + ASCII KEY + Backspace/Delete + Return + Direction key: up/down/left/right/pgup/pgdn + Home/End + INS + + @retval EFI_SUCCESS The dispatch was done successfully. + @retval EFI_LOAD_ERROR The dispatch was not successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferHandleInput ( + IN CONST EFI_INPUT_KEY * Key + ); + +/** + Backup function for FileBuffer. Only backup the following items: + Mouse/Cursor position + File Name, Type, ReadOnly, Modified + Insert Mode + + This is for making the file buffer refresh as few as possible. + + @retval EFI_SUCCESS The backup operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferBackup ( + VOID + ); + +/** + Set the cursor position according to FileBuffer.DisplayPosition. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +FileBufferRestorePosition ( + VOID + ); + +/** + Set FileName field in FileBuffer. + + @param Str The file name to set. + + @retval EFI_SUCCESS The filename was successfully set. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER Str is not a valid filename. +**/ +EFI_STATUS +EFIAPI +FileBufferSetFileName ( + IN CONST CHAR16 *Str + ); + +/** + Read a file from disk into the FileBuffer. + + @param[in] FileName The filename to read. + @param[in] Recover TRUE if is for recover mode, no information printouts. + + @retval EFI_SUCCESS The load was successful. + @retval EFI_LOAD_ERROR The load failed. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER FileName is a directory. +**/ +EFI_STATUS +EFIAPI +FileBufferRead ( + IN CONST CHAR16 *FileName, + IN CONST BOOLEAN Recover + ); + +/** + Save lines in FileBuffer to disk + + @param[in] FileName The file name for writing. + + @retval EFI_SUCCESS Data was written. + @retval EFI_LOAD_ERROR + @retval EFI_OUT_OF_RESOURCES There were not enough resources to write the file. +**/ +EFI_STATUS +EFIAPI +FileBufferSave ( + CONST CHAR16 *FileName + ); + +/** + According to cursor's file position, adjust screen display + + @param[in] NewFilePosRow The row of file position ( start from 1 ). + @param[in] NewFilePosCol The column of file position ( start from 1 ). +**/ +VOID +EFIAPI +FileBufferMovePosition ( + IN CONST UINTN NewFilePosRow, + IN CONST UINTN NewFilePosCol + ); + +/** + Cut current line out and return a pointer to it. + + @param[out] CutLine Upon a successful return pointer to the pointer to + the allocated cut line. + + @retval EFI_SUCCESS The cut was successful. + @retval EFI_NOT_FOUND There was no selection to cut. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferCutLine ( + OUT EFI_EDITOR_LINE **CutLine + ); + +/** + Paste a line into line list. + + @retval EFI_SUCCESS The paste was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferPasteLine ( + VOID + ); + +/** + Search string from current position on in file + + @param[in] Str The search string. + @param[in] Offset The offset from current position. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_NOT_FOUND The string Str was not found. +**/ +EFI_STATUS +EFIAPI +FileBufferSearch ( + IN CONST CHAR16 *Str, + IN CONST UINTN Offset + ); + +/** + Replace SearchLen characters from current position on with Replace. + + This will modify the current buffer at the current position. + + @param[in] Replace The string to replace. + @param[in] SearchLen Search string's length. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileBufferReplace ( + IN CONST CHAR16 *Replace, + IN CONST UINTN SearchLen + ); + +/** + Search and replace operation. + + @param[in] SearchStr The string to search for. + @param[in] ReplaceStr The string to replace with. + @param[in] Offset The column to start at. +**/ +EFI_STATUS +EFIAPI +FileBufferReplaceAll ( + IN CHAR16 *SearchStr, + IN CHAR16 *ReplaceStr, + IN UINTN Offset + ); + +/** + Move the mouse cursor position. + + @param[in] TextX The new x-coordinate. + @param[in] TextY The new y-coordinate. +**/ +VOID +EFIAPI +FileBufferAdjustMousePosition ( + IN CONST INT32 TextX, + IN CONST INT32 TextY + ); + +/** + Set the modified state to TRUE. +**/ +VOID +EFIAPI +FileBufferSetModified ( + VOID + ); + +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c new file mode 100644 index 0000000000..7749bdc547 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c @@ -0,0 +1,1830 @@ +/** @file + Implements editor interface functions. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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 "TextEditor.h" +#include "EditStatusBar.h" +#include "EditInputBar.h" + +/** + Load a file from disk to editor + + @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 +MainCommandOpenFile ( + VOID + ); + +/** + Switch a file from ASCII to UNICODE or vise-versa. + + @retval EFI_SUCCESS The switch was ok or a warning was presented. +**/ +EFI_STATUS +EFIAPI +MainCommandSwitchFileType ( + VOID + ); + +/** + move cursor to specified lines + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +MainCommandGotoLine ( + VOID + ); + +/** + Save current file to disk, you can save to current file name or + save to another file name. + + @retval EFI_SUCCESS The file was saved correctly. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A file access error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandSaveFile ( + VOID + ); + +/** + exit editor + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandExit ( + VOID + ); + +/** + search string in file buffer + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandSearch ( + VOID + ); + +/* + search string in file buffer, and replace it with another str + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandSearchReplace ( + VOID + ); + +/** + cut current line to clipboard + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandCutLine ( + VOID + ); + +/** + paste line to file buffer. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandPasteLine ( + VOID + ); + +EDITOR_MENU_ITEM MainMenuItems[] = { + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_GO_TO_LINE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F1), + MainCommandGotoLine + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_SAVE_FILE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F2), + MainCommandSaveFile + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_EXIT), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F3), + MainCommandExit + }, + + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F4), + MainCommandSearch + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH_REPLACE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F5), + MainCommandSearchReplace + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_CUT_LINE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F6), + MainCommandCutLine + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_PASTE_LINE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F7), + MainCommandPasteLine + }, + + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_OPEN_FILE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F8), + MainCommandOpenFile + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_FILE_TYPE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F9), + MainCommandSwitchFileType + }, + + { + 0, + 0, + NULL + } +}; + + +/** + Load a file from disk to editor + + @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 +MainCommandOpenFile ( + VOID + ) +{ + BOOLEAN Done; + EFI_STATUS Status; + + // + // This command will open a file from current working directory. + // Read-only file can also be opened. But it can not be modified. + // Below is the scenario of Open File command: + // 1.IF currently opened file has not been modIFied, directly go to step . + // IF currently opened file has been modified, + // an Input Bar will be prompted as : + // "File Modified. Save ( Yes/No/Cancel) ?" + // IF user press 'y' or 'Y', currently opened file will be saved. + // IF user press 'n' or 'N', currently opened file will + // not be saved. + // IF user press 'c' or 'C' or ESC, Open File command ends and + // currently opened file is still opened. + // + // 2. An Input Bar will be prompted as : "File Name to Open: " + // IF user press ESC, Open File command ends and + // currently opened file is still opened. + // Any other inputs with a Return will + // cause currently opened file close. + // + // 3. IF user input file name is an existing file , this file will be read + // and opened. + // IF user input file name is a new file, this file will be created + // and opened. This file's type ( UNICODE or ASCII ) is the same + // with the old file. + // if current file is modified, so you need to choose + // whether to save it first. + // + if (MainEditor.FileBuffer->FileModified) { + + Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // the answer is just one character + // + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + // + // loop for user's answer + // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' + // + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // want to save this file first + // + Status = FileBufferSave (MainEditor.FileBuffer->FileName); + if (EFI_ERROR (Status)) { + return Status; + } + + MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row); + FileBufferRestorePosition (); + Done = TRUE; + break; + + case L'n': + case L'N': + // + // the file won't be saved + // + Done = TRUE; + break; + + case L'c': + case L'C': + return EFI_SUCCESS; + } + } + } + // + // TO get the open file name + // + Status = InputBarSetPrompt (L"File Name to Open: "); + if (EFI_ERROR (Status)) { + FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); + return Status; + } + + Status = InputBarSetStringSize (100); + if (EFI_ERROR (Status)) { + FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); + return Status; + } + + while (1) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + // + // The input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + // + // CHECK if filename is valid + // + if (!IsValidFileName (InputBarGetString())) { + FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); + StatusBarSetStatusString (L"Invalid File Name"); + return EFI_SUCCESS; + } + + break; + } + } + // + // read from disk + // + Status = FileBufferRead (InputBarGetString(), FALSE); + + if (EFI_ERROR (Status)) { + FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Switch a file from ASCII to UNICODE or vise-versa. + + @retval EFI_SUCCESS The switch was ok or a warning was presented. +**/ +EFI_STATUS +EFIAPI +MainCommandSwitchFileType ( + VOID + ) +{ + // + // Below is the scenario of File Type command: + // After File Type is executed, file type will be changed to another type + // if file is read-only, can not be modified + // + if (MainEditor.FileBuffer->ReadOnly) { + StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + return EFI_SUCCESS; + } + + if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { + MainEditor.FileBuffer->FileType = FileTypeAscii; + } else { + MainEditor.FileBuffer->FileType = FileTypeUnicode; + } + + MainEditor.FileBuffer->FileModified = TRUE; + + return EFI_SUCCESS; +} + +/** + cut current line to clipboard + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandCutLine ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EDITOR_LINE *Line; + + // + // This command will cut current line ( where cursor is on ) to clip board. + // And cursor will move to the beginning of next line. + // Below is the scenario of Cut Line command: + // 1. IF cursor is on valid line, current line will be cut to clip board. + // IF cursor is not on valid line, an Status String will be prompted : + // "Nothing to Cut". + // + Status = FileBufferCutLine (&Line); + if (Status == EFI_NOT_FOUND) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + MainEditor.CutLine = Line; + + return EFI_SUCCESS; +} + +/** + paste line to file buffer. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandPasteLine ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Below is the scenario of Paste Line command: + // 1. IF nothing is on clipboard, a Status String will be prompted : + // "No Line to Paste" and Paste Line command ends. + // IF something is on clipboard, insert it above current line. + // nothing on clipboard + // + if (MainEditor.CutLine == NULL) { + StatusBarSetStatusString (L"No Line to Paste"); + return EFI_SUCCESS; + } + + Status = FileBufferPasteLine (); + + return Status; +} + + +/** + search string in file buffer + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandSearch ( + VOID + ) +{ + EFI_STATUS Status; + CHAR16 *Buffer; + BOOLEAN Done; + UINTN Offset; + + // + // Below is the scenario of Search command: + // 1. An Input Bar will be prompted : "Enter Search String:". + // IF user press ESC, Search command ends. + // IF user just press Enter, Search command ends. + // IF user inputs the search string, do Step 2. + // + // 2. IF input search string is found, cursor will move to the first + // occurrence and do Step 3. + // IF input search string is not found, a Status String + // "Search String Not Found" will be prompted and Search command ends. + // + // 3. An Input Bar will be prompted: "Find Next (Yes/No/Cancel ) ?". + // IF user press ESC, Search command ends. + // IF user press 'y' or 'Y', do Step 2. + // IF user press 'n' or 'N', Search command ends. + // IF user press 'c' or 'C', Search command ends. + // + Status = InputBarSetPrompt (L"Enter Search String: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (40); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + // + // just enter pressed + // + if (StrLen (InputBarGetString()) == 0) { + return EFI_SUCCESS; + } + + Buffer = CatSPrint (NULL, L"%s", InputBarGetString()); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // the first time , search from current position + // + Offset = 0; + do { + // + // since search may be continued to search multiple times + // so we need to backup editor each time + // + MainEditorBackup (); + + Status = FileBufferSearch (Buffer, Offset); + + if (Status == EFI_NOT_FOUND) { + break; + } + // + // Find next + // + Status = InputBarSetPrompt (L"Find Next (Yes/No) ?"); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + FreePool (Buffer); + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + Done = TRUE; + break; + + case L'n': + case L'N': + FreePool (Buffer); + return EFI_SUCCESS; + + } + // + // end of which + // + } + // + // end of while !Done + // for search second, third time, search from current position + strlen + // + Offset = StrLen (Buffer); + + } while (1); + // + // end of do + // + FreePool (Buffer); + StatusBarSetStatusString (L"Search String Not Found"); + + return EFI_SUCCESS; +} + +/* + search string in file buffer, and replace it with another str + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandSearchReplace ( + VOID + ) +{ + EFI_STATUS Status; + CHAR16 *Search; + CHAR16 *Replace; + BOOLEAN Done; + BOOLEAN First; + BOOLEAN ReplaceOption; + UINTN SearchLen; + UINTN ReplaceLen; + BOOLEAN ReplaceAll; + + ReplaceOption = FALSE; + + // + // Below is the scenario of Search/Replace command: + // 1. An Input Bar is prompted : "Enter Search String:". + // IF user press ESC, Search/Replace command ends. + // IF user just press Enter, Search/Replace command ends. + // IF user inputs the search string S, do Step 2. + // + // 2. An Input Bar is prompted: "Replace With:". + // IF user press ESC, Search/Replace command ends. + // IF user inputs the replace string R, do Step 3. + // + // 3. IF input search string is not found, an Status String + // "Search String Not Found" will be prompted + // and Search/Replace command ends + // IF input search string is found, do Step 4. + // + // 4. An Input Bar will be prompted: "Replace ( Yes/No/All/Cancel )?" + // IF user press 'y' or 'Y', S will be replaced with R and do Step 5 + // IF user press 'n' or 'N', S will not be replaced and do Step 5. + // IF user press 'a' or 'A', all the S from file current position on + // will be replaced with R and Search/Replace command ends. + // IF user press 'c' or 'C' or ESC, Search/Replace command ends. + // + // 5. An Input Bar will be prompted: "Find Next (Yes/No/Cancel) ?". + // IF user press ESC, Search/Replace command ends. + // IF user press 'y' or 'Y', do Step 3. + // IF user press 'n' or 'N', Search/Replace command ends. + // IF user press 'c' or 'C', Search/Replace command ends. + // input search string + // + Status = InputBarSetPrompt (L"Enter Search String: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (40); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + // + // if just pressed enter + // + if (StrLen (InputBarGetString()) == 0) { + return EFI_SUCCESS; + } + + Search = CatSPrint (NULL, L"%s", InputBarGetString()); + if (Search == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SearchLen = StrLen (Search); + + // + // input replace string + // + Status = InputBarSetPrompt (L"Replace With: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (40); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + Replace = CatSPrint (NULL, L"%s", InputBarGetString()); + if (Replace == NULL) { + FreePool (Search); + return EFI_OUT_OF_RESOURCES; + } + + ReplaceLen = StrLen (Replace); + + First = TRUE; + ReplaceAll = FALSE; + do { + // + // since search may be continued to search multiple times + // so we need to backup editor each time + // + MainEditorBackup (); + + if (First) { + Status = FileBufferSearch (Search, 0); + } else { + // + // if just replace, so skip this replace string + // if replace string is an empty string, so skip to next character + // + if (ReplaceOption) { + Status = FileBufferSearch (Search, (ReplaceLen == 0) ? 1 : ReplaceLen); + } else { + Status = FileBufferSearch (Search, SearchLen); + } + } + + if (Status == EFI_NOT_FOUND) { + break; + } + // + // replace or not? + // + Status = InputBarSetPrompt (L"Replace (Yes/No/All/Cancel) ?"); + + if (EFI_ERROR (Status)) { + FreePool (Search); + FreePool (Replace); + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + FreePool (Search); + FreePool (Replace); + return Status; + } + + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + FreePool (Search); + FreePool (Replace); + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + Done = TRUE; + ReplaceOption = TRUE; + break; + + case L'n': + case L'N': + Done = TRUE; + ReplaceOption = FALSE; + break; + + case L'a': + case L'A': + Done = TRUE; + ReplaceOption = TRUE; + ReplaceAll = TRUE; + break; + + case L'c': + case L'C': + FreePool (Search); + FreePool (Replace); + return EFI_SUCCESS; + + } + // + // end of which + // + } + // + // end of while !Done + // Decide to Replace + // + if (ReplaceOption) { + // + // file is read-only + // + if (MainEditor.FileBuffer->ReadOnly) { + StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); + return EFI_SUCCESS; + } + // + // replace all + // + if (ReplaceAll) { + Status = FileBufferReplaceAll (Search, Replace, 0); + FreePool (Search); + FreePool (Replace); + return Status; + } + // + // replace + // + Status = FileBufferReplace (Replace, SearchLen); + if (EFI_ERROR (Status)) { + FreePool (Search); + FreePool (Replace); + return Status; + } + } + // + // Find next + // + Status = InputBarSetPrompt (L"Find Next (Yes/No) ?"); + if (EFI_ERROR (Status)) { + FreePool (Search); + FreePool (Replace); + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + FreePool (Search); + FreePool (Replace); + return Status; + } + + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + FreePool (Search); + FreePool (Replace); + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + Done = TRUE; + break; + + case L'n': + case L'N': + FreePool (Search); + FreePool (Replace); + return EFI_SUCCESS; + + } + // + // end of which + // + } + // + // end of while !Done + // + First = FALSE; + + } while (1); + // + // end of do + // + FreePool (Search); + FreePool (Replace); + + StatusBarSetStatusString (L"Search String Not Found"); + + return EFI_SUCCESS; +} + +/** + exit editor + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandExit ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Below is the scenario of Exit command: + // 1. IF currently opened file is not modified, exit the editor and + // Exit command ends. + // IF currently opened file is modified, do Step 2 + // + // 2. An Input Bar will be prompted: + // "File modified. Save ( Yes/No/Cancel )?" + // IF user press 'y' or 'Y', currently opened file will be saved + // and Editor exits + // IF user press 'n' or 'N', currently opened file will not be saved + // and Editor exits. + // IF user press 'c' or 'C' or ESC, Exit command ends. + // if file has been modified, so will prompt user whether to save the changes + // + if (MainEditor.FileBuffer->FileModified) { + + Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // write file back to disk + // + Status = FileBufferSave (MainEditor.FileBuffer->FileName); + if (!EFI_ERROR (Status)) { + EditorExit = TRUE; + } + + return Status; + + case L'n': + case L'N': + EditorExit = TRUE; + return EFI_SUCCESS; + + case L'c': + case L'C': + return EFI_SUCCESS; + + } + } + } + + EditorExit = TRUE; + return EFI_SUCCESS; + +} + +/** + move cursor to specified lines + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +MainCommandGotoLine ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Row; + + // + // Below is the scenario of Go To Line command: + // 1. An Input Bar will be prompted : "Go To Line:". + // IF user press ESC, Go To Line command ends. + // IF user just press Enter, cursor remains unchanged. + // IF user inputs line number, do Step 2. + // + // 2. IF input line number is valid, move cursor to the beginning + // of specified line and Go To Line command ends. + // IF input line number is invalid, a Status String will be prompted: + // "No Such Line" and Go To Line command ends. + // + Status = InputBarSetPrompt (L"Go To Line: "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // line number's digit <= 6 + // + Status = InputBarSetStringSize (6); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // press ESC + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + // + // if JUST press enter + // + if (StrLen (InputBarGetString()) == 0) { + return EFI_SUCCESS; + } + + Row = ShellStrToUintn (InputBarGetString()); + + // + // invalid line number + // + if (Row > MainEditor.FileBuffer->NumLines || Row <= 0) { + StatusBarSetStatusString (L"No Such Line"); + return EFI_SUCCESS; + } + // + // move cursor to that line's start + // + FileBufferMovePosition (Row, 1); + + return EFI_SUCCESS; +} + +/** + Save current file to disk, you can save to current file name or + save to another file name. + + @retval EFI_SUCCESS The file was saved correctly. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_LOAD_ERROR A file access error occured. +**/ +EFI_STATUS +EFIAPI +MainCommandSaveFile ( + VOID + ) +{ + EFI_STATUS Status; + CHAR16 *FileName; + BOOLEAN OldFile; + CHAR16 *Str; + SHELL_FILE_HANDLE FileHandle; + EFI_FILE_INFO *Info; + + // + // This command will save currently opened file to disk. + // You can choose save to another file name or just save to + // current file name. + // Below is the scenario of Save File command: + // ( Suppose the old file name is A ) + // 1. An Input Bar will be prompted: "File To Save: [ old file name]" + // IF user press ESC, Save File command ends . + // IF user press Enter, input file name will be A. + // IF user inputs a new file name B, input file name will be B. + // + // 2. IF input file name is A, go to do Step 3. + // IF input file name is B, go to do Step 4. + // + // 3. IF A is read only, Status Bar will show "Access Denied" and + // Save File commands ends. + // IF A is not read only, save file buffer to disk and remove modified + // flag in Title Bar , then Save File command ends. + // + // 4. IF B does not exist, create this file and save file buffer to it. + // Go to do Step 7. + // IF B exits, do Step 5. + // + // 5.An Input Bar will be prompted: + // "File Exists. Overwrite ( Yes/No/Cancel )?" + // IF user press 'y' or 'Y', do Step 6. + // IF user press 'n' or 'N', Save File commands ends. + // IF user press 'c' or 'C' or ESC, Save File commands ends. + // + // 6. IF B is a read-only file, Status Bar will show "Access Denied" and + // Save File commands ends. + // IF B can be read and write, save file buffer to B. + // + // 7. Update File Name field in Title Bar to B and remove the modified + // flag in Title Bar. + // + Str = CatSPrint (NULL, L"File to Save: [%s]", MainEditor.FileBuffer->FileName); + if (Str == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (StrLen (Str) >= 50) { + // + // replace the long file name with "..." + // + Str[46] = L'.'; + Str[47] = L'.'; + Str[48] = L'.'; + Str[49] = L']'; + Str[50] = CHAR_NULL; + } + + Status = InputBarSetPrompt (Str); + FreePool(Str); + + if (EFI_ERROR (Status)) { + return Status; + } + + + Status = InputBarSetStringSize (100); + if (EFI_ERROR (Status)) { + return Status; + } + // + // get new file name + // + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // if user pressed ESC + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + // + // if just enter pressed, so think save to current file name + // + if (StrLen (InputBarGetString()) == 0) { + FileName = CatSPrint (NULL, L"%s", MainEditor.FileBuffer->FileName); + } else { + FileName = CatSPrint (NULL, L"%s", InputBarGetString()); + } + + if (FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (!IsValidFileName (FileName)) { + StatusBarSetStatusString (L"Invalid File Name"); + FreePool (FileName); + return EFI_SUCCESS; + } + + OldFile = FALSE; + + // + // save to the old file + // + if (StringNoCaseCompare (&FileName, &MainEditor.FileBuffer->FileName) == 0) { + OldFile = TRUE; + } + + if (OldFile) { + // + // if the file is read only, so can not write back to it. + // + if (MainEditor.FileBuffer->ReadOnly == TRUE) { + StatusBarSetStatusString (L"Access Denied"); + FreePool (FileName); + return EFI_SUCCESS; + } + } else { + // + // if the file exists + // + if (ShellFileExists(FileName) != EFI_NOT_FOUND) { + // + // check for read only + // + Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + StatusBarSetStatusString (L"Open Failed"); + FreePool (FileName); + return EFI_SUCCESS; + } + + Info = ShellGetFileInfo(FileHandle); + if (Info == NULL) { + StatusBarSetStatusString (L"Access Denied"); + FreePool (FileName); + return (EFI_SUCCESS); + } + + if (Info->Attribute & EFI_FILE_READ_ONLY) { + StatusBarSetStatusString (L"Access Denied - Read Only"); + FreePool (Info); + FreePool (FileName); + return (EFI_SUCCESS); + } + FreePool (Info); + + // + // ask user whether to overwrite this file + // + Status = InputBarSetPrompt (L"File exists. Overwrite (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (FileName); + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (FileName); + return Status; + } + + while (TRUE) { + Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + StatusBarSetRefresh(); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + break; + + case L'n': + case L'N': + case L'c': + case L'C': + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } // end switch + } // while (!done) + } // file does exist + } // if old file name same + + // + // save file to disk with specified name + // + FileBufferSetModified(); + Status = FileBufferSave (FileName); + SHELL_FREE_NON_NULL (FileName); + + return Status; +} + +EFI_EDITOR_COLOR_ATTRIBUTES OriginalColors; +INTN OriginalMode; + +// +// the first time editor launch +// +BOOLEAN EditorFirst; + +// +// it's time editor should exit +// +BOOLEAN EditorExit; + +BOOLEAN EditorMouseAction; + +extern EFI_EDITOR_FILE_BUFFER FileBuffer; + +extern BOOLEAN FileBufferMouseNeedRefresh; + +extern EFI_EDITOR_FILE_BUFFER FileBufferBackupVar; + +EFI_EDITOR_GLOBAL_EDITOR MainEditor; + +// +// basic initialization for MainEditor +// +EFI_EDITOR_GLOBAL_EDITOR MainEditorConst = { + &FileBuffer, + { + 0, + 0 + }, + { + 0, + 0 + }, + NULL, + FALSE, + NULL +}; + +/** + The initialization function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainEditorInit ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + + // + // basic initialization + // + CopyMem (&MainEditor, &MainEditorConst, sizeof (MainEditor)); + + // + // set screen attributes + // + MainEditor.ColorAttributes.Colors.Foreground = gST->ConOut->Mode->Attribute & 0x000000ff; + + MainEditor.ColorAttributes.Colors.Background = (UINT8) (gST->ConOut->Mode->Attribute >> 4); + OriginalColors = MainEditor.ColorAttributes.Colors; + + OriginalMode = gST->ConOut->Mode->Mode; + + // + // query screen size + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &(MainEditor.ScreenSize.Column), + &(MainEditor.ScreenSize.Row) + ); + + // + // Find mouse in System Table ConsoleInHandle + // + Status = gBS->HandleProtocol ( + gST->ConIn, + &gEfiSimplePointerProtocolGuid, + (VOID**)&MainEditor.MouseInterface + ); + if (EFI_ERROR (Status)) { + // + // If there is no Simple Pointer Protocol on System Table + // + HandleBuffer = NULL; + MainEditor.MouseInterface = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimplePointerProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (!EFI_ERROR (Status) && HandleCount > 0) { + // + // Try to find the first available mouse device + // + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiSimplePointerProtocolGuid, + (VOID**)&MainEditor.MouseInterface + ); + if (!EFI_ERROR (Status)) { + break; + } + } + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + } + + if (!EFI_ERROR (Status) && MainEditor.MouseInterface != NULL) { + MainEditor.MouseAccumulatorX = 0; + MainEditor.MouseAccumulatorY = 0; + MainEditor.MouseSupported = TRUE; + } + + // + // below will call the five components' init function + // + Status = MainTitleBarInit (L"UEFI EDIT 2.0"); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_TITLEBAR), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + Status = MenuBarInit (MainMenuItems); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_MAINMENU), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + Status = StatusBarInit (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_STATUSBAR), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + InputBarInit (); + + Status = FileBufferInit (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + // + // clear whole screen and enable cursor + // + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + // + // initialize EditorFirst and EditorExit + // + EditorFirst = TRUE; + EditorExit = FALSE; + EditorMouseAction = FALSE; + + return EFI_SUCCESS; +} + +/** + The cleanup function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainEditorCleanup ( + VOID + ) +{ + EFI_STATUS Status; + + // + // call the five components' cleanup function + // if error, do not exit + // just print some warning + // + MainTitleBarCleanup(); + StatusBarCleanup(); + InputBarCleanup(); + MenuBarCleanup (); + + Status = FileBufferCleanup (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP), gShellDebug1HiiHandle); + } + // + // restore old mode + // + if (OriginalMode != gST->ConOut->Mode->Mode) { + gST->ConOut->SetMode (gST->ConOut, OriginalMode); + } + // + // restore old screen color + // + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR (OriginalColors.Foreground, OriginalColors.Background) + ); + + gST->ConOut->ClearScreen (gST->ConOut); + + return EFI_SUCCESS; +} + +/** + Refresh the main editor component. +**/ +VOID +EFIAPI +MainEditorRefresh ( + VOID + ) +{ + // + // The Stall value is from experience. NOT from spec. avoids 'flicker' + // + gBS->Stall (50); + + // + // call the components refresh function + // + if (EditorFirst + || StrCmp (FileBufferBackupVar.FileName, FileBuffer.FileName) != 0 + || FileBufferBackupVar.FileType != FileBuffer.FileType + || FileBufferBackupVar.FileModified != FileBuffer.FileModified + || FileBufferBackupVar.ReadOnly != FileBuffer.ReadOnly) { + + MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row); + FileBufferRestorePosition (); + FileBufferRefresh (); + } + if (EditorFirst + || FileBufferBackupVar.FilePosition.Row != FileBuffer.FilePosition.Row + || FileBufferBackupVar.FilePosition.Column != FileBuffer.FilePosition.Column + || FileBufferBackupVar.ModeInsert != FileBuffer.ModeInsert + || StatusBarGetRefresh()) { + + StatusBarRefresh (EditorFirst, MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column, MainEditor.FileBuffer->FilePosition.Row, MainEditor.FileBuffer->FilePosition.Column, MainEditor.FileBuffer->ModeInsert); + FileBufferRestorePosition (); + FileBufferRefresh (); + } + + if (EditorFirst) { + MenuBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); + FileBufferRestorePosition (); + } + + // + // EditorFirst is now set to FALSE + // + EditorFirst = FALSE; +} + +/** + Get's the resultant location of the cursor based on the relative movement of the Mouse. + + @param[in] GuidX The relative mouse movement. + + @return The X location of the mouse. +**/ +INT32 +EFIAPI +GetTextX ( + IN INT32 GuidX + ) +{ + INT32 Gap; + + MainEditor.MouseAccumulatorX += GuidX; + Gap = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX); + MainEditor.MouseAccumulatorX = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX); + MainEditor.MouseAccumulatorX = MainEditor.MouseAccumulatorX / (INT32) MainEditor.ScreenSize.Column; + return Gap; +} + +/** + Get's the resultant location of the cursor based on the relative movement of the Mouse. + + @param[in] GuidY The relative mouse movement. + + @return The Y location of the mouse. +**/ +INT32 +EFIAPI +GetTextY ( + IN INT32 GuidY + ) +{ + INT32 Gap; + + MainEditor.MouseAccumulatorY += GuidY; + Gap = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY); + MainEditor.MouseAccumulatorY = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY); + MainEditor.MouseAccumulatorY = MainEditor.MouseAccumulatorY / (INT32) MainEditor.ScreenSize.Row; + + return Gap; +} + +/** + Support mouse movement. Move the cursor. + + @param[in] MouseState The current mouse state. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_NOT_FOUND There was no mouse support found. +**/ +STATIC +EFI_STATUS +EFIAPI +MainEditorHandleMouseInput ( + IN EFI_SIMPLE_POINTER_STATE MouseState + ) +{ + + INT32 TextX; + INT32 TextY; + UINTN FRow; + UINTN FCol; + + LIST_ENTRY *Link; + EFI_EDITOR_LINE *Line; + + UINTN Index; + BOOLEAN Action; + + // + // mouse action means: + // mouse movement + // mouse left button + // + Action = FALSE; + + // + // have mouse movement + // + if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) { + // + // handle + // + TextX = GetTextX (MouseState.RelativeMovementX); + TextY = GetTextY (MouseState.RelativeMovementY); + + FileBufferAdjustMousePosition (TextX, TextY); + + Action = TRUE; + + } + + // + // if left button pushed down + // + if (MouseState.LeftButton) { + + FCol = MainEditor.FileBuffer->MousePosition.Column - 1 + 1; + + FRow = MainEditor.FileBuffer->FilePosition.Row + + MainEditor.FileBuffer->MousePosition.Row - + MainEditor.FileBuffer->DisplayPosition.Row; + + // + // beyond the file line length + // + if (MainEditor.FileBuffer->NumLines < FRow) { + FRow = MainEditor.FileBuffer->NumLines; + } + + Link = MainEditor.FileBuffer->ListHead->ForwardLink; + for (Index = 0; Index < FRow - 1; Index++) { + Link = Link->ForwardLink; + } + + Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); + + // + // beyond the line's column length + // + if (FCol > Line->Size + 1) { + FCol = Line->Size + 1; + } + + FileBufferMovePosition (FRow, FCol); + + MainEditor.FileBuffer->MousePosition.Row = MainEditor.FileBuffer->DisplayPosition.Row; + + MainEditor.FileBuffer->MousePosition.Column = MainEditor.FileBuffer->DisplayPosition.Column; + + Action = TRUE; + } + // + // mouse has action + // + if (Action) { + return EFI_SUCCESS; + } + + // + // no mouse action + // + return EFI_NOT_FOUND; +} + +/** + Handle user key input. This routes to other functions for the actions. + + @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 +MainEditorKeyInput ( + VOID + ) +{ + EFI_INPUT_KEY Key; + EFI_STATUS Status; + EFI_SIMPLE_POINTER_STATE MouseState; + + do { + + Status = EFI_SUCCESS; + EditorMouseAction = FALSE; + + // + // backup some key elements, so that can aVOID some refresh work + // + MainEditorBackup (); + + // + // change priority of checking mouse/keyboard activity dynamically + // so prevent starvation of keyboard. + // if last time, mouse moves then this time check keyboard + // + if (MainEditor.MouseSupported) { + Status = MainEditor.MouseInterface->GetState ( + MainEditor.MouseInterface, + &MouseState + ); + if (!EFI_ERROR (Status)) { + + Status = MainEditorHandleMouseInput (MouseState); + + if (!EFI_ERROR (Status)) { + EditorMouseAction = TRUE; + FileBufferMouseNeedRefresh = TRUE; + } else if (Status == EFI_LOAD_ERROR) { + StatusBarSetStatusString (L"Invalid Mouse Movement "); + } + } + } + + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (!EFI_ERROR (Status)) { + // + // dispatch to different components' key handling function + // so not everywhere has to set this variable + // + FileBufferMouseNeedRefresh = TRUE; + // + // clear previous status string + // + StatusBarSetRefresh(); + + // + // dispatch to different components' key handling function + // + if ((Key.ScanCode == SCAN_NULL) || ((Key.ScanCode >= SCAN_UP) && (Key.ScanCode <= SCAN_PAGE_DOWN))) { + Status = FileBufferHandleInput (&Key); + } else if ((Key.ScanCode >= SCAN_F1) && (Key.ScanCode <= SCAN_F12)) { + Status = MenuBarDispatchFunctionKey (&Key); + } else { + StatusBarSetStatusString (L"Unknown Command"); + FileBufferMouseNeedRefresh = FALSE; + } + + if (Status != EFI_SUCCESS && Status != EFI_OUT_OF_RESOURCES) { + // + // not already has some error status + // + if (StatusBarGetString() != NULL && StrCmp (L"", StatusBarGetString()) == 0) { + StatusBarSetStatusString (L"Disk Error. Try Again"); + } + } + + } + // + // after handling, refresh editor + // + MainEditorRefresh (); + + } while (Status != EFI_OUT_OF_RESOURCES && !EditorExit); + + return Status; +} + +/** + Set clipboard + + @param[in] Line A pointer to the line to be set to clipboard + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +MainEditorSetCutLine ( + EFI_EDITOR_LINE *Line + ) +{ + if (Line == NULL) { + return EFI_SUCCESS; + } + + if (MainEditor.CutLine != NULL) { + // + // free the old clipboard + // + LineFree (MainEditor.CutLine); + } + // + // duplicate the line to clipboard + // + MainEditor.CutLine = LineDup (Line); + if (MainEditor.CutLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Backup function for MainEditor + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +MainEditorBackup ( + VOID + ) +{ + FileBufferBackup (); + + return EFI_SUCCESS; +} diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h new file mode 100644 index 0000000000..c45859deda --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h @@ -0,0 +1,77 @@ +/** @file + Declares editor interface functions. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef _LIB_EDITOR_H_ +#define _LIB_EDITOR_H_ + +#include "TextEditorTypes.h" + +/** + The initialization function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainEditorInit ( + VOID + ); + +/** + The cleanup function for MainEditor. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_LOAD_ERROR A load error occured. +**/ +EFI_STATUS +EFIAPI +MainEditorCleanup ( + VOID + ); + +/** + Refresh the main editor component. +**/ +VOID +EFIAPI +MainEditorRefresh ( + VOID + ); + +/** + Handle user key input. This routes to other functions for the actions. + + @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 +MainEditorKeyInput ( + VOID + ); + +/** + Backup function for MainEditor + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +MainEditorBackup ( + VOID + ); + +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c new file mode 100644 index 0000000000..ade78b8f90 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c @@ -0,0 +1,92 @@ +/** @file + Implementation of various string and line routines. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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 "TextEditor.h" +#include "Misc.h" + +/** + Duplicate a EFI_EDITOR_LINE structure. + + @param Src The line structure to copy from. + + @retval NULL A memory allocation failed. + @return a pointer to the newly allcoated line. +**/ +EFI_EDITOR_LINE * +EFIAPI +LineDup ( + IN EFI_EDITOR_LINE *Src + ) +{ + EFI_EDITOR_LINE *Dest; + + // + // allocate for the line structure + // + Dest = AllocateZeroPool (sizeof (EFI_EDITOR_LINE)); + if (Dest == NULL) { + return NULL; + } + // + // allocate and set the line buffer + // + Dest->Buffer = CatSPrint (NULL, L"%s", Src->Buffer); + if (Dest->Buffer == NULL) { + FreePool (Dest); + return NULL; + } + + // + // set the other structure members + // + Dest->Signature = LINE_LIST_SIGNATURE; + Dest->Size = Src->Size; + Dest->TotalSize = Dest->Size; + Dest->Type = Src->Type; + Dest->Link = Src->Link; + + return Dest; +} + +/** + Free a EFI_EDITOR_LINE structure. + + @param Src The line structure to free. +**/ +VOID +EFIAPI +LineFree ( + IN EFI_EDITOR_LINE *Src + ) +{ + if (Src == NULL) { + return ; + } + // + // free the line buffer and then the line structure itself + // + SHELL_FREE_NON_NULL (Src->Buffer); + SHELL_FREE_NON_NULL (Src); + +} + + + + + + + + + + diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h new file mode 100644 index 0000000000..583de3b42c --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h @@ -0,0 +1,52 @@ +/** @file + Declares generic editor helper functions. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef _LIB_MISC_H_ +#define _LIB_MISC_H_ + +#include "TextEditorTypes.h" + + + +/** + Free a EFI_EDITOR_LINE structure. + + @param Src The line structure to free. +**/ +VOID +EFIAPI +LineFree ( + IN EFI_EDITOR_LINE *Src + ); + +/** + Duplicate a EFI_EDITOR_LINE structure. + + @param Src The line structure to copy from. + + @retval NULL A memory allocation failed. + @return a pointer to the newly allcoated line. +**/ +EFI_EDITOR_LINE * +EFIAPI +LineDup ( + IN EFI_EDITOR_LINE *Src + ); + + + + + + +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni new file mode 100644 index 0000000000..09a0d47b28 Binary files /dev/null and b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni differ diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h new file mode 100644 index 0000000000..774f01a291 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h @@ -0,0 +1,32 @@ +/** @file + Main include file for Edit shell Debug1 function. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef _EFI_EDIT_H_ +#define _EFI_EDIT_H_ + +#include "TextEditorTypes.h" + +#include "MainTextEditor.h" +#include "FileBuffer.h" +#include "EditTitleBar.h" +#include "EditStatusBar.h" +#include "EditInputBar.h" +#include "EditMenuBar.h" +#include "Misc.h" + +extern EFI_EDITOR_GLOBAL_EDITOR MainEditor; +extern BOOLEAN EditorFirst; +extern BOOLEAN EditorExit; + +#endif // _EFI_EDIT_H_ diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h new file mode 100644 index 0000000000..9bcf39e028 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h @@ -0,0 +1,102 @@ +/** @file + Declares editor types. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef _EDITOR_TYPE_H_ +#define _EDITOR_TYPE_H_ + +#include "UefiShellDebug1CommandsLib.h" +#include "EditTitleBar.h" +#include "EditMenuBar.h" + +#define MIN_POOL_SIZE 125 +#define MAX_STRING_LENGTH 127 + +typedef struct { + UINTN Row; + UINTN Column; +} EFI_EDITOR_POSITION; + +typedef +EFI_STATUS +(*EFI_MENU_ITEM_FUNCTION) ( + VOID + ); + +typedef enum { + NewLineTypeDefault, + NewLineTypeLineFeed, + NewLineTypeCarriageReturn, + NewLineTypeCarriageReturnLineFeed, + NewLineTypeLineFeedCarriageReturn, + NewLineTypeUnknown +} EE_NEWLINE_TYPE; + +#define LINE_LIST_SIGNATURE 'eell' +typedef struct _EFI_EDITOR_LINE { + UINTN Signature; + CHAR16 *Buffer; + UINTN Size; // unit is Unicode + UINTN TotalSize; // unit is Unicode, exclude CHAR_NULL + EE_NEWLINE_TYPE Type; + LIST_ENTRY Link; +} EFI_EDITOR_LINE; + +typedef struct { + UINT32 Foreground : 4; + UINT32 Background : 4; +} EFI_EDITOR_COLOR_ATTRIBUTES; + +typedef union { + EFI_EDITOR_COLOR_ATTRIBUTES Colors; + UINTN Data; +} EFI_EDITOR_COLOR_UNION; + +typedef struct { + UINTN Columns; + UINTN Rows; +} EFI_EDITOR_TEXT_MODE; + +typedef struct { + CHAR16 *FileName; // file name current edited in editor + EDIT_FILE_TYPE FileType; // Unicode file or ASCII file + LIST_ENTRY *ListHead; // list head of lines + EFI_EDITOR_LINE *Lines; // lines of current file + UINTN NumLines; // total line numbers + EFI_EDITOR_POSITION DisplayPosition; // cursor position in screen + EFI_EDITOR_POSITION FilePosition; // cursor position in file + EFI_EDITOR_POSITION MousePosition; // mouse position in screen + // file position of first byte displayed on screen + // + EFI_EDITOR_POSITION LowVisibleRange; + + BOOLEAN FileModified; // file is modified or not + BOOLEAN ModeInsert; // input mode INS or OVR + BOOLEAN ReadOnly; // file is read-only or not + EFI_EDITOR_LINE *CurrentLine; // current line cursor is at +} EFI_EDITOR_FILE_BUFFER; + +typedef struct { + EFI_EDITOR_FILE_BUFFER *FileBuffer; + + EFI_EDITOR_COLOR_UNION ColorAttributes; + EFI_EDITOR_POSITION ScreenSize; // row number and column number + EFI_EDITOR_LINE *CutLine; // clip board + BOOLEAN MouseSupported; + EFI_SIMPLE_POINTER_PROTOCOL *MouseInterface; + INT32 MouseAccumulatorX; + INT32 MouseAccumulatorY; + +} EFI_EDITOR_GLOBAL_EDITOR; + +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.c new file mode 100644 index 0000000000..04ebd24edc --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.c @@ -0,0 +1,2695 @@ +/** @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.
+ 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; + +EFI_STATUS +HBufferImageInit ( + VOID + ) +/*++ + +Routine Description: + + Initialization function for HBufferImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + +--*/ +{ + 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; +} + +EFI_STATUS +HBufferImageBackup ( + VOID + ) +/*++ + +Routine Description: + + Backup function for HBufferImage + Only a few fields need to be backup. + This is for making the file buffer refresh + as few as possible. + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + 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; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +HBufferImageFreeLines ( + VOID + ) +/*++ + +Routine Description: + + Free all the lines in HBufferImage + Fields affected: + Lines + CurrentLine + NumLines + ListHead + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + HFreeLines (HBufferImage.ListHead, HBufferImage.Lines); + + HBufferImage.Lines = NULL; + HBufferImage.CurrentLine = NULL; + HBufferImage.NumLines = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +HBufferImageCleanup ( + VOID + ) +/*++ + +Routine Description: + + Cleanup function for HBufferImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + + // + // free all the lines + // + Status = HBufferImageFreeLines (); + + SHELL_FREE_NON_NULL (HBufferImage.ListHead); + HBufferImage.ListHead = NULL; + + HFileImageCleanup (); + HDiskImageCleanup (); + HMemImageCleanup (); + + return Status; + +} + +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 + + ) +/*++ + +Routine Description: + + Print Line on Row + +Arguments: + + Line - Line to print + Row - Row on screen ( begin from 1 ) + FRow - FRow + Orig - Orig + New - Light display + +Returns: + + EFI_SUCCESS + +--*/ +{ + + 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 == FALSE) { + 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 == FALSE) { + 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; +} + +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)) { + return TRUE; + } + + if ((Column % 3 == 2)) { + *FCol = 0; + } + + return FALSE; +} + +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; +} + +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.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 (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 (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; +} + +EFI_STATUS +HBufferImageRestorePosition ( + VOID + ) +/*++ + +Routine Description: + + Set cursor position according to HBufferImage.DisplayPosition. + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // set cursor position + // + gST->ConOut->SetCursorPosition ( + gST->ConOut, + HBufferImage.DisplayPosition.Column - 1, + HBufferImage.DisplayPosition.Row - 1 + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +HBufferImageRefresh ( + VOID + ) +/*++ + +Routine Description: + + Refresh function for HBufferImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + +--*/ +{ + 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 FEndRow; + UINTN Tmp; + + Orig = HMainEditor.ColorAttributes; + 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 == FALSE && + HBufferImageOnlyLineNeedRefresh == FALSE && + HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow + ) { + HBufferImageRestoreMousePosition (); + HBufferImageRestorePosition (); + return EFI_SUCCESS; + } + } + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + // + // only need to refresh current line + // + if (HBufferImageOnlyLineNeedRefresh == TRUE && 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; + FEndRow = EndRow; + + StartRow = 2 + StartRow - HBufferImage.LowVisibleRow; + EndRow = 2 + EndRow - HBufferImage.LowVisibleRow; + + } else { + // + // not mouse selection actions + // + FStartRow = HBufferImage.LowVisibleRow; + StartRow = 2; + EndRow = (HMainEditor.ScreenSize.Row - 4); + } + // + // 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) { + HEditorClearLine (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; +} + +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; + + // + // 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; + } + + if (EFI_ERROR (Status)) { + HBufferImage.BufferType = BufferTypeBackup; + } + + return Status; +} + +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; + } + + if (EFI_ERROR (Status)) { + HBufferImage.BufferType = BufferTypeBackup; + } + + return Status; +} + +HEFI_EDITOR_LINE * +HBufferImageCreateLine ( + VOID + ) +/*++ + +Routine Description: + + Create a new line and append it to the line list + Fields affected: + NumLines + Lines + +Arguments: + + None + +Returns: + + NULL -- create line failed + Not NULL -- the line created + +--*/ +{ + 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; +} + +EFI_STATUS +HBufferImageFree ( + VOID + ) +/*++ + +Routine Description: + + Function called when load a new file in. It will free all the old lines + and set FileModified field to FALSE + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // free all lines + // + HBufferImageFreeLines (); + + return EFI_SUCCESS; +} + +EFI_STATUS +HBufferImageHandleInput ( + IN EFI_INPUT_KEY *Key + ) +/*++ + +Routine Description: + + Dispatch input to different handler + +Arguments: + + Key -- input key + the keys can be: + ASCII KEY + Backspace/Delete + Direction key: up/down/left/right/pgup/pgdn + Home/End + INS + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + 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; +} + +EFI_STATUS +HBufferImageDoCharInput ( + IN CHAR16 Char + ) +/*++ + +Routine Description: + + ASCII key + Backspace + return + +Arguments: + + Char -- input char + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + 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; +} + +INTN +HBufferImageCharToHex ( + IN CHAR16 Char + ) +/*++ + +Routine Description: + + change char to int value based on Hex + +Arguments: + + Char -- input char + +Returns: + + int value; + + +--*/ +{ + // + // 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; +} + +EFI_STATUS +HBufferImageAddChar ( + IN CHAR16 Char + ) +/*++ + +Routine Description: + + Add character + +Arguments: + + Char -- input char + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + +--*/ +{ + 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 == FALSE && 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 == FALSE) { + // + // 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; +} + +BOOLEAN +HInCurrentScreen ( + IN UINTN FileRow + ) +/*++ + +Routine Description: + + Check user specified FileRow and FileCol is in current screen + +Arguments: + + FileRow -- Row of file position ( start from 1 ) + + +Returns: + + TRUE + FALSE + +--*/ +{ + if (FileRow >= HBufferImage.LowVisibleRow && FileRow <= HBufferImage.LowVisibleRow + (HMainEditor.ScreenSize.Row - 5) - 1) { + return TRUE; + } + + return FALSE; +} + +BOOLEAN +HAboveCurrentScreen ( + IN UINTN FileRow + ) +/*++ + +Routine Description: + + Check user specified FileRow is above current screen + +Arguments: + + FileRow -- Row of file position ( start from 1 ) + +Returns: + + TRUE + FALSE + +--*/ +{ + if (FileRow < HBufferImage.LowVisibleRow) { + return TRUE; + } + + return FALSE; +} + +BOOLEAN +HUnderCurrentScreen ( + IN UINTN FileRow + ) +/*++ + +Routine Description: + + Check user specified FileRow is under current screen + +Arguments: + + FileRow -- Row of file position ( start from 1 ) + +Returns: + + TRUE + FALSE + +--*/ +{ + if (FileRow > HBufferImage.LowVisibleRow + (HMainEditor.ScreenSize.Row - 5) - 1) { + return TRUE; + } + + return FALSE; +} + +VOID +HBufferImageMovePosition ( + IN UINTN NewFilePosRow, + IN UINTN NewFilePosCol, + IN BOOLEAN HighBits + ) +/*++ + +Routine Description: + + According to cursor's file position, adjust screen display + +Arguments: + + NewFilePosRow -- Row of file position ( start from 1 ) + NewFilePosCol -- Column of file position ( start from 1 ) + HighBits -- cursor will on high4 bits or low4 bits + +Returns: + + None + +--*/ +{ + 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 = -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 == FALSE) { + NewDisplayCol++; + } + + HBufferImage.DisplayPosition.Column = NewDisplayCol; + + // + // let CurrentLine point to correct line; + // + HBufferImage.CurrentLine = HMoveCurrentLine (RowGap); + +} + +EFI_STATUS +HBufferImageScrollRight ( + VOID + ) +/*++ + +Routine Description: + + Scroll cursor to right + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + 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; +} + +EFI_STATUS +HBufferImageScrollLeft ( + VOID + ) +/*++ + +Routine Description: + + Scroll cursor to left + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + + 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; +} + +EFI_STATUS +HBufferImageScrollDown ( + VOID + ) +/*++ + +Routine Description: + + Scroll cursor to the next line + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + 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; +} + +EFI_STATUS +HBufferImageScrollUp ( + VOID + ) +/*++ + +Routine Description: + + Scroll cursor to previous line + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + 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; +} + +EFI_STATUS +HBufferImagePageDown ( + VOID + ) +/*++ + +Routine Description: + + Scroll cursor to next page + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + 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 - 5)) { + Gap = (HMainEditor.ScreenSize.Row - 5); + } 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 (FCol > Line->Size) { + FCol = Line->Size + 1; + HighBits = TRUE; + } + + FRow += Gap; + + HBufferImageMovePosition (FRow, FCol, HighBits); + + return EFI_SUCCESS; +} + +EFI_STATUS +HBufferImagePageUp ( + VOID + ) +/*++ + +Routine Description: + + Scroll cursor to previous page + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + HEFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + UINTN Gap; + INTN Retreat; + + Line = HBufferImage.CurrentLine; + + FRow = HBufferImage.BufferPosition.Row; + FCol = HBufferImage.BufferPosition.Column; + + // + // has previous page + // + if (FRow > (HMainEditor.ScreenSize.Row - 5)) { + Gap = (HMainEditor.ScreenSize.Row - 5); + } else { + // + // the first line of file will displayed on the first line of screen + // + Gap = FRow - 1; + } + + Retreat = Gap; + Retreat = -Retreat; + + // + // get correct line + // + Line = HMoveLine (Retreat); + + FRow -= Gap; + + HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits); + + return EFI_SUCCESS; +} + +EFI_STATUS +HBufferImageHome ( + VOID + ) +/*++ + +Routine Description: + + Scroll cursor to start of line + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + HEFI_EDITOR_LINE *Line; + UINTN FRow; + UINTN FCol; + BOOLEAN HighBits; + + Line = HBufferImage.CurrentLine; + + // + // curosr will at the high bit + // + FRow = HBufferImage.BufferPosition.Row; + FCol = 1; + HighBits = TRUE; + + // + // move cursor position + // + HBufferImageMovePosition (FRow, FCol, HighBits); + + return EFI_SUCCESS; +} + +EFI_STATUS +HBufferImageEnd ( + VOID + ) +/*++ + +Routine Description: + + Scroll cursor to end of line + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + 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; +} + +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; +} + +EFI_STATUS +HBufferImageDeleteCharacterFromBuffer ( + IN UINTN Pos, + IN UINTN Count, + OUT UINT8 *DeleteBuffer + ) +/*++ +Routine Description: + + Delete character from buffer + +Arguments: + + Pos - Position, Pos starting from 0 + Count - Count + DeleteBuffer - DeleteBuffer + +Returns: + + EFI_SUCCESS Success + +--*/ +{ + UINTN Index; + + VOID *Buffer; + UINT8 *BufferPtr; + UINTN Size; + + HEFI_EDITOR_LINE *Line; + LIST_ENTRY *Link; + UINTN StartRow; + + UINTN OldFCol; + UINTN OldFRow; + UINTN OldPos; + + UINTN NewPos; + + EFI_STATUS Status; + + // + // get the line that start position is at + // + StartRow = Pos / 0x10; + + 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; +} + +EFI_STATUS +HBufferImageAddCharacterToBuffer ( + IN UINTN Pos, + IN UINTN Count, + IN UINT8 *AddBuffer + ) +/*++' +Routine Description: + + Add character to buffer, add before pos + +Arguments: + + Pos - Position, Pos starting from 0 + Count - Count + AddBuffer - Add buffer + +Returns: + + EFI_SUCCESS Success + +--*/ +{ + INTN Index; + + VOID *Buffer; + UINT8 *BufferPtr; + UINTN Size; + + HEFI_EDITOR_LINE *Line; + + LIST_ENTRY *Link; + UINTN StartRow; + + UINTN OldFCol; + UINTN OldFRow; + UINTN OldPos; + + UINTN NewPos; + + // + // get the line that start position is at + // + StartRow = Pos / 0x10; + + 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; +} + +EFI_STATUS +HBufferImageDoBackspace ( + VOID + ) +/*++ + +Routine Description: + + delete the previous character + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + 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; +} + +EFI_STATUS +HBufferImageDoDelete ( + VOID + ) +/*++ + +Routine Description: + + Delete current character from line + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + + 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; +} + +EFI_STATUS +HBufferImageBufferToList ( + IN VOID *Buffer, + IN UINTN Bytes + ) +{ + UINTN i; + UINTN j; + UINTN Left; + HEFI_EDITOR_LINE *Line; + UINT8 *BufferPtr; + + i = 0; + Left = 0; + BufferPtr = (UINT8 *) Buffer; + + // + // parse file content line by line + // + while (i < Bytes) { + if (Bytes - i >= 0x10) { + Left = 0x10; + } else { + Left = Bytes - i; + } + + // + // allocate a new line + // + Line = HBufferImageCreateLine (); + if (Line == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Line->Size = Left; + + for (j = 0; j < Left; j++) { + Line->Buffer[j] = BufferPtr[i]; + i++; + } + + } + + // + // 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; +} + +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); + + 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; +} + +VOID +HBufferImageAdjustMousePosition ( + IN INT32 TextX, + IN INT32 TextY + ) +{ + UINTN X; + UINTN Y; + UINTN AbsX; + UINTN AbsY; + + // + // TextX and TextY is mouse movement data returned by mouse driver + // This function will change it to MousePosition + // + // + // get absolute X value + // + if (TextX >= 0) { + AbsX = TextX; + } else { + AbsX = -TextX; + } + // + // get absolute Y value + // + if (TextY >= 0) { + AbsY = TextY; + } else { + AbsY = -TextY; + } + + X = HBufferImage.MousePosition.Column; + Y = HBufferImage.MousePosition.Row; + + if (TextX >= 0) { + X += TextX; + } else { + if (X >= AbsX) { + X -= AbsX; + } else { + X = 0; + } + } + + if (TextY >= 0) { + Y += TextY; + } else { + if (Y >= AbsY) { + Y -= AbsY; + } else { + Y = 0; + } + } + // + // check whether new mouse column position is beyond screen + // if not, adjust it + // + if (X >= 10 && X <= (10 + 0x10 * 3 - 1)) { + HBufferImage.MousePosition.Column = X; + } else if (X < 10) { + HBufferImage.MousePosition.Column = 10; + } else if (X > (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 (Y >= 2 && Y <= (HMainEditor.ScreenSize.Row - 4)) { + HBufferImage.MousePosition.Row = Y; + } else if (Y < 2) { + HBufferImage.MousePosition.Row = 2; + } else if (Y > (HMainEditor.ScreenSize.Row - 4)) { + HBufferImage.MousePosition.Row = (HMainEditor.ScreenSize.Row - 4); + } + +} diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.h new file mode 100644 index 0000000000..d661e50524 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/BufferImage.h @@ -0,0 +1,250 @@ +/** @file + Defines BufferImage - 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.
+ 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. + +**/ + +#ifndef _LIB_BUFFER_IMAGE_H_ +#define _LIB_BUFFER_IMAGE_H_ + +#include "HexEditor.h" + +EFI_STATUS +HBufferImageInit ( + VOID + ); +EFI_STATUS +HBufferImageCleanup ( + VOID + ); +EFI_STATUS +HBufferImageRefresh ( + VOID + ); +EFI_STATUS +HBufferImageHide ( + VOID + ); +EFI_STATUS +HBufferImageHandleInput ( + EFI_INPUT_KEY * + ); +EFI_STATUS +HBufferImageBackup ( + VOID + ); + +EFI_STATUS +HBufferImageRead ( + IN CONST CHAR16 *, + IN CONST CHAR16 *, + IN UINTN, + IN UINTN, + IN UINTN, + IN UINTN, + IN EDIT_FILE_TYPE, + IN BOOLEAN + ); + +EFI_STATUS +HBufferImageSave ( + IN CHAR16 *, + IN CHAR16 *, + IN UINTN, + IN UINTN, + IN UINTN, + IN UINTN, + IN EDIT_FILE_TYPE + ); + +INTN +HBufferImageCharToHex ( + IN CHAR16 + ); + +EFI_STATUS +HBufferImageRestoreMousePosition ( + VOID + ); +EFI_STATUS +HBufferImageRestorePosition ( + VOID + ); + +VOID +HBufferImageMovePosition ( + IN UINTN, + IN UINTN, + IN BOOLEAN + ); + +EFI_STATUS +HBufferImageHandleInput ( + EFI_INPUT_KEY * + ); + +HEFI_EDITOR_LINE * +HBufferImageCreateLine ( + VOID + ); + +EFI_STATUS +HBufferImageDoCharInput ( + CHAR16 + ); +EFI_STATUS +HBufferImageAddChar ( + CHAR16 + ); + +BOOLEAN +HInCurrentScreen ( + UINTN + ); +BOOLEAN +HAboveCurrentScreen ( + UINTN + ); +BOOLEAN +HUnderCurrentScreen ( + UINTN + ); + +EFI_STATUS +HBufferImageScrollRight ( + VOID + ); +EFI_STATUS +HBufferImageScrollLeft ( + VOID + ); +EFI_STATUS +HBufferImageScrollDown ( + VOID + ); +EFI_STATUS +HBufferImageScrollUp ( + VOID + ); +EFI_STATUS +HBufferImagePageUp ( + VOID + ); +EFI_STATUS +HBufferImagePageDown ( + VOID + ); +EFI_STATUS +HBufferImageHome ( + VOID + ); +EFI_STATUS +HBufferImageEnd ( + VOID + ); + +EFI_STATUS +HBufferImageDoBackspace ( + VOID + ); +EFI_STATUS +HBufferImageDoDelete ( + VOID + ); + +EFI_STATUS +HBufferImageCutLine ( + HEFI_EDITOR_LINE ** + ); +EFI_STATUS +HBufferImagePasteLine ( + VOID + ); + +EFI_STATUS +HBufferImageGetFileInfo ( + EFI_FILE_HANDLE, + CHAR16 *, + EFI_FILE_INFO ** + ); + +EFI_STATUS +HBufferImageSearch ( + CHAR16 *, + UINTN + ); +EFI_STATUS +HBufferImageReplace ( + CHAR16 *, + UINTN + ); + +EFI_STATUS +HBufferImageFree ( + VOID + ) ; + +EFI_STATUS +HBufferImageDeleteCharacterFromBuffer ( + IN UINTN, + IN UINTN, + UINT8 * + ); + +EFI_STATUS +HBufferImageAddCharacterToBuffer ( + IN UINTN, + IN UINTN, + UINT8 * + ); + +EFI_STATUS +HBufferImageBufferToList ( + IN VOID *, + IN UINTN + ); + +EFI_STATUS +HBufferImageListToBuffer ( + IN VOID *, + IN UINTN + ); + +VOID +HBufferImageAdjustMousePosition ( + INT32, + INT32 + ); + +BOOLEAN +HBufferImageIsAtHighBits ( + UINTN, + UINTN * + ) ; + +EFI_STATUS +HBufferImageCutLine ( + HEFI_EDITOR_LINE ** + ); + +UINTN +HBufferImageGetTotalSize ( + VOID + ); + +BOOLEAN +HBufferImageIsInSelectedArea ( + UINTN, + UINTN + ); + +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.c new file mode 100644 index 0000000000..2408027abb --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.c @@ -0,0 +1,112 @@ +/** @file + Functions to deal with Clip Board + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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" + +HEFI_EDITOR_CLIPBOARD HClipBoard; + +// +// for basic initialization of HClipBoard +// +HEFI_EDITOR_CLIPBOARD HClipBoardConst = { + NULL, + 0 +}; + +EFI_STATUS +HClipBoardInit ( + VOID + ) +/*++ + +Routine Description: + + Initialization function for HDiskImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + +--*/ +{ + // + // basiclly initialize the HDiskImage + // + CopyMem (&HClipBoard, &HClipBoardConst, sizeof (HClipBoard)); + + return EFI_SUCCESS; +} + +EFI_STATUS +HClipBoardCleanup ( + VOID + ) +/*++ + +Routine Description: + + Initialization function for HDiskImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + +--*/ +{ + + SHELL_FREE_NON_NULL (HClipBoard.Buffer); + + return EFI_SUCCESS; +} + +EFI_STATUS +HClipBoardSet ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + // + // free the old clipboard buffer + // and set new clipboard buffer + // + SHELL_FREE_NON_NULL (HClipBoard.Buffer); + HClipBoard.Buffer = Buffer; + + HClipBoard.Size = Size; + + return EFI_SUCCESS; +} + +UINTN +HClipBoardGet ( + OUT UINT8 **Buffer + ) +{ + // + // return the clipboard buffer + // + *Buffer = HClipBoard.Buffer; + + return HClipBoard.Size; +} diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.h new file mode 100644 index 0000000000..9165d98f30 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Clipboard.h @@ -0,0 +1,40 @@ +/** @file + Defines DiskImage - 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.
+ 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. + +**/ + +#ifndef _LIB_CLIP_BOARD_H_ +#define _LIB_CLIP_BOARD_H_ + +#include "HexEditor.h" + +EFI_STATUS +HClipBoardInit ( + VOID + ); +EFI_STATUS +HClipBoardCleanup ( + VOID + ); + +EFI_STATUS +HClipBoardSet ( + UINT8 *, + UINTN + ); +UINTN +HClipBoardGet ( + UINT8 ** + ); + +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.c new file mode 100644 index 0000000000..140db71671 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.c @@ -0,0 +1,487 @@ +/** @file + Functions to deal with Disk buffer. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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" +#include + +extern EFI_HANDLE HImageHandleBackup; +extern HEFI_EDITOR_BUFFER_IMAGE HBufferImage; + +extern BOOLEAN HBufferImageNeedRefresh; +extern BOOLEAN HBufferImageOnlyLineNeedRefresh; +extern BOOLEAN HBufferImageMouseNeedRefresh; + +extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; + +HEFI_EDITOR_DISK_IMAGE HDiskImage; +HEFI_EDITOR_DISK_IMAGE HDiskImageBackupVar; + +// +// for basic initialization of HDiskImage +// +HEFI_EDITOR_DISK_IMAGE HDiskImageConst = { + NULL, + 0, + 0, + 0 +}; + +EFI_STATUS +HDiskImageInit ( + VOID + ) +/*++ + +Routine Description: + + Initialization function for HDiskImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + +--*/ +{ + // + // basically initialize the HDiskImage + // + CopyMem (&HDiskImage, &HDiskImageConst, sizeof (HDiskImage)); + + CopyMem (&HDiskImageBackupVar, &HDiskImageConst, sizeof (HDiskImageBackupVar)); + + return EFI_SUCCESS; +} + +EFI_STATUS +HDiskImageBackup ( + VOID + ) +/*++ + +Routine Description: + + Backup function for HDiskImage + Only a few fields need to be backup. + This is for making the Disk buffer refresh + as few as possible. + +Arguments: + + None + +Returns: + + EFI_SUCCESS - Success + EFI_OUT_OF_RESOURCES - gST->ConOut of resources + +--*/ +{ + // + // backup the disk name, offset and size + // + // + SHELL_FREE_NON_NULL (HDiskImageBackupVar.Name); + + HDiskImageBackupVar.Name = CatSPrint(NULL, L"%s", HDiskImage.Name); + if (HDiskImageBackupVar.Name == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + HDiskImageBackupVar.Offset = HDiskImage.Offset; + HDiskImageBackupVar.Size = HDiskImage.Size; + + return EFI_SUCCESS; +} + +EFI_STATUS +HDiskImageCleanup ( + VOID + ) +/*++ + +Routine Description: + + Cleanup function for HDiskImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + SHELL_FREE_NON_NULL (HDiskImage.Name); + SHELL_FREE_NON_NULL (HDiskImageBackupVar.Name); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HDiskImageSetDiskNameOffsetSize ( + IN CONST CHAR16 *Str, + IN UINTN Offset, + IN UINTN Size + ) +/*++ + +Routine Description: + + Set FileName field in HFileImage + +Arguments: + + Str - File name to set + Offset - The offset + Size - The size + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + +--*/ +{ + UINTN Len; + UINTN Index; + + // + // free the old file name + // + SHELL_FREE_NON_NULL (HDiskImage.Name); + + Len = StrLen (Str); + + HDiskImage.Name = AllocateZeroPool (2 * (Len + 1)); + if (HDiskImage.Name == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < Len; Index++) { + HDiskImage.Name[Index] = Str[Index]; + } + + HDiskImage.Name[Len] = L'\0'; + + HDiskImage.Offset = Offset; + HDiskImage.Size = Size; + + return EFI_SUCCESS; +} + +EFI_STATUS +HDiskImageRead ( + IN CONST CHAR16 *DeviceName, + IN UINTN Offset, + IN UINTN Size, + IN BOOLEAN Recover + ) +/*++ + +Routine Description: + + Read a disk from disk into HBufferImage + +Arguments: + + DeviceName - filename to read + Offset - The offset + Size - The size + Recover - if is for recover, no information print + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + EFI_INVALID_PARAMETER + +--*/ +{ + CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DupDevicePath; + EFI_HANDLE Handle; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + EFI_STATUS Status; + + VOID *Buffer; + CHAR16 *Str; + UINTN Bytes; + + HEFI_EDITOR_LINE *Line; + UINT64 ByteOffset; + + EDIT_FILE_TYPE BufferTypeBackup; + + BufferTypeBackup = HBufferImage.BufferType; + HBufferImage.BufferType = FileTypeDiskBuffer; + + DevicePath = gEfiShellProtocol->GetDevicePathFromMap(DeviceName); + if (DevicePath == NULL) { + StatusBarSetStatusString (L"Cannot Find Device"); + return EFI_INVALID_PARAMETER; + } + DupDevicePath = DuplicateDevicePath(DevicePath); + // + // get blkio interface + // + Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid,&DupDevicePath,&Handle); + FreePool(DupDevicePath); + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Disk Failed"); + return Status; + } + Status = gBS->OpenProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID**)&BlkIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Disk Failed"); + return Status; + } + // + // if Offset exceeds LastBlock, + // return error + // + if (Offset > BlkIo->Media->LastBlock || Offset + Size > BlkIo->Media->LastBlock) { + StatusBarSetStatusString (L"Invalid Offset + Size"); + return EFI_LOAD_ERROR; + } + + Bytes = BlkIo->Media->BlockSize * Size; + Buffer = AllocateZeroPool (Bytes); + + if (Buffer == NULL) { + StatusBarSetStatusString (L"Read Disk Failed"); + return EFI_OUT_OF_RESOURCES; + } + + ByteOffset = MultU64x32 (Offset, BlkIo->Media->BlockSize); + + // + // read from disk + // + Status = BlkIo->ReadBlocks ( + BlkIo, + BlkIo->Media->MediaId, + Offset, + Bytes, + Buffer + ); + + if (EFI_ERROR (Status)) { + FreePool (Buffer); + StatusBarSetStatusString (L"Read Disk Failed"); + return EFI_LOAD_ERROR; + } + + HBufferImageFree (); + + // + // convert buffer to line list + // + Status = HBufferImageBufferToList (Buffer, Bytes); + FreePool (Buffer); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Disk Failed"); + return Status; + } + + Status = HDiskImageSetDiskNameOffsetSize (DeviceName, Offset, Size); + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Disk Failed"); + return EFI_OUT_OF_RESOURCES; + } + // + // initialize some variables + // + HDiskImage.BlockSize = BlkIo->Media->BlockSize; + + HBufferImage.DisplayPosition.Row = 2; + HBufferImage.DisplayPosition.Column = 10; + + HBufferImage.MousePosition.Row = 2; + HBufferImage.MousePosition.Column = 10; + + HBufferImage.LowVisibleRow = 1; + HBufferImage.HighBits = TRUE; + + HBufferImage.BufferPosition.Row = 1; + HBufferImage.BufferPosition.Column = 1; + + if (!Recover) { + Str = CatSPrint(NULL, L"%d Lines Read", HBufferImage.NumLines); + if (Str == NULL) { + StatusBarSetStatusString (L"Read Disk Failed"); + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (Str); + SHELL_FREE_NON_NULL (Str); + + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + + } + + // + // has line + // + if (HBufferImage.Lines != NULL) { + HBufferImage.CurrentLine = CR ( + HBufferImage.ListHead->ForwardLink, + HEFI_EDITOR_LINE, + Link, + EFI_EDITOR_LINE_LIST + ); + } else { + // + // create a dummy line + // + Line = HBufferImageCreateLine (); + if (Line == NULL) { + StatusBarSetStatusString (L"Read Disk Failed"); + return EFI_OUT_OF_RESOURCES; + } + + HBufferImage.CurrentLine = Line; + } + + HBufferImage.Modified = FALSE; + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageMouseNeedRefresh = TRUE; + + return EFI_SUCCESS; +} + +EFI_STATUS +HDiskImageSave ( + IN CHAR16 *DeviceName, + IN UINTN Offset, + IN UINTN Size + ) +/*++ + +Routine Description: + + Save lines in HBufferImage to disk + NOT ALLOW TO WRITE TO ANOTHER DISK!!!!!!!!! + +Arguments: + + DeviceName - The device name + Offset - The offset + Size - The size + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + EFI_INVALID_PARAMETER + +--*/ +{ + + CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DupDevicePath; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + EFI_STATUS Status; + EFI_HANDLE Handle; + VOID *Buffer; + UINTN Bytes; + + UINT64 ByteOffset; + + EDIT_FILE_TYPE BufferTypeBackup; + + // + // if not modified, directly return + // + if (HBufferImage.Modified == FALSE) { + return EFI_SUCCESS; + } + + BufferTypeBackup = HBufferImage.BufferType; + HBufferImage.BufferType = FileTypeDiskBuffer; + + DevicePath = gEfiShellProtocol->GetDevicePathFromMap(DeviceName); + if (DevicePath == NULL) { +// StatusBarSetStatusString (L"Cannot Find Device"); + return EFI_INVALID_PARAMETER; + } + DupDevicePath = DuplicateDevicePath(DevicePath); + + // + // get blkio interface + // + Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid,&DupDevicePath,&Handle); + FreePool(DupDevicePath); + if (EFI_ERROR (Status)) { +// StatusBarSetStatusString (L"Read Disk Failed"); + return Status; + } + Status = gBS->OpenProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID**)&BlkIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { +// StatusBarSetStatusString (L"Read Disk Failed"); + return Status; + } + + Bytes = BlkIo->Media->BlockSize * Size; + Buffer = AllocateZeroPool (Bytes); + + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // concatenate the line list to a buffer + // + Status = HBufferImageListToBuffer (Buffer, Bytes); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + + ByteOffset = MultU64x32 (Offset, BlkIo->Media->BlockSize); + + // + // write the buffer to disk + // + Status = BlkIo->WriteBlocks ( + BlkIo, + BlkIo->Media->MediaId, + Offset, + Bytes, + Buffer + ); + + FreePool (Buffer); + + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + // + // now not modified + // + HBufferImage.Modified = FALSE; + + return EFI_SUCCESS; +} diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.h new file mode 100644 index 0000000000..eaa8e2615d --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/DiskImage.h @@ -0,0 +1,48 @@ +/** @file + Defines DiskImage - 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.
+ 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. + +**/ + +#ifndef _LIB_DISK_IMAGE_H_ +#define _LIB_DISK_IMAGE_H_ + +#include "HexEditor.h" + +EFI_STATUS +HDiskImageInit ( + VOID + ); +EFI_STATUS +HDiskImageCleanup ( + VOID + ); +EFI_STATUS +HDiskImageBackup ( + VOID + ); + +EFI_STATUS +HDiskImageRead ( + IN CONST CHAR16 *, + IN UINTN, + IN UINTN, + IN BOOLEAN + ); +EFI_STATUS +HDiskImageSave ( + IN CHAR16 *, + IN UINTN, + IN UINTN + ); + +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c new file mode 100644 index 0000000000..adf7928197 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.c @@ -0,0 +1,504 @@ +/** @file + Functions to deal with file buffer. + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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_BUFFER_IMAGE HBufferImage; + +extern BOOLEAN HBufferImageNeedRefresh; +extern BOOLEAN HBufferImageOnlyLineNeedRefresh; +extern BOOLEAN HBufferImageMouseNeedRefresh; + +extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; + +HEFI_EDITOR_FILE_IMAGE HFileImage; +HEFI_EDITOR_FILE_IMAGE HFileImageBackupVar; + +// +// for basic initialization of HFileImage +// +HEFI_EDITOR_BUFFER_IMAGE HFileImageConst = { + NULL, + 0, + FALSE +}; + +EFI_STATUS +HFileImageInit ( + VOID + ) +/*++ + +Routine Description: + + Initialization function for HFileImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + +--*/ +{ + // + // basically initialize the HFileImage + // + CopyMem (&HFileImage, &HFileImageConst, sizeof (HFileImage)); + + CopyMem ( + &HFileImageBackupVar, + &HFileImageConst, + sizeof (HFileImageBackupVar) + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +HFileImageBackup ( + VOID + ) +/*++ + +Routine Description: + + Backup function for HFileImage + Only a few fields need to be backup. + This is for making the file buffer refresh + as few as possible. + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + +--*/ +{ + SHELL_FREE_NON_NULL (HFileImageBackupVar.FileName); + HFileImageBackupVar.FileName = CatSPrint(NULL, L"%s", HFileImage.FileName); + if (HFileImageBackupVar.FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +HFileImageCleanup ( + VOID + ) +/*++ + +Routine Description: + + Cleanup function for HFileImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + + SHELL_FREE_NON_NULL (HFileImage.FileName); + SHELL_FREE_NON_NULL (HFileImageBackupVar.FileName); + + return EFI_SUCCESS; +} + +EFI_STATUS +HFileImageSetFileName ( + IN CONST CHAR16 *Str + ) +/*++ + +Routine Description: + + Set FileName field in HFileImage + +Arguments: + + Str -- File name to set + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + +--*/ +{ + UINTN Size; + UINTN Index; + + // + // free the old file name + // + SHELL_FREE_NON_NULL (HFileImage.FileName); + + Size = StrLen (Str); + + HFileImage.FileName = AllocateZeroPool (2 * (Size + 1)); + if (HFileImage.FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < Size; Index++) { + HFileImage.FileName[Index] = Str[Index]; + } + + HFileImage.FileName[Size] = L'\0'; + + return EFI_SUCCESS; +} + +EFI_STATUS +HFileImageGetFileInfo ( + IN EFI_FILE_HANDLE Handle, + IN CHAR16 *FileName, + OUT EFI_FILE_INFO **InfoOut + ) +/*++ + +Routine Description: + + Get this file's information + +Arguments: + + Handle - in NT32 mode Directory handle, in other mode File Handle + FileName - The file name + InfoOut - parameter to pass file information out + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + EFI_LOAD_ERROR + +--*/ +{ + + VOID *Info; + UINTN Size; + EFI_STATUS Status; + + Size = SIZE_OF_EFI_FILE_INFO + 1024; + Info = AllocateZeroPool (Size); + if (!Info) { + return EFI_OUT_OF_RESOURCES; + } + // + // get file information + // + Status = Handle->GetInfo (Handle, &gEfiFileInfoGuid, &Size, Info); + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + + *InfoOut = (EFI_FILE_INFO *) Info; + + return EFI_SUCCESS; + +} + +EFI_STATUS +HFileImageRead ( + IN CONST CHAR16 *FileName, + IN BOOLEAN Recover + ) +/*++ + +Routine Description: + + Read a file from disk into HBufferImage + +Arguments: + + FileName -- filename to read + Recover -- if is for recover, no information print + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + HEFI_EDITOR_LINE *Line; + UINT8 *Buffer; + CHAR16 *UnicodeBuffer; + EFI_STATUS Status; + + // + // variable initialization + // + Line = NULL; + + // + // in this function, when you return error ( except EFI_OUT_OF_RESOURCES ) + // you should set status string + // since this function maybe called before the editorhandleinput loop + // so any error will cause editor return + // so if you want to print the error status + // you should set the status string + // + Status = ReadFileIntoBuffer (FileName, (VOID**)&Buffer, &HFileImage.Size, &HFileImage.ReadOnly); + if (EFI_ERROR(Status)) { + UnicodeBuffer = CatSPrint(NULL, L"Read error on file &s: %r", FileName, Status); + if (UnicodeBuffer == NULL) { + SHELL_FREE_NON_NULL(Buffer); + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (UnicodeBuffer); + FreePool (UnicodeBuffer); + } + + HFileImageSetFileName (FileName); + + // + // free the old lines + // + HBufferImageFree (); + + Status = HBufferImageBufferToList (Buffer, HFileImage.Size); + SHELL_FREE_NON_NULL (Buffer); + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Error parsing file."); + return Status; + } + + HBufferImage.DisplayPosition.Row = 2; + HBufferImage.DisplayPosition.Column = 10; + HBufferImage.MousePosition.Row = 2; + HBufferImage.MousePosition.Column = 10; + HBufferImage.LowVisibleRow = 1; + HBufferImage.HighBits = TRUE; + HBufferImage.BufferPosition.Row = 1; + HBufferImage.BufferPosition.Column = 1; + + if (!Recover) { + UnicodeBuffer = CatSPrint(NULL, L"%d Lines Read", HBufferImage.NumLines); + if (UnicodeBuffer == NULL) { + SHELL_FREE_NON_NULL(Buffer); + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (UnicodeBuffer); + FreePool (UnicodeBuffer); + + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + } + + // + // has line + // + if (HBufferImage.Lines != 0) { + HBufferImage.CurrentLine = CR (HBufferImage.ListHead->ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + } else { + // + // create a dummy line + // + Line = HBufferImageCreateLine (); + if (Line == NULL) { + SHELL_FREE_NON_NULL(Buffer); + return EFI_OUT_OF_RESOURCES; + } + + HBufferImage.CurrentLine = Line; + } + + HBufferImage.Modified = FALSE; + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageMouseNeedRefresh = TRUE; + + return EFI_SUCCESS; +} + +EFI_STATUS +HFileImageSave ( + IN CHAR16 *FileName + ) +/*++ + +Routine Description: + + Save lines in HBufferImage to disk + +Arguments: + + FileName - The file name + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + + LIST_ENTRY *Link; + HEFI_EDITOR_LINE *Line; + CHAR16 *Str; + EFI_STATUS Status; + UINTN NumLines; + SHELL_FILE_HANDLE FileHandle; + UINTN TotalSize; + UINT8 *Buffer; + UINT8 *Ptr; + EDIT_FILE_TYPE BufferTypeBackup; + + BufferTypeBackup = HBufferImage.BufferType; + HBufferImage.BufferType = FileTypeFileBuffer; + + // + // if is the old file + // + if (StrCmp (FileName, HFileImage.FileName) == 0) { + // + // check whether file exists on disk + // + if (ShellIsFile(FileName) == EFI_SUCCESS) { + // + // current file exists on disk + // so if not modified, then not save + // + if (HBufferImage.Modified == FALSE) { + return EFI_SUCCESS; + } + // + // if file is read-only, set error + // + if (HFileImage.ReadOnly == TRUE) { + StatusBarSetStatusString (L"Read Only File Can Not Be Saved"); + return EFI_SUCCESS; + } + } + } + + if (ShellIsDirectory(FileName) == EFI_SUCCESS) { + StatusBarSetStatusString (L"Directory Can Not Be Saved"); + return EFI_LOAD_ERROR; + } + + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); + + if (!EFI_ERROR (Status)) { + // + // the file exits, delete it + // + Status = ShellDeleteFile (&FileHandle); + if (EFI_ERROR (Status) || Status == EFI_WARN_DELETE_FAILURE) { + StatusBarSetStatusString (L"Write File Failed"); + return EFI_LOAD_ERROR; + } + } + + // + // write all the lines back to disk + // + NumLines = 0; + TotalSize = 0; + for (Link = HBufferImage.ListHead->ForwardLink; Link != HBufferImage.ListHead; Link = Link->ForwardLink) { + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + + if (Line->Size != 0) { + TotalSize += Line->Size; + } + // + // end of if Line -> Size != 0 + // + NumLines++; + } + // + // end of for Link + // + Buffer = AllocateZeroPool (TotalSize); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Ptr = Buffer; + for (Link = HBufferImage.ListHead->ForwardLink; Link != HBufferImage.ListHead; Link = Link->ForwardLink) { + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + + if (Line->Size != 0) { + CopyMem (Ptr, Line->Buffer, Line->Size); + Ptr += Line->Size; + } + // + // end of if Line -> Size != 0 + // + } + + + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Create File Failed"); + return EFI_LOAD_ERROR; + } + + Status = ShellWriteFile (FileHandle, &TotalSize, Buffer); + FreePool (Buffer); + if (EFI_ERROR (Status)) { + ShellDeleteFile (&FileHandle); + return EFI_LOAD_ERROR; + } + + ShellCloseFile(&FileHandle); + + HBufferImage.Modified = FALSE; + + // + // set status string + // + Str = CatSPrint(NULL, L"%d Lines Wrote", NumLines); + StatusBarSetStatusString (Str); + FreePool (Str); + + // + // now everything is ready , you can set the new file name to filebuffer + // + if (BufferTypeBackup != FileTypeFileBuffer || StringNoCaseCompare (&FileName, &HFileImage.FileName) != 0) { + // + // not the same + // + HFileImageSetFileName (FileName); + if (HFileImage.FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + HFileImage.ReadOnly = FALSE; + + return EFI_SUCCESS; +} diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.h new file mode 100644 index 0000000000..ae386d2fc9 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/FileImage.h @@ -0,0 +1,56 @@ +/** @file + Defines FileImage - 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.
+ 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. + +**/ + +#ifndef _LIB_FILE_IMAGE_H_ +#define _LIB_FILE_IMAGE_H_ + +#include "HexEditor.h" + +EFI_STATUS +HFileImageInit ( + VOID + ); +EFI_STATUS +HFileImageCleanup ( + VOID + ); +EFI_STATUS +HFileImageBackup ( + VOID + ); + +EFI_STATUS +HFileImageSetFileName ( + IN CONST CHAR16 * + ); + +EFI_STATUS +HFileImageGetFileInfo ( + EFI_FILE_HANDLE, + CHAR16 *, + EFI_FILE_INFO ** + ); + +EFI_STATUS +HFileImageRead ( + IN CONST CHAR16 *, + IN BOOLEAN + ); +EFI_STATUS +HFileImageSave ( + IN CHAR16 * + ); + +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEdit.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEdit.c new file mode 100644 index 0000000000..511eb9e636 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEdit.c @@ -0,0 +1,247 @@ +/** @file + Main entry point of editor + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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 "UefiShellDebug1CommandsLib.h" +#include "HexEditor.h" + +// +// Global Variables +// +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-f", TypeFlag}, + {L"-d", TypeFlag}, + {L"-m", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'hexedit' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunHexEdit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CHAR16 *Buffer; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + LIST_ENTRY *Package; + CONST CHAR16 *Cwd; + CHAR16 *NFS; + CHAR16 *Spot; + CONST CHAR16 *Name; + UINTN Offset; + UINTN Size; + UINT64 LastOffset; + EDIT_FILE_TYPE WhatToDo; + + Buffer = NULL; + ShellStatus = SHELL_SUCCESS; + NFS = NULL; + Cwd = NULL; + Buffer = NULL; + Name = NULL; + Spot = NULL; + Offset = 0; + Size = 0; + LastOffset = 0; + WhatToDo = FileTypeNone; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // Check for -d + // + if (ShellCommandLineGetFlag(Package, L"-d")){ + if (ShellCommandLineGetCount(Package) < 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) > 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + WhatToDo = FileTypeDiskBuffer; + Name = ShellCommandLineGetRawValue(Package, 1); + Offset = ShellStrToUintn(ShellCommandLineGetRawValue(Package, 2)); + Size = ShellStrToUintn(ShellCommandLineGetRawValue(Package, 3)); + } + } + + // + // check for -f + // + if (ShellCommandLineGetFlag(Package, L"-f") && (WhatToDo == FileTypeNone)){ + if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Name = ShellCommandLineGetRawValue(Package, 1); + if (!IsValidFileName(Name)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, Name); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + WhatToDo = FileTypeFileBuffer; + } + } + } + + // + // check for -m + // + if (ShellCommandLineGetFlag(Package, L"-m") && (WhatToDo == FileTypeNone)){ + if (ShellCommandLineGetCount(Package) < 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) > 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + WhatToDo = FileTypeMemBuffer; + Offset = ShellStrToUintn(ShellCommandLineGetRawValue(Package, 1)); + Size = ShellStrToUintn(ShellCommandLineGetRawValue(Package, 2)); + } + } + ShellCommandLineFreeVarList (Package); + + if (ShellStatus == SHELL_SUCCESS && WhatToDo == FileTypeNone) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } + + if (ShellStatus == SHELL_SUCCESS) { + // + // Do the editor + // + Status = HMainEditorInit (); + if (EFI_ERROR (Status)) { + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_INIT_FAILED), gShellDebug1HiiHandle); + } else { + HMainEditorBackup (); + switch (WhatToDo) { + case FileTypeFileBuffer: + Status = HBufferImageRead ( + Name, + NULL, + 0, + 0, + 0, + 0, + FileTypeFileBuffer, + FALSE + ); + break; + + case FileTypeDiskBuffer: + Status = HBufferImageRead ( + NULL, + Name, + Offset, + Size, + 0, + 0, + FileTypeDiskBuffer, + FALSE + ); + break; + + case FileTypeMemBuffer: + Status = HBufferImageRead ( + NULL, + NULL, + 0, + 0, + (UINT32) Offset, + Size, + FileTypeMemBuffer, + FALSE + ); + break; + + } + if (!EFI_ERROR (Status)) { + HMainEditorRefresh (); + Status = HMainEditorKeyInput (); + } + if (Status != EFI_OUT_OF_RESOURCES) { + // + // back up the status string + // + Buffer = CatSPrint (NULL, L"%s", StatusBarGetString()); + } + } + + // + // cleanup + // + HMainEditorCleanup (); + + if (!EFI_ERROR (Status)) { + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = SHELL_UNSUPPORTED; + } + } + + // + // print editor exit code on screen + // + if (Status == EFI_OUT_OF_RESOURCES) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellDebug1HiiHandle); + } else if (EFI_ERROR(Status)){ + if (Buffer != NULL) { + if (StrCmp (Buffer, L"") != 0) { + // + // print out the status string + // + ShellPrintEx(-1, -1, L"%s", gShellDebug1HiiHandle, Buffer); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_UNKNOWN_EDITOR), gShellDebug1HiiHandle); + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_UNKNOWN_EDITOR), gShellDebug1HiiHandle); + } + } + } + } + + SHELL_FREE_NON_NULL (Buffer); + return ShellStatus; +} diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditor.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditor.h new file mode 100644 index 0000000000..d0a4bf4aae --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditor.h @@ -0,0 +1,41 @@ +/** @file + Main include file for hex editor + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef _EFI_SHELL_HEXEDIT_H_ +#define _EFI_SHELL_HEXEDIT_H_ + +#include "UefiShellDebug1CommandsLib.h" +#include "HexEditorTypes.h" + +#include "MainHexEditor.h" + +#include "BufferImage.h" +#include "FileImage.h" +#include "DiskImage.h" +#include "MemImage.h" + +#include "EditTitleBar.h" +#include "EditStatusBar.h" +#include "EditInputBar.h" +#include "EditMenuBar.h" + +#include "Misc.h" + +#include "Clipboard.h" + +extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; +extern BOOLEAN HEditorFirst; +extern BOOLEAN HEditorExit; + +#endif // _HEDITOR_H diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditorTypes.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditorTypes.h new file mode 100644 index 0000000000..51c9f44cd5 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexEditorTypes.h @@ -0,0 +1,132 @@ +/** @file + data types that are used by editor + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef _HEDITOR_TYPE_H_ +#define _HEDITOR_TYPE_H_ + +#include "UefiShellDebug1CommandsLib.h" +#include "EditTitleBar.h" + +#define EFI_EDITOR_LINE_LIST 'eell' + +#define ASCII_POSITION ((0x10 * 3) + 12) + + +typedef struct { + UINTN Row; + UINTN Column; +} HEFI_EDITOR_POSITION; + +typedef +EFI_STATUS +(*HEFI_MENU_ITEM_FUNCTION) ( + VOID + ); + +typedef struct { + CHAR16 Name[50]; + CHAR16 Key[3]; + HEFI_MENU_ITEM_FUNCTION Function; +} HMENU_ITEMS; + +typedef struct _HEFI_EDITOR_LINE { + UINTN Signature; + UINT8 Buffer[0x10]; + UINTN Size; // unit is Unicode + LIST_ENTRY Link; +} HEFI_EDITOR_LINE; + +typedef struct _HEFI_EDITOR_MENU_ITEM { + CHAR16 NameToken; + CHAR16 FunctionKeyToken; + HEFI_MENU_ITEM_FUNCTION Function; +} HEFI_EDITOR_MENU_ITEM; + +typedef struct { + UINT32 Foreground : 4; + UINT32 Background : 4; +} HEFI_EDITOR_COLOR_ATTRIBUTES; + +typedef union { + HEFI_EDITOR_COLOR_ATTRIBUTES Colors; + UINT8 Data; +} HEFI_EDITOR_COLOR_UNION; + +typedef struct { + UINTN Columns; + UINTN Rows; +} HEFI_EDITOR_TEXT_MODE; + + +typedef struct { + CHAR16 *Name; + + UINTN BlockSize; + UINTN Size; + UINTN Offset; +} HEFI_EDITOR_DISK_IMAGE; + +typedef struct { + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoFncs; + + UINTN Offset; + UINTN Size; +} HEFI_EDITOR_MEM_IMAGE; + +typedef struct { + CHAR16 *FileName; + UINTN Size; // file size + BOOLEAN ReadOnly; // file is read-only or not +} HEFI_EDITOR_FILE_IMAGE; + +typedef struct { + LIST_ENTRY *ListHead; // list head of lines + HEFI_EDITOR_LINE *Lines; // lines of current file + UINTN NumLines; // number of lines + HEFI_EDITOR_LINE *CurrentLine; // current line cursor is at + HEFI_EDITOR_POSITION DisplayPosition; // cursor position in screen + HEFI_EDITOR_POSITION MousePosition; // mouse position in screen + HEFI_EDITOR_POSITION BufferPosition; // cursor position in buffer + UINTN LowVisibleRow; // the lowest visible row of file position + BOOLEAN HighBits; // cursor is at the high4 bits or low4 bits + BOOLEAN Modified; // BUFFER is modified or not + EDIT_FILE_TYPE BufferType; + + HEFI_EDITOR_FILE_IMAGE *FileImage; + HEFI_EDITOR_DISK_IMAGE *DiskImage; + HEFI_EDITOR_MEM_IMAGE *MemImage; + +} HEFI_EDITOR_BUFFER_IMAGE; + +typedef struct { + UINT8 *Buffer; + UINTN Size; +} HEFI_EDITOR_CLIPBOARD; + +typedef struct { + HEFI_EDITOR_BUFFER_IMAGE *BufferImage; + HEFI_EDITOR_CLIPBOARD *Clipboard; + + HEFI_EDITOR_COLOR_UNION ColorAttributes; + HEFI_EDITOR_POSITION ScreenSize; // row number and column number + BOOLEAN MouseSupported; + EFI_SIMPLE_POINTER_PROTOCOL *MouseInterface; + INT32 MouseAccumulatorX; + INT32 MouseAccumulatorY; + + UINTN SelectStart; // starting from 1 + UINTN SelectEnd; // starting from 1 +} HEFI_EDITOR_GLOBAL_EDITOR; + +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexeditStrings.uni b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexeditStrings.uni new file mode 100644 index 0000000000..3389444f62 Binary files /dev/null and b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/HexeditStrings.uni differ diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.c new file mode 100644 index 0000000000..387a1e2d1e --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.c @@ -0,0 +1,2294 @@ +/** @file + Defines the Main Editor data type - + - Global variables + - Instances of the other objects of the editor + - Main Interfaces + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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" +#include "EditStatusBar.h" +#include "EditInputBar.h" + +HEFI_EDITOR_COLOR_ATTRIBUTES HOriginalColors; +INTN HOriginalMode; + +// +// the first time editor launch +// +BOOLEAN HEditorFirst; + +// +// it's time editor should exit +// +BOOLEAN HEditorExit; + +BOOLEAN HEditorMouseAction; + +extern HEFI_EDITOR_BUFFER_IMAGE HBufferImage; +extern HEFI_EDITOR_BUFFER_IMAGE HBufferImageBackupVar; + +extern HEFI_EDITOR_CLIPBOARD HClipBoard; + +extern BOOLEAN HBufferImageMouseNeedRefresh; +extern BOOLEAN HBufferImageNeedRefresh; +extern BOOLEAN HBufferImageOnlyLineNeedRefresh; + +HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; +HEFI_EDITOR_GLOBAL_EDITOR HMainEditorBackupVar; + +// +// basic initialization for MainEditor +// +HEFI_EDITOR_GLOBAL_EDITOR HMainEditorConst = { + &HBufferImage, + &HClipBoard, + { + 0, + 0 + }, + { + 0, + 0 + }, + FALSE, + NULL, + 0, + 0, + 1, + 1 +}; + +EFI_STATUS +HMainCommandGoToOffset ( + VOID + ) +/*++ + +Routine Description: + + move cursor to specified lines + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + UINTN Size; + UINT64 Offset; + EFI_STATUS Status; + UINTN FRow; + UINTN FCol; + + // + // variable initialization + // + Size = 0; + Offset = 0; + FRow = 0; + FCol = 0; + + // + // get offset + // + Status = InputBarSetPrompt (L"Go To Offset: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (8); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + Status = ShellConvertStringToUint64 (InputBarGetString(), &Offset, TRUE, FALSE); + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Invalid Offset"); + return EFI_SUCCESS; + } + + break; + } + } + + Size = HBufferImageGetTotalSize (); + if (Offset >= Size) { + StatusBarSetStatusString (L"Invalid Offset"); + return EFI_SUCCESS; + } + + FRow = (UINTN)DivU64x32(Offset , 0x10) + 1; + FCol = (UINTN)ModU64x32(Offset , 0x10) + 1; + + HBufferImageMovePosition (FRow, FCol, TRUE); + + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageMouseNeedRefresh = TRUE; + + return EFI_SUCCESS; +} + +EFI_STATUS +HMainCommandSaveBuffer ( + VOID + ) +/*++ + +Routine Description: + + save current opened buffer . + if is file buffer, you can save to current file name or + save to another file name + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + EFI_LOAD_ERROR + +--*/ +{ + EFI_STATUS Status; + BOOLEAN Done; + CHAR16 *FileName; + BOOLEAN OldFile; + CHAR16 *Str; + EFI_FILE_INFO *Info; + SHELL_FILE_HANDLE ShellFileHandle; + + if (HMainEditor.BufferImage->BufferType != FileTypeFileBuffer) { + if (HMainEditor.BufferImage->Modified == FALSE) { + return EFI_SUCCESS; + } + + Status = InputBarSetPrompt (L"Dangerous to save disk/mem buffer. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // the answer is just one character + // + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + // + // loop for user's answer + // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' + // + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // want to save this buffer first + // + Status = HBufferImageSave ( + NULL, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + HMainEditor.BufferImage->BufferType + ); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"BufferSave: Problems Writing"); + return Status; + } + + return EFI_SUCCESS; + + case L'n': + case L'N': + // + // the file won't be saved + // + return EFI_SUCCESS; + break; + + case L'c': + case L'C': + return EFI_SUCCESS; + } + // + // end of switch + // + } + // + // ENDOF WHILE + // + } + // + // ENDOF != FILEBUFFER + // + // This command will save currently opened file to disk. + // You can choose save to another file name or just save to + // current file name. + // Below is the scenario of Save File command: ( + // Suppose the old file name is A ) + // 1. An Input Bar will be prompted: "File To Save: [ old file name]" + // IF user press ESC, Save File command ends . + // IF user press Enter, input file name will be A. + // IF user inputs a new file name B, input file name will be B. + // + // 2. IF input file name is A, go to do Step 3. + // IF input file name is B, go to do Step 4. + // + // 3. IF A is read only, Status Bar will show "Access Denied" + // and Save File commands ends. + // IF A is not read only, save file buffer to disk + // and remove Modified flag in Title Bar , then Save File command ends. + // + // 4. IF B does not exist, create this file and save file buffer to it. + // Go to do Step 7. + // IF B exits, do Step 5. + // + // 5. An Input Bar will be prompted: + // "File Exists. Overwrite ( Yes/No/Cancel ) ?" + // IF user press 'y' or 'Y', do Step 6. + // IF user press 'n' or 'N', Save File commands ends. + // IF user press 'c' or 'C' or ESC, Save File commands ends. + // + // 6. IF B is a read-only file, Status Bar will show "Access Denied" + // and Save File commands ends. + // IF B can be read and write, save file buffer to B. + // + // 7. Update File Name field in Title Bar to B + // and remove the Modified flag in Title Bar. + // + Str = CatSPrint(NULL, + L"File to Save: [%s]", + HMainEditor.BufferImage->FileImage->FileName + ); + if (Str == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (StrLen (Str) >= 50) { + // + // replace the long file name with "..." + // + Str[46] = L'.'; + Str[47] = L'.'; + Str[48] = L'.'; + Str[49] = L']'; + Str[50] = L'\0'; + } + + Status = InputBarSetPrompt (Str); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (100); + if (EFI_ERROR (Status)) { + return Status; + } + // + // get new file name + // + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // if user pressed ESC + // + if (Status == EFI_NOT_READY) { + SHELL_FREE_NON_NULL (Str); + return EFI_SUCCESS; + } + + SHELL_FREE_NON_NULL (Str); + + // + // if just enter pressed, so think save to current file name + // + if (StrLen (InputBarGetString()) == 0) { + FileName = CatSPrint(NULL, + L"%s", + HMainEditor.BufferImage->FileImage->FileName + ); + } else { + FileName = CatSPrint(NULL, L"%s", InputBarGetString()); + } + + if (FileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (!IsValidFileName (FileName)) { + StatusBarSetStatusString (L"Invalid File Name"); + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } + + OldFile = FALSE; + + // + // save to the old file + // + if (StringNoCaseCompare ( + &FileName, + &HMainEditor.BufferImage->FileImage->FileName + ) == 0) { + OldFile = TRUE; + } + + if (OldFile) { + // + // if the file is read only, so can not write back to it. + // + if (HMainEditor.BufferImage->FileImage->ReadOnly == TRUE) { + StatusBarSetStatusString (L"Access Denied"); + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } + } else { + Status = ShellOpenFileByName (FileName, &ShellFileHandle, EFI_FILE_MODE_READ, 0); + + if (!EFI_ERROR (Status)) { + + Info = ShellGetFileInfo(ShellFileHandle); + + ShellCloseFile(&ShellFileHandle); + // + // check if read only + // + if (Info->Attribute & EFI_FILE_READ_ONLY) { + StatusBarSetStatusString (L"Access Denied"); + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } + + SHELL_FREE_NON_NULL(Info); + // + // ask user whether to overwrite this file + // + Status = InputBarSetPrompt (L"File exists. Overwrite (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (FileName); + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + SHELL_FREE_NON_NULL (FileName); + return Status; + } + + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + if (Status == EFI_NOT_READY) { + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + Done = TRUE; + break; + case L'n': + case L'N': + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + case L'c': + case L'C': + SHELL_FREE_NON_NULL (FileName); + return EFI_SUCCESS; + } // switch + } // while + } // if opened existing file + } // if OldFile + + // + // save file back to disk + // + Status = HBufferImageSave ( + FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + FileTypeFileBuffer + ); + SHELL_FREE_NON_NULL (FileName); + + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +HMainCommandSelectStart ( + VOID + ) +/*++ + +Routine Description: + + Load a disk buffer editor + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + UINTN Start; + + Start = (HMainEditor.BufferImage->BufferPosition.Row - 1) * 0x10 + HMainEditor.BufferImage->BufferPosition.Column; + + // + // last line + // + if (HMainEditor.BufferImage->CurrentLine->Link.ForwardLink == HMainEditor.BufferImage->ListHead) { + if (HMainEditor.BufferImage->BufferPosition.Column > HMainEditor.BufferImage->CurrentLine->Size) { + StatusBarSetStatusString (L"Invalid Block Start"); + return EFI_LOAD_ERROR; + } + } + + if (HMainEditor.SelectEnd != 0 && Start > HMainEditor.SelectEnd) { + StatusBarSetStatusString (L"Invalid Block Start"); + return EFI_LOAD_ERROR; + } + + HMainEditor.SelectStart = Start; + + HBufferImageNeedRefresh = TRUE; + + return EFI_SUCCESS; +} + +EFI_STATUS +HMainCommandSelectEnd ( + VOID + ) +/*++ + +Routine Description: + + Load a disk buffer editor + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + UINTN End; + + End = (HMainEditor.BufferImage->BufferPosition.Row - 1) * 0x10 + HMainEditor.BufferImage->BufferPosition.Column; + + // + // last line + // + if (HMainEditor.BufferImage->CurrentLine->Link.ForwardLink == HMainEditor.BufferImage->ListHead) { + if (HMainEditor.BufferImage->BufferPosition.Column > HMainEditor.BufferImage->CurrentLine->Size) { + StatusBarSetStatusString (L"Invalid Block End"); + return EFI_LOAD_ERROR; + } + } + + if (HMainEditor.SelectStart != 0 && End < HMainEditor.SelectStart) { + StatusBarSetStatusString (L"Invalid Block End"); + return EFI_SUCCESS; + } + + HMainEditor.SelectEnd = End; + + HBufferImageNeedRefresh = TRUE; + + return EFI_SUCCESS; +} + +EFI_STATUS +HMainCommandCut ( + VOID + ) +/*++ + +Routine Description: + + cut current line to clipboard + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + EFI_LOAD_ERROR + +--*/ +{ + UINTN Index; + HEFI_EDITOR_LINE *Line; + LIST_ENTRY *Link; + UINT8 *Buffer; + UINTN Count; + + // + // not select, so not allowed to cut + // + if (HMainEditor.SelectStart == 0) { + StatusBarSetStatusString (L"No Block is Selected"); + return EFI_SUCCESS; + } + // + // not select, so not allowed to cut + // + if (HMainEditor.SelectEnd == 0) { + StatusBarSetStatusString (L"No Block is Selected"); + return EFI_SUCCESS; + } + + Link = HMainEditor.BufferImage->ListHead->ForwardLink; + for (Index = 0; Index < (HMainEditor.SelectEnd - 1) / 0x10; Index++) { + Link = Link->ForwardLink; + } + + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + + Count = HMainEditor.SelectEnd - HMainEditor.SelectStart + 1; + Buffer = AllocateZeroPool (Count); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // cut the selected area + // + HBufferImageDeleteCharacterFromBuffer ( + HMainEditor.SelectStart - 1, + Count, + Buffer + ); + + // + // put to clipboard + // + HClipBoardSet (Buffer, Count); + + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + + if (!HMainEditor.BufferImage->Modified) { + HMainEditor.BufferImage->Modified = TRUE; + } + + // + // now no select area + // + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +HMainCommandPaste ( + VOID + ) +/*++ + +Routine Description: + + paste line to file buffer + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + EFI_LOAD_ERROR + + +--*/ +{ + + BOOLEAN OnlyLineRefresh; + HEFI_EDITOR_LINE *Line; + UINT8 *Buffer; + UINTN Count; + UINTN FPos; + + Count = HClipBoardGet (&Buffer); + if (Count == 0 || Buffer == NULL) { + StatusBarSetStatusString (L"Nothing to Paste"); + return EFI_SUCCESS; + } + + Line = HMainEditor.BufferImage->CurrentLine; + + OnlyLineRefresh = FALSE; + if (Line->Link.ForwardLink == HMainEditor.BufferImage->ListHead && Line->Size + Count < 0x10) { + // + // is at last line, and after paste will not exceed + // so only this line need to be refreshed + // + // if after add, the line is 0x10, then will append a new line + // so the whole page will need be refreshed + // + OnlyLineRefresh = TRUE; + + } + + FPos = 0x10 * (HMainEditor.BufferImage->BufferPosition.Row - 1) + HMainEditor.BufferImage->BufferPosition.Column - 1; + + HBufferImageAddCharacterToBuffer (FPos, Count, Buffer); + + if (OnlyLineRefresh) { + HBufferImageNeedRefresh = FALSE; + HBufferImageOnlyLineNeedRefresh = TRUE; + } else { + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + } + + if (!HMainEditor.BufferImage->Modified) { + HMainEditor.BufferImage->Modified = TRUE; + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +HMainCommandExit ( + VOID + ) +/*++ + +Routine Description: + + exit editor + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + EFI_LOAD_ERROR + +--*/ +{ + EFI_STATUS Status; + + // + // Below is the scenario of Exit command: + // 1. IF currently opened file is not modified, exit the editor and + // Exit command ends. + // IF currently opened file is modified, do Step 2 + // + // 2. An Input Bar will be prompted: + // "File modified. Save ( Yes/No/Cancel )?" + // IF user press 'y' or 'Y', currently opened file will be saved and + // Editor exits + // IF user press 'n' or 'N', currently opened file will not be saved + // and Editor exits. + // IF user press 'c' or 'C' or ESC, Exit command ends. + // + // + // if file has been modified, so will prompt user + // whether to save the changes + // + if (HMainEditor.BufferImage->Modified) { + + Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // write file back to disk + // + Status = HBufferImageSave ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + HMainEditor.BufferImage->BufferType + ); + if (!EFI_ERROR (Status)) { + HEditorExit = TRUE; + } + + return Status; + + case L'n': + case L'N': + HEditorExit = TRUE; + return EFI_SUCCESS; + + case L'c': + case L'C': + return EFI_SUCCESS; + + } + } + } + + HEditorExit = TRUE; + return EFI_SUCCESS; + +} + +EFI_STATUS +HMainCommandOpenFile ( + VOID + ) +/*++ + +Routine Description: + + Load a file from disk to editor + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + BOOLEAN Done; + EFI_STATUS Status; + EDIT_FILE_TYPE BufferType; + + BufferType = HMainEditor.BufferImage->BufferType; + + // + // This command will open a file from current working directory. + // Read-only file can also be opened. But it can not be modified. + // Below is the scenario of Open File command: + // 1. IF currently opened file has not been modified, directly go to step . + // IF currently opened file has been modified, an Input Bar will be + // prompted as : + // "File Modified. Save ( Yes/No/Cancel) ?" + // IF user press 'y' or 'Y', currently opened file will be saved. + // IF user press 'n' or 'N', currently opened file will + // not be saved. + // IF user press 'c' or 'C' or ESC, Open File command ends and + // currently opened file is still opened. + // + // 2. An Input Bar will be prompted as : "File Name to Open: " + // IF user press ESC, Open File command ends and + // currently opened file is still opened. + // Any other inputs with a Return will cause + // currently opened file close. + // + // 3. IF user input file name is an existing file , + // this file will be read and opened. + // IF user input file name is a new file, this file will be created + // and opened. This file's type ( UNICODE or ASCII ) is the same with + // the old file. + // + // + // if current file is modified, so you need to choose whether to + // save it first. + // + if (HMainEditor.BufferImage->Modified) { + + Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // the answer is just one character + // + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + // + // loop for user's answer + // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' + // + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // want to save this buffer first + // + Status = HBufferImageSave ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + HMainEditor.BufferImage->BufferType + ); + if (EFI_ERROR (Status)) { + return Status; + } + + MainTitleBarRefresh ( + HMainEditor.BufferImage->BufferType == FileTypeFileBuffer?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Name:NULL, + HMainEditor.BufferImage->BufferType, + HMainEditor.BufferImage->FileImage->ReadOnly, + FALSE, + HMainEditor.ScreenSize.Column, + HMainEditor.ScreenSize.Row + ); + Done = TRUE; + break; + + case L'n': + case L'N': + // + // the file won't be saved + // + Done = TRUE; + break; + + case L'c': + case L'C': + return EFI_SUCCESS; + } + } + } + // + // TO get the open file name + // + Status = InputBarSetPrompt (L"File Name to Open: "); + if (EFI_ERROR (Status)) { + HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + return Status; + } + + Status = InputBarSetStringSize (100); + if (EFI_ERROR (Status)) { + Status = HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + Status = HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + + return Status; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + // + // CHECK if filename's valid + // + if (!IsValidFileName (InputBarGetString())) { + HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + + StatusBarSetStatusString (L"Invalid File Name"); + return EFI_SUCCESS; + } + + break; + } + } + // + // read from disk + // + Status = HBufferImageRead ( + InputBarGetString(), + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + FileTypeFileBuffer, + FALSE + ); + + if (EFI_ERROR (Status)) { + HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +HMainCommandOpenDisk ( + VOID + ) +/*++ + +Routine Description: + + Load a disk buffer editor + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + EFI_NOT_FOUND + +--*/ +{ + UINT64 Size; + UINT64 Offset; + CHAR16 *DeviceName; + EFI_STATUS Status; + BOOLEAN Done; + + EDIT_FILE_TYPE BufferType; + + // + // variable initialization + // + Size = 0; + Offset = 0; + BufferType = HMainEditor.BufferImage->BufferType; + + // + // if current file is modified, so you need to choose + // whether to save it first. + // + if (HMainEditor.BufferImage->Modified) { + + Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // the answer is just one character + // + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + // + // loop for user's answer + // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' + // + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // want to save this buffer first + // + Status = HBufferImageSave ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType + ); + if (EFI_ERROR (Status)) { + return Status; + } + + MainTitleBarRefresh ( + HMainEditor.BufferImage->BufferType == FileTypeFileBuffer?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Name:NULL, + HMainEditor.BufferImage->BufferType, + HMainEditor.BufferImage->FileImage->ReadOnly, + FALSE, + HMainEditor.ScreenSize.Column, + HMainEditor.ScreenSize.Row + ); + Done = TRUE; + break; + + case L'n': + case L'N': + // + // the file won't be saved + // + Done = TRUE; + break; + + case L'c': + case L'C': + return EFI_SUCCESS; + } + } + } + // + // get disk block device name + // + Status = InputBarSetPrompt (L"Block Device to Open: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (100); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + break; + } + } + + DeviceName = CatSPrint(NULL, L"%s", InputBarGetString()); + if (DeviceName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // get starting offset + // + Status = InputBarSetPrompt (L"First Block No.: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (16); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + Status = ShellConvertStringToUint64 (InputBarGetString(), &Offset, TRUE, FALSE); + if (EFI_ERROR (Status)) { + continue; + } + + break; + } + } + // + // get Number of Blocks: + // + Status = InputBarSetPrompt (L"Number of Blocks: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (8); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + Status = ShellConvertStringToUint64 (InputBarGetString(), &Size, TRUE, FALSE); + if (EFI_ERROR (Status)) { + continue; + } + + if (Size == 0) { + continue; + } + + break; + } + } + + Status = HBufferImageRead ( + NULL, + DeviceName, + (UINTN)Offset, + (UINTN)Size, + 0, + 0, + FileTypeDiskBuffer, + FALSE + ); + + if (EFI_ERROR (Status)) { + + HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +HMainCommandOpenMemory ( + VOID + ) +/*++ + +Routine Description: + + Load memory content to editor + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + EFI_NOT_FOUND + +--*/ +{ + UINT64 Size; + UINT64 Offset; + EFI_STATUS Status; + BOOLEAN Done; + EDIT_FILE_TYPE BufferType; + + // + // variable initialization + // + Size = 0; + Offset = 0; + BufferType = HMainEditor.BufferImage->BufferType; + + // + // if current buffer is modified, so you need to choose + // whether to save it first. + // + if (HMainEditor.BufferImage->Modified) { + + Status = InputBarSetPrompt (L"Buffer modified. Save (Yes/No/Cancel) ? "); + if (EFI_ERROR (Status)) { + return Status; + } + // + // the answer is just one character + // + Status = InputBarSetStringSize (1); + if (EFI_ERROR (Status)) { + return Status; + } + // + // loop for user's answer + // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' + // + Done = FALSE; + while (!Done) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + return EFI_SUCCESS; + } + + switch (InputBarGetString()[0]) { + case L'y': + case L'Y': + // + // want to save this buffer first + // + Status = HBufferImageSave ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType + ); + if (EFI_ERROR (Status)) { + return Status; + } + + MainTitleBarRefresh ( + HMainEditor.BufferImage->BufferType == FileTypeFileBuffer?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Name:NULL, + HMainEditor.BufferImage->BufferType, + HMainEditor.BufferImage->FileImage->ReadOnly, + FALSE, + HMainEditor.ScreenSize.Column, + HMainEditor.ScreenSize.Row + ); + Done = TRUE; + break; + + case L'n': + case L'N': + // + // the file won't be saved + // + Done = TRUE; + break; + + case L'c': + case L'C': + return EFI_SUCCESS; + } + } + } + // + // get starting offset + // + Status = InputBarSetPrompt (L"Starting Offset: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (8); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + Status = ShellConvertStringToUint64 (InputBarGetString(), &Offset, TRUE, FALSE); + if (EFI_ERROR (Status)) { + continue; + } + + break; + } + } + // + // get Number of Blocks: + // + Status = InputBarSetPrompt (L"Buffer Size: "); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InputBarSetStringSize (8); + if (EFI_ERROR (Status)) { + return Status; + } + + while (1) { + Status = InputBarRefresh (HMainEditor.ScreenSize.Row, HMainEditor.ScreenSize.Column); + + // + // ESC pressed + // + if (Status == EFI_NOT_READY) { + + return EFI_SUCCESS; + } + // + // THE input string length should > 0 + // + if (StrLen (InputBarGetString()) > 0) { + Status = ShellConvertStringToUint64 (InputBarGetString(), &Size, TRUE, FALSE); + if (EFI_ERROR (Status)) { + continue; + } + + if (Size == 0) { + continue; + } + + break; + } + } + + if ((Offset + Size - 1)> 0xffffffff) { + StatusBarSetStatusString (L"Invalid parameter"); + return EFI_LOAD_ERROR; + } + + Status = HBufferImageRead ( + NULL, + NULL, + 0, + 0, + (UINTN)Offset, + (UINTN)Size, + FileTypeMemBuffer, + FALSE + ); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Device Error!"); + HBufferImageRead ( + HMainEditor.BufferImage->FileImage->FileName, + HMainEditor.BufferImage->DiskImage->Name, + HMainEditor.BufferImage->DiskImage->Offset, + HMainEditor.BufferImage->DiskImage->Size, + HMainEditor.BufferImage->MemImage->Offset, + HMainEditor.BufferImage->MemImage->Size, + BufferType, + TRUE + ); + return EFI_NOT_FOUND; + } + return EFI_SUCCESS; + +} + +CONST EDITOR_MENU_ITEM HexEditorMenuItems[] = { + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_GO_TO_OFFSET), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F1), + HMainCommandGoToOffset + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_SAVE_BUFFER), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F2), + HMainCommandSaveBuffer + }, + { + STRING_TOKEN(STR_EDIT_LIBMENUBAR_EXIT), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F3), + HMainCommandExit + }, + + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_SELECT_START), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F4), + HMainCommandSelectStart + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_SELECT_END), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F5), + HMainCommandSelectEnd + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_CUT), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F6), + HMainCommandCut + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_PASTE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F7), + HMainCommandPaste + }, + + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_OPEN_FILE), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F8), + HMainCommandOpenFile + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_OPEN_DISK), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F9), + HMainCommandOpenDisk + }, + { + STRING_TOKEN(STR_HEXEDIT_LIBMENUBAR_OPEN_MEMORY), + STRING_TOKEN(STR_EDIT_LIBMENUBAR_F10), + HMainCommandOpenMemory + }, + + { + 0, + 0, + NULL + } +}; + + +EFI_STATUS +HMainEditorInit ( + VOID + ) +/*++ + +Routine Description: + + Init function for MainEditor + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + + // + // basic initialization + // + CopyMem (&HMainEditor, &HMainEditorConst, sizeof (HMainEditor)); + + // + // set screen attributes + // + HMainEditor.ColorAttributes.Colors.Foreground = gST->ConOut->Mode->Attribute & 0x000000ff; + + HMainEditor.ColorAttributes.Colors.Background = (UINT8) (gST->ConOut->Mode->Attribute >> 4); + + HOriginalColors = HMainEditor.ColorAttributes.Colors; + + HOriginalMode = gST->ConOut->Mode->Mode; + + // + // query screen size + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &(HMainEditor.ScreenSize.Column), + &(HMainEditor.ScreenSize.Row) + ); + + // + // Find mouse in System Table ConsoleInHandle + // + Status = gBS->HandleProtocol ( + gST->ConIn, + &gEfiSimplePointerProtocolGuid, + (VOID**)&HMainEditor.MouseInterface + ); + if (EFI_ERROR (Status)) { + // + // If there is no Simple Pointer Protocol on System Table + // + HandleBuffer = NULL; + HMainEditor.MouseInterface = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimplePointerProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (!EFI_ERROR (Status) && HandleCount > 0) { + // + // Try to find the first available mouse device + // + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiSimplePointerProtocolGuid, + (VOID**)&HMainEditor.MouseInterface + ); + if (!EFI_ERROR (Status)) { + break; + } + } + } + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + } + + if (!EFI_ERROR (Status) && HMainEditor.MouseInterface != NULL) { + HMainEditor.MouseAccumulatorX = 0; + HMainEditor.MouseAccumulatorY = 0; + HMainEditor.MouseSupported = TRUE; + } + + // + // below will call the five components' init function + // + Status = MainTitleBarInit (NULL); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_TITLE), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + Status = MenuBarInit (HexEditorMenuItems); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_MAINMENU), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + Status = StatusBarInit (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_STATUS), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + InputBarInit (); + + Status = HBufferImageInit (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_BUFFERIMAGE), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + + Status = HClipBoardInit (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_MAINEDITOR_CLIPBOARD), gShellDebug1HiiHandle); + return EFI_LOAD_ERROR; + } + // + // clear whole screen and enable cursor + // + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + // + // initialize EditorFirst and EditorExit + // + HEditorFirst = TRUE; + HEditorExit = FALSE; + HEditorMouseAction = FALSE; + + return EFI_SUCCESS; +} + +EFI_STATUS +HMainEditorCleanup ( + VOID + ) +/*++ + +Routine Description: + + cleanup function for MainEditor + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + +--*/ +{ + EFI_STATUS Status; + + // + // call the five components' cleanup function + // + MainTitleBarCleanup (); + + MenuBarCleanup (); + + StatusBarCleanup (); + + InputBarCleanup (); + + Status = HBufferImageCleanup (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_BUFFERIMAGE_CLEAN), gShellDebug1HiiHandle); + } + + Status = HClipBoardCleanup (); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HEXEDIT_LIBEDITOR_CLIPBOARD_CLEAN), gShellDebug1HiiHandle); + } + // + // restore old mode + // + if (HOriginalMode != gST->ConOut->Mode->Mode) { + gST->ConOut->SetMode (gST->ConOut, HOriginalMode); + } + + gST->ConOut->SetAttribute ( + gST->ConOut, + EFI_TEXT_ATTR (HOriginalColors.Foreground, HOriginalColors.Background) + ); + gST->ConOut->ClearScreen (gST->ConOut); + + return EFI_SUCCESS; +} + +EFI_STATUS +HMainEditorRefresh ( + VOID + ) +/*++ + +Routine Description: + + Refresh function for MainEditor + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + // + // to aVOID screen flicker + // the stall value is from experience + // + gBS->Stall (50); + + // + // call the four components refresh function + // + MainTitleBarRefresh ( + HMainEditor.BufferImage->BufferType == FileTypeFileBuffer?HMainEditor.BufferImage->FileImage->FileName:HMainEditor.BufferImage->BufferType == FileTypeDiskBuffer?HMainEditor.BufferImage->DiskImage->Name:NULL, + HMainEditor.BufferImage->BufferType, + HMainEditor.BufferImage->FileImage->ReadOnly, + HMainEditor.BufferImage->Modified, + HMainEditor.ScreenSize.Column, + HMainEditor.ScreenSize.Row + ); + HBufferImageRefresh (); + StatusBarRefresh ( + HEditorFirst, + HMainEditor.ScreenSize.Row, + HMainEditor.ScreenSize.Column, + 0, + 0, + TRUE + ); + MenuBarRefresh ( + HMainEditor.ScreenSize.Row, + HMainEditor.ScreenSize.Column); + + // + // EditorFirst is now set to FALSE + // + HEditorFirst = FALSE; + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +HMainEditorHandleMouseInput ( + IN EFI_SIMPLE_POINTER_STATE MouseState, + OUT BOOLEAN *BeforeLeftButtonDown + ) +{ + + INT32 TextX; + INT32 TextY; + UINTN FRow; + UINTN FCol; + BOOLEAN HighBits; + LIST_ENTRY *Link; + HEFI_EDITOR_LINE *Line; + UINTN Index; + BOOLEAN Action; + + Action = FALSE; + + // + // have mouse movement + // + if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) { + // + // handle + // + TextX = HGetTextX (MouseState.RelativeMovementX); + TextY = HGetTextY (MouseState.RelativeMovementY); + + HBufferImageAdjustMousePosition (TextX, TextY); + + Action = TRUE; + + } + + if (MouseState.LeftButton) { + HighBits = HBufferImageIsAtHighBits ( + HMainEditor.BufferImage->MousePosition.Column, + &FCol + ); + + // + // not at an movable place + // + if (FCol == 0) { + // + // now just move mouse pointer to legal position + // + // + // move mouse position to legal position + // + HMainEditor.BufferImage->MousePosition.Column -= 10; + if (HMainEditor.BufferImage->MousePosition.Column > 24) { + HMainEditor.BufferImage->MousePosition.Column--; + FCol = HMainEditor.BufferImage->MousePosition.Column / 3 + 1 + 1; + } else { + if (HMainEditor.BufferImage->MousePosition.Column < 24) { + FCol = HMainEditor.BufferImage->MousePosition.Column / 3 + 1 + 1; + } else { + // + // == 24 + // + FCol = 9; + } + } + + HighBits = TRUE; + + } + + FRow = HMainEditor.BufferImage->BufferPosition.Row + + HMainEditor.BufferImage->MousePosition.Row - + HMainEditor.BufferImage->DisplayPosition.Row; + + if (HMainEditor.BufferImage->NumLines < FRow) { + // + // dragging + // + // + // now just move mouse pointer to legal position + // + FRow = HMainEditor.BufferImage->NumLines; + HighBits = TRUE; + } + + Link = HMainEditor.BufferImage->ListHead->ForwardLink; + for (Index = 0; Index < FRow - 1; Index++) { + Link = Link->ForwardLink; + } + + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + + // + // dragging + // + // + // now just move mouse pointer to legal position + // + if (FCol > Line->Size) { + if (*BeforeLeftButtonDown) { + HighBits = FALSE; + + if (Line->Size == 0) { + if (FRow > 1) { + FRow--; + FCol = 16; + } else { + FRow = 1; + FCol = 1; + } + + } else { + FCol = Line->Size; + } + } else { + FCol = Line->Size + 1; + HighBits = TRUE; + } + } + + HBufferImageMovePosition (FRow, FCol, HighBits); + + HMainEditor.BufferImage->MousePosition.Row = HMainEditor.BufferImage->DisplayPosition.Row; + + HMainEditor.BufferImage->MousePosition.Column = HMainEditor.BufferImage->DisplayPosition.Column; + + *BeforeLeftButtonDown = TRUE; + + Action = TRUE; + } else { + // + // else of if LButton + // + // release LButton + // + if (*BeforeLeftButtonDown == TRUE) { + Action = TRUE; + } + // + // mouse up + // + *BeforeLeftButtonDown = FALSE; + } + + if (Action) { + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +HMainEditorKeyInput ( + VOID + ) +/*++ + +Routine Description: + + Handle user key input. will route it to other components handle function + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + EFI_INPUT_KEY Key; + EFI_STATUS Status; + EFI_SIMPLE_POINTER_STATE MouseState; + BOOLEAN LengthChange; + UINTN Size; + UINTN OldSize; + BOOLEAN BeforeMouseIsDown; + BOOLEAN MouseIsDown; + BOOLEAN FirstDown; + BOOLEAN MouseDrag; + UINTN FRow; + UINTN FCol; + UINTN SelectStartBackup; + UINTN SelectEndBackup; + + // + // variable initialization + // + OldSize = 0; + FRow = 0; + FCol = 0; + LengthChange = FALSE; + + MouseIsDown = FALSE; + FirstDown = FALSE; + MouseDrag = FALSE; + + do { + + Status = EFI_SUCCESS; + + HEditorMouseAction = FALSE; + + // + // backup some key elements, so that can aVOID some refresh work + // + HMainEditorBackup (); + + // + // wait for user key input + // + // + // change priority of checking mouse/keyboard activity dynamically + // so prevent starvation of keyboard. + // if last time, mouse moves then this time check keyboard + // + if (HMainEditor.MouseSupported) { + Status = HMainEditor.MouseInterface->GetState ( + HMainEditor.MouseInterface, + &MouseState + ); + if (!EFI_ERROR (Status)) { + + BeforeMouseIsDown = MouseIsDown; + + Status = HMainEditorHandleMouseInput (MouseState, &MouseIsDown); + + if (!EFI_ERROR (Status)) { + if (BeforeMouseIsDown == FALSE) { + // + // mouse down + // + if (MouseIsDown == TRUE) { + FRow = HBufferImage.BufferPosition.Row; + FCol = HBufferImage.BufferPosition.Column; + SelectStartBackup = HMainEditor.SelectStart; + SelectEndBackup = HMainEditor.SelectEnd; + + FirstDown = TRUE; + } + } else { + + SelectStartBackup = HMainEditor.SelectStart; + SelectEndBackup = HMainEditor.SelectEnd; + + // + // begin to drag + // + if (MouseIsDown == TRUE) { + if (FirstDown == TRUE) { + if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) { + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + HMainEditor.SelectStart = (FRow - 1) * 0x10 + FCol; + + MouseDrag = TRUE; + FirstDown = FALSE; + } + } else { + if (( + (HBufferImage.BufferPosition.Row - 1) * + 0x10 + + HBufferImage.BufferPosition.Column + ) >= HMainEditor.SelectStart + ) { + HMainEditor.SelectEnd = (HBufferImage.BufferPosition.Row - 1) * + 0x10 + + HBufferImage.BufferPosition.Column; + } else { + HMainEditor.SelectEnd = 0; + } + } + // + // end of if RelativeX/Y + // + } else { + // + // mouse is up + // + if (MouseDrag) { + if (HBufferImageGetTotalSize () == 0) { + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + FirstDown = FALSE; + MouseDrag = FALSE; + } + + if (( + (HBufferImage.BufferPosition.Row - 1) * + 0x10 + + HBufferImage.BufferPosition.Column + ) >= HMainEditor.SelectStart + ) { + HMainEditor.SelectEnd = (HBufferImage.BufferPosition.Row - 1) * + 0x10 + + HBufferImage.BufferPosition.Column; + } else { + HMainEditor.SelectEnd = 0; + } + + if (HMainEditor.SelectEnd == 0) { + HMainEditor.SelectStart = 0; + } + } + + FirstDown = FALSE; + MouseDrag = FALSE; + } + + if (SelectStartBackup != HMainEditor.SelectStart || SelectEndBackup != HMainEditor.SelectEnd) { + if ((SelectStartBackup - 1) / 0x10 != (HMainEditor.SelectStart - 1) / 0x10) { + HBufferImageNeedRefresh = TRUE; + } else { + if ((SelectEndBackup - 1) / 0x10 != (HMainEditor.SelectEnd - 1) / 0x10) { + HBufferImageNeedRefresh = TRUE; + } else { + HBufferImageOnlyLineNeedRefresh = TRUE; + } + } + } + } + + HEditorMouseAction = TRUE; + HBufferImageMouseNeedRefresh = TRUE; + + } else if (Status == EFI_LOAD_ERROR) { + StatusBarSetStatusString (L"Invalid Mouse Movement "); + } + } + } + + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (!EFI_ERROR (Status)) { + // + // dispatch to different components' key handling function + // so not everywhere has to set this variable + // + HBufferImageMouseNeedRefresh = TRUE; + + // + // clear previous status string + // + StatusBarSetRefresh(); + + if (Key.ScanCode == SCAN_NULL) { + Status = HBufferImageHandleInput (&Key); + } else if (((Key.ScanCode >= SCAN_UP) && (Key.ScanCode <= SCAN_PAGE_DOWN))) { + Status = HBufferImageHandleInput (&Key); + } else if (((Key.ScanCode >= SCAN_F1) && Key.ScanCode <= (SCAN_F12))) { + Status = MenuBarDispatchFunctionKey (&Key); + } else { + StatusBarSetStatusString (L"Unknown Command"); + + HBufferImageMouseNeedRefresh = FALSE; + } + + if (Status != EFI_SUCCESS && Status != EFI_OUT_OF_RESOURCES) { + // + // not already has some error status + // + if (StrCmp (L"", StatusBarGetString()) == 0) { + StatusBarSetStatusString (L"Disk Error. Try Again"); + } + } + } + // + // decide if has to set length warning + // + if (HBufferImage.BufferType != HBufferImageBackupVar.BufferType) { + LengthChange = FALSE; + } else { + // + // still the old buffer + // + if (HBufferImage.BufferType != FileTypeFileBuffer) { + Size = HBufferImageGetTotalSize (); + + switch (HBufferImage.BufferType) { + case FileTypeDiskBuffer: + OldSize = HBufferImage.DiskImage->Size * HBufferImage.DiskImage->BlockSize; + break; + + case FileTypeMemBuffer: + OldSize = HBufferImage.MemImage->Size; + break; + } + + if (LengthChange == FALSE) { + if (OldSize != Size) { + StatusBarSetStatusString (L"Disk/Mem Buffer Length should not be changed"); + } + } + + if (OldSize != Size) { + LengthChange = TRUE; + } else { + LengthChange = FALSE; + } + } + } + // + // after handling, refresh editor + // + HMainEditorRefresh (); + + } while (Status != EFI_OUT_OF_RESOURCES && !HEditorExit); + + return Status; +} + +/** + Backup function for MainEditor. +**/ +VOID +EFIAPI +HMainEditorBackup ( + VOID + ) +{ + HMainEditorBackupVar.SelectStart = HMainEditor.SelectStart; + HMainEditorBackupVar.SelectEnd = HMainEditor.SelectEnd; + HBufferImageBackup (); +} diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.h new file mode 100644 index 0000000000..c4f2ea6382 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MainHexEditor.h @@ -0,0 +1,48 @@ +/** @file + Defines the Main Editor data type - + - Global variables + - Instances of the other objects of the editor + - Main Interfaces + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef _LIB_EDITOR_H_ +#define _LIB_EDITOR_H_ + +#include "HexEditor.h" + +EFI_STATUS +HMainEditorInit ( + VOID + ); +EFI_STATUS +HMainEditorCleanup ( + VOID + ); +EFI_STATUS +HMainEditorRefresh ( + VOID + ); +EFI_STATUS +HMainEditorKeyInput ( + VOID + ); + +/** + Backup function for MainEditor. +**/ +VOID +EFIAPI +HMainEditorBackup ( + VOID + ); +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.c new file mode 100644 index 0000000000..73464906b4 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.c @@ -0,0 +1,412 @@ +/** @file + Functions to deal with Mem buffer + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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_BUFFER_IMAGE HBufferImage; + +extern BOOLEAN HBufferImageNeedRefresh; +extern BOOLEAN HBufferImageOnlyLineNeedRefresh; +extern BOOLEAN HBufferImageMouseNeedRefresh; + +extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; + +HEFI_EDITOR_MEM_IMAGE HMemImage; +HEFI_EDITOR_MEM_IMAGE HMemImageBackupVar; + +EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL DummyPciRootBridgeIo; + +// +// for basic initialization of HDiskImage +// +HEFI_EDITOR_MEM_IMAGE HMemImageConst = { + NULL, + 0, + 0 +}; + +EFI_STATUS +DummyMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +DummyMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +HMemImageInit ( + VOID + ) +/*++ + +Routine Description: + + Initialization function for HDiskImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + +--*/ +{ + EFI_STATUS Status; + + // + // basically initialize the HMemImage + // + CopyMem (&HMemImage, &HMemImageConst, sizeof (HMemImage)); + + Status = gBS->LocateProtocol ( + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + (VOID**)&HMemImage.IoFncs + ); + if (Status == EFI_NOT_FOUND) { + // + // For NT32, no EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL is available + // Use Dummy PciRootBridgeIo for memory access + // + ZeroMem (&DummyPciRootBridgeIo, sizeof (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL)); + DummyPciRootBridgeIo.Mem.Read = DummyMemRead; + DummyPciRootBridgeIo.Mem.Write = DummyMemWrite; + HMemImage.IoFncs = &DummyPciRootBridgeIo; + Status = EFI_SUCCESS; + } + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } else { + return EFI_LOAD_ERROR; + } +} + +EFI_STATUS +HMemImageBackup ( + VOID + ) +/*++ + +Routine Description: + + Backup function for HDiskImage + Only a few fields need to be backup. + This is for making the Disk buffer refresh + as few as possible. + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + HMemImageBackupVar.Offset = HMemImage.Offset; + HMemImageBackupVar.Size = HMemImage.Size; + + return EFI_SUCCESS; +} + +EFI_STATUS +HMemImageCleanup ( + VOID + ) +/*++ + +Routine Description: + + Cleanup function for HDiskImage + +Arguments: + + None + +Returns: + + EFI_SUCCESS + +--*/ +{ + return EFI_SUCCESS; +} + +EFI_STATUS +HMemImageSetMemOffsetSize ( + IN UINTN Offset, + IN UINTN Size + ) +/*++ + +Routine Description: + + Set FileName field in HFileImage + +Arguments: + + Offset - The offset + Size - The size + +Returns: + + EFI_SUCCESS + EFI_OUT_OF_RESOURCES + +--*/ +{ + + HMemImage.Offset = Offset; + HMemImage.Size = Size; + + return EFI_SUCCESS; +} + +EFI_STATUS +HMemImageRead ( + IN UINTN Offset, + IN UINTN Size, + BOOLEAN Recover + ) +/*++ + +Routine Description: + + Read a disk from disk into HBufferImage + +Arguments: + + Offset - The offset + Size - The size + Recover - if is for recover, no information print + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + + EFI_STATUS Status; + void *Buffer; + CHAR16 *Str; + HEFI_EDITOR_LINE *Line; + + EDIT_FILE_TYPE BufferTypeBackup; + + BufferTypeBackup = HBufferImage.BufferType; + HBufferImage.BufferType = FileTypeMemBuffer; + + Buffer = AllocateZeroPool (Size); + if (Buffer == NULL) { + StatusBarSetStatusString (L"Read Memory Failed"); + return EFI_OUT_OF_RESOURCES; + } + + Status = HMemImage.IoFncs->Mem.Read ( + HMemImage.IoFncs, + EfiPciWidthUint8, + Offset, + Size, + Buffer + ); + + if (EFI_ERROR (Status)) { + FreePool (Buffer); + StatusBarSetStatusString (L"Memory Specified Not Accessible"); + return EFI_LOAD_ERROR; + } + + HBufferImageFree (); + + Status = HBufferImageBufferToList (Buffer, Size); + FreePool (Buffer); + + if (EFI_ERROR (Status)) { + StatusBarSetStatusString (L"Read Memory Failed"); + return Status; + } + + Status = HMemImageSetMemOffsetSize (Offset, Size); + + HBufferImage.DisplayPosition.Row = 2; + HBufferImage.DisplayPosition.Column = 10; + + HBufferImage.MousePosition.Row = 2; + HBufferImage.MousePosition.Column = 10; + + HBufferImage.LowVisibleRow = 1; + HBufferImage.HighBits = TRUE; + + HBufferImage.BufferPosition.Row = 1; + HBufferImage.BufferPosition.Column = 1; + + if (!Recover) { + Str = CatSPrint(NULL, L"%d Lines Read", HBufferImage.NumLines); + if (Str == NULL) { + StatusBarSetStatusString (L"Read Memory Failed"); + return EFI_OUT_OF_RESOURCES; + } + + StatusBarSetStatusString (Str); + SHELL_FREE_NON_NULL (Str); + + HMainEditor.SelectStart = 0; + HMainEditor.SelectEnd = 0; + + } + + // + // has line + // + if (HBufferImage.Lines != NULL) { + HBufferImage.CurrentLine = CR (HBufferImage.ListHead->ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + } else { + // + // create a dummy line + // + Line = HBufferImageCreateLine (); + if (Line == NULL) { + StatusBarSetStatusString (L"Read Memory Failed"); + return EFI_OUT_OF_RESOURCES; + } + + HBufferImage.CurrentLine = Line; + } + + HBufferImage.Modified = FALSE; + HBufferImageNeedRefresh = TRUE; + HBufferImageOnlyLineNeedRefresh = FALSE; + HBufferImageMouseNeedRefresh = TRUE; + + return EFI_SUCCESS; + +} + +EFI_STATUS +HMemImageSave ( + IN UINTN Offset, + IN UINTN Size + ) +/*++ + +Routine Description: + + Save lines in HBufferImage to disk + +Arguments: + + Offset - The offset + Size - The size + +Returns: + + EFI_SUCCESS + EFI_LOAD_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + + EFI_STATUS Status; + VOID *Buffer; + + EDIT_FILE_TYPE BufferTypeBackup; + + // + // not modified, so directly return + // + if (HBufferImage.Modified == FALSE) { + return EFI_SUCCESS; + } + + BufferTypeBackup = HBufferImage.BufferType; + HBufferImage.BufferType = FileTypeMemBuffer; + + Buffer = AllocateZeroPool (Size); + + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = HBufferImageListToBuffer (Buffer, Size); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + // + // write back to memory + // + Status = HMemImage.IoFncs->Mem.Write ( + HMemImage.IoFncs, + EfiPciWidthUint8, + Offset, + Size, + Buffer + ); + + FreePool (Buffer); + + if (EFI_ERROR (Status)) { + return EFI_LOAD_ERROR; + } + // + // now not modified + // + HBufferImage.Modified = FALSE; + + return EFI_SUCCESS; +} + +EFI_STATUS +DummyMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +DummyMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.h new file mode 100644 index 0000000000..8805c0d75d --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/MemImage.h @@ -0,0 +1,52 @@ +/** @file + Defines MemImage - 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.
+ 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. + +**/ + +#ifndef _LIB_MEM_IMAGE_H_ +#define _LIB_MEM_IMAGE_H_ + +#include "HexEditor.h" + +EFI_STATUS +HMemImageInit ( + VOID + ); +EFI_STATUS +HMemImageCleanup ( + VOID + ); +EFI_STATUS +HMemImageBackup ( + VOID + ); + +EFI_STATUS +HMemImageSetMemOffsetSize ( + IN UINTN, + IN UINTN + ); + +EFI_STATUS +HMemImageRead ( + IN UINTN, + IN UINTN, + IN BOOLEAN + ); +EFI_STATUS +HMemImageSave ( + IN UINTN, + IN UINTN + ); + +#endif diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.c new file mode 100644 index 0000000000..8ae21450c4 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.c @@ -0,0 +1,541 @@ +/** @file + Implementation of various string and line routines + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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 BOOLEAN HEditorMouseAction; + +VOID +HEditorClearLine ( + IN UINTN Row + ) +/*++ + +Routine Description: + + Clear line at Row + +Arguments: + + Row -- row number to be cleared ( start from 1 ) + +Returns: + + EFI_SUCCESS + +--*/ +{ + CHAR16 Line[200]; + UINTN Index; + UINTN Limit; + UINTN StartCol; + + if (HEditorMouseAction) { + Limit = 3 * 0x10; + StartCol = 10; + } else { + Limit = HMainEditor.ScreenSize.Column; + StartCol = 1; + } + // + // prepare a blank line + // + for (Index = 0; Index < Limit; Index++) { + Line[Index] = ' '; + } + + if (Row == HMainEditor.ScreenSize.Row && Limit == HMainEditor.ScreenSize.Column) { + // + // if '\0' is still at position 80, it will cause first line error + // + Line[Limit - 1] = '\0'; + } else { + Line[Limit] = '\0'; + } + // + // print out the blank line + // + ShellPrintEx ((INT32)StartCol - 1, (INT32)Row - 1, Line); +} + +HEFI_EDITOR_LINE * +HLineDup ( + IN HEFI_EDITOR_LINE *Src + ) +/*++ + +Routine Description: + + Duplicate a line + +Arguments: + + Src -- line to be duplicated + +Returns: + + NULL -- wrong + Not NULL -- line created + +--*/ +{ + HEFI_EDITOR_LINE *Dest; + + // + // allocate for the line structure + // + Dest = AllocateZeroPool (sizeof (HEFI_EDITOR_LINE)); + if (Dest == NULL) { + return NULL; + } + + Dest->Signature = EFI_EDITOR_LINE_LIST; + Dest->Size = Src->Size; + + CopyMem (Dest->Buffer, Src->Buffer, 0x10); + + Dest->Link = Src->Link; + + return Dest; +} + +VOID +HLineFree ( + IN HEFI_EDITOR_LINE *Src + ) +/*++ + +Routine Description: + + Free a line and it's internal buffer + +Arguments: + + Src -- line to be freed + +Returns: + + None + +--*/ +{ + if (Src == NULL) { + return ; + } + + SHELL_FREE_NON_NULL (Src); + +} + +HEFI_EDITOR_LINE * +_HLineAdvance ( + IN UINTN Count + ) +/*++ + +Routine Description: + + Advance to the next Count lines + +Arguments: + + Count -- line number to advance + +Returns: + + NULL -- wrong + Not NULL -- line after advance + +--*/ +{ + UINTN Index; + HEFI_EDITOR_LINE *Line; + + Line = HMainEditor.BufferImage->CurrentLine; + if (Line == NULL) { + return NULL; + } + + for (Index = 0; Index < Count; Index++) { + // + // if already last line + // + if (Line->Link.ForwardLink == HMainEditor.BufferImage->ListHead) { + return NULL; + } + + Line = CR (Line->Link.ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + } + + return Line; +} + +HEFI_EDITOR_LINE * +_HLineRetreat ( + IN UINTN Count + ) +/*++ + +Routine Description: + + Retreat to the previous Count lines + +Arguments: + + Count -- line number to retreat + +Returns: + + NULL -- wrong + Not NULL -- line after retreat + +--*/ +{ + UINTN Index; + HEFI_EDITOR_LINE *Line; + + Line = HMainEditor.BufferImage->CurrentLine; + if (Line == NULL) { + return NULL; + } + + for (Index = 0; Index < Count; Index++) { + // + // already the first line + // + if (Line->Link.BackLink == HMainEditor.BufferImage->ListHead) { + return NULL; + } + + Line = CR (Line->Link.BackLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + } + + return Line; +} + +HEFI_EDITOR_LINE * +HMoveLine ( + IN INTN Count + ) +/*++ + +Routine Description: + + Advance/Retreat lines + +Arguments: + + Count -- line number to advance/retreat + >0 : advance + <0: retreat + +Returns: + + NULL -- wrong + Not NULL -- line after advance + +--*/ +{ + HEFI_EDITOR_LINE *Line; + UINTN AbsCount; + + // + // difference with MoveCurrentLine + // just return Line + // do not set currentline to Line + // + if (Count <= 0) { + AbsCount = -Count; + Line = _HLineRetreat (AbsCount); + } else { + Line = _HLineAdvance (Count); + } + + return Line; +} + +HEFI_EDITOR_LINE * +HMoveCurrentLine ( + IN INTN Count + ) +/*++ + +Routine Description: + + Advance/Retreat lines and set CurrentLine in BufferImage to it + +Arguments: + + Count -- line number to advance/retreat + >0 : advance + <0: retreat + +Returns: + + NULL -- wrong + Not NULL -- line after advance + + +--*/ +{ + HEFI_EDITOR_LINE *Line; + UINTN AbsCount; + + // + // <0: retreat + // >0: advance + // + if (Count <= 0) { + AbsCount = -Count; + Line = _HLineRetreat (AbsCount); + } else { + Line = _HLineAdvance (Count); + } + + if (Line == NULL) { + return NULL; + } + + HMainEditor.BufferImage->CurrentLine = Line; + + return Line; +} + + +EFI_STATUS +HFreeLines ( + IN LIST_ENTRY *ListHead, + IN HEFI_EDITOR_LINE *Lines + ) +/*++ + +Routine Description: + + Free all the lines in HBufferImage + Fields affected: + Lines + CurrentLine + NumLines + ListHead + +Arguments: + + ListHead - The list head + Lines - The lines + +Returns: + + EFI_SUCCESS + +--*/ +{ + LIST_ENTRY *Link; + HEFI_EDITOR_LINE *Line; + + // + // release all the lines + // + if (Lines != NULL) { + + Line = Lines; + Link = &(Line->Link); + do { + Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); + Link = Link->ForwardLink; + HLineFree (Line); + } while (Link != ListHead); + } + + ListHead->ForwardLink = ListHead; + ListHead->BackLink = ListHead; + + return EFI_SUCCESS; +} + +UINTN +HStrStr ( + IN CHAR16 *Str, + IN CHAR16 *Pat + ) +/*++ + +Routine Description: + + Search Pat in Str + +Arguments: + + Str -- mother string + Pat -- search pattern + + +Returns: + + 0 : not found + >= 1 : found position + 1 + +--*/ +{ + INTN *Failure; + INTN i; + INTN j; + INTN Lenp; + INTN Lens; + + // + // this function copies from some lib + // + Lenp = StrLen (Pat); + Lens = StrLen (Str); + + Failure = AllocateZeroPool (Lenp * sizeof (INTN)); + Failure[0] = -1; + for (j = 1; j < Lenp; j++) { + i = Failure[j - 1]; + while ((Pat[j] != Pat[i + 1]) && (i >= 0)) { + i = Failure[i]; + } + + if (Pat[j] == Pat[i + 1]) { + Failure[j] = i + 1; + } else { + Failure[j] = -1; + } + } + + i = 0; + j = 0; + while (i < Lens && j < Lenp) { + if (Str[i] == Pat[j]) { + i++; + j++; + } else if (j == 0) { + i++; + } else { + j = Failure[j - 1] + 1; + } + } + + FreePool (Failure); + + // + // 0: not found + // >=1 : found position + 1 + // + return ((j == Lenp) ? (i - Lenp) : -1) + 1; + +} + +INT32 +HGetTextX ( + IN INT32 GuidX + ) +{ + INT32 Gap; + + HMainEditor.MouseAccumulatorX += GuidX; + Gap = (HMainEditor.MouseAccumulatorX * (INT32) HMainEditor.ScreenSize.Column) / (INT32) (50 * (INT32) HMainEditor.MouseInterface->Mode->ResolutionX); + HMainEditor.MouseAccumulatorX = (HMainEditor.MouseAccumulatorX * (INT32) HMainEditor.ScreenSize.Column) % (INT32) (50 * (INT32) HMainEditor.MouseInterface->Mode->ResolutionX); + HMainEditor.MouseAccumulatorX = HMainEditor.MouseAccumulatorX / (INT32) HMainEditor.ScreenSize.Column; + return Gap; +} + +INT32 +HGetTextY ( + IN INT32 GuidY + ) +{ + INT32 Gap; + + HMainEditor.MouseAccumulatorY += GuidY; + Gap = (HMainEditor.MouseAccumulatorY * (INT32) HMainEditor.ScreenSize.Row) / (INT32) (50 * (INT32) HMainEditor.MouseInterface->Mode->ResolutionY); + HMainEditor.MouseAccumulatorY = (HMainEditor.MouseAccumulatorY * (INT32) HMainEditor.ScreenSize.Row) % (INT32) (50 * (INT32) HMainEditor.MouseInterface->Mode->ResolutionY); + HMainEditor.MouseAccumulatorY = HMainEditor.MouseAccumulatorY / (INT32) HMainEditor.ScreenSize.Row; + + return Gap; +} + +EFI_STATUS +HXtoi ( + IN CHAR16 *Str, + OUT UINTN *Value + ) +/*++ +Routine Description: + + convert hex string to uint + +Arguments: + + Str - The string + Value - The value + +Returns: + + +--*/ +{ + UINT64 u; + CHAR16 c; + UINTN Size; + + Size = sizeof (UINTN); + + // + // skip leading white space + // + while (*Str && *Str == ' ') { + Str += 1; + } + + if (StrLen (Str) > Size * 2) { + return EFI_LOAD_ERROR; + } + // + // convert hex digits + // + u = 0; + c = *Str; + while (c) { + c = *Str; + Str++; + + if (c == 0) { + break; + } + // + // not valid char + // + if (!((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9') || (c == '\0'))) { + return EFI_LOAD_ERROR; + } + + if (c >= 'a' && c <= 'f') { + c -= 'a' - 'A'; + } + + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { + u = LShiftU64 (u, 4) + (c - (c >= 'A' ? 'A' - 10 : '0')); + } else { + // + // '\0' + // + break; + } + } + + *Value = (UINTN) u; + + return EFI_SUCCESS; +} diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.h b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.h new file mode 100644 index 0000000000..a9b59ff514 --- /dev/null +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/HexEdit/Misc.h @@ -0,0 +1,96 @@ +/** @file + Definitions for various line and string routines + + Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+ 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. + +**/ + +#ifndef _LIB_MISC_H_ +#define _LIB_MISC_H_ + +#include "HexEditor.h" + +VOID +HEditorClearLine ( + UINTN + ); +HEFI_EDITOR_LINE * +HLineDup ( + HEFI_EDITOR_LINE * + ); +VOID +HLineFree ( + HEFI_EDITOR_LINE * + ); + +HEFI_EDITOR_LINE * +HMoveLine ( + INTN + ); +HEFI_EDITOR_LINE * +HMoveCurrentLine ( + INTN + ); + +UINTN +HLineStrInsert ( + HEFI_EDITOR_LINE *, + CHAR16, + UINTN, + UINTN + ); + +VOID +HLineCat ( + HEFI_EDITOR_LINE *, + HEFI_EDITOR_LINE * + ); + +VOID +HLineDeleteAt ( + HEFI_EDITOR_LINE *, + UINTN + ); + +UINTN +HUnicodeToAscii ( + CHAR16 *, + UINTN, + CHAR8 * + ); + +UINTN +HStrStr ( + CHAR16 *, + CHAR16 * + ); + +EFI_STATUS +HFreeLines ( + LIST_ENTRY *, + HEFI_EDITOR_LINE * + ); + +INT32 +HGetTextX ( + INT32 + ) ; +INT32 +HGetTextY ( + INT32 + ) ; + +EFI_STATUS +HXtoi ( + CHAR16 *, + UINTN * + ); + +#endif