/** @file | |
Functions to deal with file buffer. | |
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved. <BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#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 | |
}; | |
/** | |
Initialization function for HFileImage | |
@retval EFI_SUCCESS The operation was successful. | |
**/ | |
EFI_STATUS | |
HFileImageInit ( | |
VOID | |
) | |
{ | |
// | |
// basically initialize the HFileImage | |
// | |
CopyMem (&HFileImage, &HFileImageConst, sizeof (HFileImage)); | |
CopyMem ( | |
&HFileImageBackupVar, | |
&HFileImageConst, | |
sizeof (HFileImageBackupVar) | |
); | |
return EFI_SUCCESS; | |
} | |
/** | |
Backup function for HFileImage. Only a few fields need to be backup. | |
This is for making the file buffer refresh as few as possible. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
**/ | |
EFI_STATUS | |
HFileImageBackup ( | |
VOID | |
) | |
{ | |
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; | |
} | |
/** | |
Cleanup function for HFileImage. | |
@retval EFI_SUCCESS The operation was successful. | |
**/ | |
EFI_STATUS | |
HFileImageCleanup ( | |
VOID | |
) | |
{ | |
SHELL_FREE_NON_NULL (HFileImage.FileName); | |
SHELL_FREE_NON_NULL (HFileImageBackupVar.FileName); | |
return EFI_SUCCESS; | |
} | |
/** | |
Set FileName field in HFileImage | |
@param[in] Str File name to set. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
**/ | |
EFI_STATUS | |
HFileImageSetFileName ( | |
IN CONST CHAR16 *Str | |
) | |
{ | |
if (Str == HFileImage.FileName) { | |
// | |
// This function might be called using HFileImage.FileName as Str. | |
// Directly return without updating HFileImage.FileName. | |
// | |
return EFI_SUCCESS; | |
} | |
// | |
// free the old file name | |
// | |
SHELL_FREE_NON_NULL (HFileImage.FileName); | |
HFileImage.FileName = AllocateCopyPool (StrSize (Str), Str); | |
if (HFileImage.FileName == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Read a file from disk into HBufferImage. | |
@param[in] FileName filename to read. | |
@param[in] Recover if is for recover, no information print. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
HFileImageRead ( | |
IN CONST CHAR16 *FileName, | |
IN BOOLEAN Recover | |
) | |
{ | |
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); | |
// | |
// NULL pointer is only also a failure for a non-zero file size. | |
// | |
if ((EFI_ERROR (Status)) || ((Buffer == NULL) && (HFileImage.Size != 0))) { | |
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); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
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; | |
HBufferImage.BufferType = FileTypeFileBuffer; | |
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; | |
} | |
/** | |
Save lines in HBufferImage to disk. | |
@param[in] FileName The file name. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
HFileImageSave ( | |
IN CHAR16 *FileName | |
) | |
{ | |
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 ((HFileImage.FileName != NULL) && (FileName != NULL) && (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 Written", NumLines); | |
StatusBarSetStatusString (Str); | |
FreePool (Str); | |
// | |
// now everything is ready , you can set the new file name to filebuffer | |
// | |
if (((BufferTypeBackup != FileTypeFileBuffer) && (FileName != NULL)) || | |
((FileName != NULL) && (HFileImage.FileName != NULL) && (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; | |
} |