| /** @file | |
| Functions to deal with file buffer. | |
| Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved. <BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "HexEditor.h" | |
| extern EFI_HANDLE HImageHandleBackup; | |
| extern HEFI_EDITOR_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 | |
| ) | |
| { | |
| 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; | |
| } | |
| /** | |
| 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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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 Wrote", 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; | |
| } |