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
HFileImageInit(VOID)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
HFileImageBackup(VOID)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
HFileImageCleanup(VOID)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
HFileImageSetFileName(IN CONST CHAR16 * Str)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
HFileImageRead(IN CONST CHAR16 * FileName,IN BOOLEAN Recover)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
HFileImageSave(IN CHAR16 * FileName)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