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