1 /** @file 2 Functions to deal with file buffer. 3 4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved. <BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "HexEditor.h" 16 17 extern EFI_HANDLE HImageHandleBackup; 18 extern HEFI_EDITOR_BUFFER_IMAGE HBufferImage; 19 20 extern BOOLEAN HBufferImageNeedRefresh; 21 extern BOOLEAN HBufferImageOnlyLineNeedRefresh; 22 extern BOOLEAN HBufferImageMouseNeedRefresh; 23 24 extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; 25 26 HEFI_EDITOR_FILE_IMAGE HFileImage; 27 HEFI_EDITOR_FILE_IMAGE HFileImageBackupVar; 28 29 // 30 // for basic initialization of HFileImage 31 // 32 HEFI_EDITOR_BUFFER_IMAGE HFileImageConst = { 33 NULL, 34 0, 35 FALSE 36 }; 37 38 /** 39 Initialization function for HFileImage 40 41 @retval EFI_SUCCESS The operation was successful. 42 **/ 43 EFI_STATUS 44 HFileImageInit ( 45 VOID 46 ) 47 { 48 // 49 // basically initialize the HFileImage 50 // 51 CopyMem (&HFileImage, &HFileImageConst, sizeof (HFileImage)); 52 53 CopyMem ( 54 &HFileImageBackupVar, 55 &HFileImageConst, 56 sizeof (HFileImageBackupVar) 57 ); 58 59 return EFI_SUCCESS; 60 } 61 62 /** 63 Backup function for HFileImage. Only a few fields need to be backup. 64 This is for making the file buffer refresh as few as possible. 65 66 @retval EFI_SUCCESS The operation was successful. 67 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 68 **/ 69 EFI_STATUS 70 HFileImageBackup ( 71 VOID 72 ) 73 { 74 SHELL_FREE_NON_NULL (HFileImageBackupVar.FileName); 75 HFileImageBackupVar.FileName = CatSPrint(NULL, L"%s", HFileImage.FileName); 76 if (HFileImageBackupVar.FileName == NULL) { 77 return EFI_OUT_OF_RESOURCES; 78 } 79 80 return EFI_SUCCESS; 81 } 82 83 /** 84 Cleanup function for HFileImage. 85 86 @retval EFI_SUCCESS The operation was successful. 87 **/ 88 EFI_STATUS 89 HFileImageCleanup ( 90 VOID 91 ) 92 { 93 94 SHELL_FREE_NON_NULL (HFileImage.FileName); 95 SHELL_FREE_NON_NULL (HFileImageBackupVar.FileName); 96 97 return EFI_SUCCESS; 98 } 99 100 /** 101 Set FileName field in HFileImage 102 103 @param[in] Str File name to set. 104 105 @retval EFI_SUCCESS The operation was successful. 106 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 107 **/ 108 EFI_STATUS 109 HFileImageSetFileName ( 110 IN CONST CHAR16 *Str 111 ) 112 { 113 UINTN Size; 114 UINTN Index; 115 116 // 117 // free the old file name 118 // 119 SHELL_FREE_NON_NULL (HFileImage.FileName); 120 121 Size = StrLen (Str); 122 123 HFileImage.FileName = AllocateZeroPool (2 * (Size + 1)); 124 if (HFileImage.FileName == NULL) { 125 return EFI_OUT_OF_RESOURCES; 126 } 127 128 for (Index = 0; Index < Size; Index++) { 129 HFileImage.FileName[Index] = Str[Index]; 130 } 131 132 HFileImage.FileName[Size] = L'\0'; 133 134 return EFI_SUCCESS; 135 } 136 137 /** 138 Read a file from disk into HBufferImage. 139 140 @param[in] FileName filename to read. 141 @param[in] Recover if is for recover, no information print. 142 143 @retval EFI_SUCCESS The operation was successful. 144 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 145 @retval EFI_LOAD_ERROR A load error occured. 146 **/ 147 EFI_STATUS 148 HFileImageRead ( 149 IN CONST CHAR16 *FileName, 150 IN BOOLEAN Recover 151 ) 152 { 153 HEFI_EDITOR_LINE *Line; 154 UINT8 *Buffer; 155 CHAR16 *UnicodeBuffer; 156 EFI_STATUS Status; 157 158 // 159 // variable initialization 160 // 161 Line = NULL; 162 163 // 164 // in this function, when you return error ( except EFI_OUT_OF_RESOURCES ) 165 // you should set status string 166 // since this function maybe called before the editorhandleinput loop 167 // so any error will cause editor return 168 // so if you want to print the error status 169 // you should set the status string 170 // 171 Status = ReadFileIntoBuffer (FileName, (VOID**)&Buffer, &HFileImage.Size, &HFileImage.ReadOnly); 172 // 173 // NULL pointer is only also a failure for a non-zero file size. 174 // 175 if ((EFI_ERROR(Status)) || (Buffer == NULL && HFileImage.Size != 0)) { 176 UnicodeBuffer = CatSPrint(NULL, L"Read error on file %s: %r", FileName, Status); 177 if (UnicodeBuffer == NULL) { 178 SHELL_FREE_NON_NULL(Buffer); 179 return EFI_OUT_OF_RESOURCES; 180 } 181 182 StatusBarSetStatusString (UnicodeBuffer); 183 FreePool (UnicodeBuffer); 184 return EFI_OUT_OF_RESOURCES; 185 } 186 187 HFileImageSetFileName (FileName); 188 189 // 190 // free the old lines 191 // 192 HBufferImageFree (); 193 194 Status = HBufferImageBufferToList (Buffer, HFileImage.Size); 195 SHELL_FREE_NON_NULL (Buffer); 196 if (EFI_ERROR (Status)) { 197 StatusBarSetStatusString (L"Error parsing file."); 198 return Status; 199 } 200 201 HBufferImage.DisplayPosition.Row = 2; 202 HBufferImage.DisplayPosition.Column = 10; 203 HBufferImage.MousePosition.Row = 2; 204 HBufferImage.MousePosition.Column = 10; 205 HBufferImage.LowVisibleRow = 1; 206 HBufferImage.HighBits = TRUE; 207 HBufferImage.BufferPosition.Row = 1; 208 HBufferImage.BufferPosition.Column = 1; 209 HBufferImage.BufferType = FileTypeFileBuffer; 210 211 if (!Recover) { 212 UnicodeBuffer = CatSPrint(NULL, L"%d Lines Read", HBufferImage.NumLines); 213 if (UnicodeBuffer == NULL) { 214 SHELL_FREE_NON_NULL(Buffer); 215 return EFI_OUT_OF_RESOURCES; 216 } 217 218 StatusBarSetStatusString (UnicodeBuffer); 219 FreePool (UnicodeBuffer); 220 221 HMainEditor.SelectStart = 0; 222 HMainEditor.SelectEnd = 0; 223 } 224 225 // 226 // has line 227 // 228 if (HBufferImage.Lines != 0) { 229 HBufferImage.CurrentLine = CR (HBufferImage.ListHead->ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); 230 } else { 231 // 232 // create a dummy line 233 // 234 Line = HBufferImageCreateLine (); 235 if (Line == NULL) { 236 SHELL_FREE_NON_NULL(Buffer); 237 return EFI_OUT_OF_RESOURCES; 238 } 239 240 HBufferImage.CurrentLine = Line; 241 } 242 243 HBufferImage.Modified = FALSE; 244 HBufferImageNeedRefresh = TRUE; 245 HBufferImageOnlyLineNeedRefresh = FALSE; 246 HBufferImageMouseNeedRefresh = TRUE; 247 248 return EFI_SUCCESS; 249 } 250 251 /** 252 Save lines in HBufferImage to disk. 253 254 @param[in] FileName The file name. 255 256 @retval EFI_SUCCESS The operation was successful. 257 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 258 @retval EFI_LOAD_ERROR A load error occured. 259 **/ 260 EFI_STATUS 261 HFileImageSave ( 262 IN CHAR16 *FileName 263 ) 264 { 265 266 LIST_ENTRY *Link; 267 HEFI_EDITOR_LINE *Line; 268 CHAR16 *Str; 269 EFI_STATUS Status; 270 UINTN NumLines; 271 SHELL_FILE_HANDLE FileHandle; 272 UINTN TotalSize; 273 UINT8 *Buffer; 274 UINT8 *Ptr; 275 EDIT_FILE_TYPE BufferTypeBackup; 276 277 BufferTypeBackup = HBufferImage.BufferType; 278 HBufferImage.BufferType = FileTypeFileBuffer; 279 280 // 281 // if is the old file 282 // 283 if (HFileImage.FileName != NULL && FileName != NULL && StrCmp (FileName, HFileImage.FileName) == 0) { 284 // 285 // check whether file exists on disk 286 // 287 if (ShellIsFile(FileName) == EFI_SUCCESS) { 288 // 289 // current file exists on disk 290 // so if not modified, then not save 291 // 292 if (HBufferImage.Modified == FALSE) { 293 return EFI_SUCCESS; 294 } 295 // 296 // if file is read-only, set error 297 // 298 if (HFileImage.ReadOnly == TRUE) { 299 StatusBarSetStatusString (L"Read Only File Can Not Be Saved"); 300 return EFI_SUCCESS; 301 } 302 } 303 } 304 305 if (ShellIsDirectory(FileName) == EFI_SUCCESS) { 306 StatusBarSetStatusString (L"Directory Can Not Be Saved"); 307 return EFI_LOAD_ERROR; 308 } 309 310 Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); 311 312 if (!EFI_ERROR (Status)) { 313 // 314 // the file exits, delete it 315 // 316 Status = ShellDeleteFile (&FileHandle); 317 if (EFI_ERROR (Status) || Status == EFI_WARN_DELETE_FAILURE) { 318 StatusBarSetStatusString (L"Write File Failed"); 319 return EFI_LOAD_ERROR; 320 } 321 } 322 323 // 324 // write all the lines back to disk 325 // 326 NumLines = 0; 327 TotalSize = 0; 328 for (Link = HBufferImage.ListHead->ForwardLink; Link != HBufferImage.ListHead; Link = Link->ForwardLink) { 329 Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); 330 331 if (Line->Size != 0) { 332 TotalSize += Line->Size; 333 } 334 // 335 // end of if Line -> Size != 0 336 // 337 NumLines++; 338 } 339 // 340 // end of for Link 341 // 342 Buffer = AllocateZeroPool (TotalSize); 343 if (Buffer == NULL) { 344 return EFI_OUT_OF_RESOURCES; 345 } 346 347 Ptr = Buffer; 348 for (Link = HBufferImage.ListHead->ForwardLink; Link != HBufferImage.ListHead; Link = Link->ForwardLink) { 349 Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); 350 351 if (Line->Size != 0) { 352 CopyMem (Ptr, Line->Buffer, Line->Size); 353 Ptr += Line->Size; 354 } 355 // 356 // end of if Line -> Size != 0 357 // 358 } 359 360 361 Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); 362 363 if (EFI_ERROR (Status)) { 364 StatusBarSetStatusString (L"Create File Failed"); 365 return EFI_LOAD_ERROR; 366 } 367 368 Status = ShellWriteFile (FileHandle, &TotalSize, Buffer); 369 FreePool (Buffer); 370 if (EFI_ERROR (Status)) { 371 ShellDeleteFile (&FileHandle); 372 return EFI_LOAD_ERROR; 373 } 374 375 ShellCloseFile(&FileHandle); 376 377 HBufferImage.Modified = FALSE; 378 379 // 380 // set status string 381 // 382 Str = CatSPrint(NULL, L"%d Lines Wrote", NumLines); 383 StatusBarSetStatusString (Str); 384 FreePool (Str); 385 386 // 387 // now everything is ready , you can set the new file name to filebuffer 388 // 389 if ((BufferTypeBackup != FileTypeFileBuffer && FileName != NULL) || 390 (FileName != NULL && HFileImage.FileName != NULL && StringNoCaseCompare (&FileName, &HFileImage.FileName) != 0)){ 391 // 392 // not the same 393 // 394 HFileImageSetFileName (FileName); 395 if (HFileImage.FileName == NULL) { 396 return EFI_OUT_OF_RESOURCES; 397 } 398 } 399 400 HFileImage.ReadOnly = FALSE; 401 402 return EFI_SUCCESS; 403 } 404