ShellPkg: Standardized HP Copyright Message String
[mirror_edk2.git] / ShellPkg / Application / Shell / FileHandleWrappers.c
1 /** @file\r
2   EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables,\r
3   StdIn, StdOut, StdErr, etc...).\r
4 \r
5   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
6   (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>\r
7   This program and the accompanying materials\r
8   are licensed and made available under the terms and conditions of the BSD License\r
9   which accompanies this distribution.  The full text of the license may be found at\r
10   http://opensource.org/licenses/bsd-license.php\r
11 \r
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14 \r
15 **/\r
16 \r
17 #include "Shell.h"\r
18 #include "FileHandleInternal.h"\r
19 \r
20 /**\r
21   File style interface for console (Open).  \r
22   \r
23   @param[in] This       Ignored.\r
24   @param[out] NewHandle Ignored.\r
25   @param[in] FileName   Ignored.\r
26   @param[in] OpenMode   Ignored.\r
27   @param[in] Attributes Ignored.\r
28   \r
29   @retval EFI_NOT_FOUND\r
30 **/\r
31 EFI_STATUS\r
32 EFIAPI\r
33 FileInterfaceOpenNotFound(\r
34   IN EFI_FILE_PROTOCOL *This,\r
35   OUT EFI_FILE_PROTOCOL **NewHandle,\r
36   IN CHAR16 *FileName,\r
37   IN UINT64 OpenMode,\r
38   IN UINT64 Attributes\r
39   )\r
40 {\r
41   return (EFI_NOT_FOUND);\r
42 }\r
43 \r
44 /**\r
45   File style interface for console (Close, Delete, & Flush)\r
46   \r
47   @param[in] This       Ignored.\r
48   \r
49   @retval EFI_SUCCESS\r
50 **/\r
51 EFI_STATUS\r
52 EFIAPI\r
53 FileInterfaceNopGeneric(\r
54   IN EFI_FILE_PROTOCOL *This\r
55   )\r
56 {\r
57   return (EFI_SUCCESS);\r
58 }\r
59 \r
60 /**\r
61   File style interface for console (GetPosition).\r
62 \r
63   @param[in] This       Ignored.\r
64   @param[out] Position  Ignored.\r
65   \r
66   @retval EFI_UNSUPPORTED\r
67 **/\r
68 EFI_STATUS\r
69 EFIAPI\r
70 FileInterfaceNopGetPosition(\r
71   IN EFI_FILE_PROTOCOL *This,\r
72   OUT UINT64 *Position\r
73   )\r
74 {\r
75   return (EFI_UNSUPPORTED);\r
76 }\r
77 \r
78 /**\r
79   File style interface for console (SetPosition).\r
80   \r
81   @param[in] This       Ignored.\r
82   @param[in] Position   Ignored.\r
83   \r
84   @retval EFI_UNSUPPORTED\r
85 **/\r
86 EFI_STATUS\r
87 EFIAPI\r
88 FileInterfaceNopSetPosition(\r
89   IN EFI_FILE_PROTOCOL *This,\r
90   IN UINT64 Position\r
91   )\r
92 {\r
93   return (EFI_UNSUPPORTED);\r
94 }\r
95 \r
96 /**\r
97   File style interface for console (GetInfo).\r
98   \r
99   @param[in] This              Ignored.\r
100   @param[in] InformationType   Ignored.\r
101   @param[in, out] BufferSize   Ignored.\r
102   @param[out] Buffer           Ignored.\r
103   \r
104   @retval EFI_UNSUPPORTED\r
105 **/\r
106 EFI_STATUS\r
107 EFIAPI\r
108 FileInterfaceNopGetInfo(\r
109   IN EFI_FILE_PROTOCOL *This,\r
110   IN EFI_GUID *InformationType,\r
111   IN OUT UINTN *BufferSize,\r
112   OUT VOID *Buffer\r
113   )\r
114 {\r
115   return (EFI_UNSUPPORTED);\r
116 }\r
117 \r
118 /**\r
119   File style interface for console (SetInfo).\r
120   \r
121   @param[in] This       Ignored.\r
122   @param[in] InformationType   Ignored.\r
123   @param[in] BufferSize Ignored.\r
124   @param[in] Buffer     Ignored.\r
125   \r
126   @retval EFI_UNSUPPORTED\r
127 **/\r
128 EFI_STATUS\r
129 EFIAPI\r
130 FileInterfaceNopSetInfo(\r
131   IN EFI_FILE_PROTOCOL *This,\r
132   IN EFI_GUID *InformationType,\r
133   IN UINTN BufferSize,\r
134   IN VOID *Buffer\r
135   )\r
136 {\r
137   return (EFI_UNSUPPORTED);\r
138 }\r
139 \r
140 /**\r
141   File style interface for StdOut (Write).\r
142 \r
143   Writes data to the screen.\r
144   \r
145   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
146   @param[in, out] BufferSize   Size in bytes of Buffer.\r
147   @param[in] Buffer            The pointer to the buffer to write.\r
148   \r
149   @retval EFI_UNSUPPORTED No output console is supported.\r
150   @return A return value from gST->ConOut->OutputString.\r
151 **/\r
152 EFI_STATUS\r
153 EFIAPI\r
154 FileInterfaceStdOutWrite(\r
155   IN EFI_FILE_PROTOCOL *This,\r
156   IN OUT UINTN *BufferSize,\r
157   IN VOID *Buffer\r
158   )\r
159 {\r
160   if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {\r
161     return (EFI_UNSUPPORTED);\r
162   } else {\r
163     return (gST->ConOut->OutputString(gST->ConOut, Buffer));\r
164   }\r
165 }\r
166 \r
167 /**\r
168   File style interface for StdIn (Write).\r
169   \r
170   @param[in] This            Ignored.\r
171   @param[in, out] BufferSize Ignored.\r
172   @param[in] Buffer          Ignored.\r
173   \r
174   @retval EFI_UNSUPPORTED\r
175 **/\r
176 EFI_STATUS\r
177 EFIAPI\r
178 FileInterfaceStdInWrite(\r
179   IN      EFI_FILE_PROTOCOL *This,\r
180   IN OUT  UINTN             *BufferSize,\r
181   IN      VOID              *Buffer\r
182   )\r
183 {\r
184   return (EFI_UNSUPPORTED);\r
185 }\r
186 \r
187 /**\r
188   File style interface for console StdErr (Write).\r
189 \r
190   Writes error to the error output.\r
191   \r
192   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
193   @param[in, out] BufferSize   Size in bytes of Buffer.\r
194   @param[in] Buffer            The pointer to the buffer to write.\r
195   \r
196   @return A return value from gST->StdErr->OutputString.\r
197 **/\r
198 EFI_STATUS\r
199 EFIAPI\r
200 FileInterfaceStdErrWrite(\r
201   IN EFI_FILE_PROTOCOL *This,\r
202   IN OUT UINTN *BufferSize,\r
203   IN VOID *Buffer\r
204   )\r
205 {\r
206   return (gST->StdErr->OutputString(gST->StdErr, Buffer));\r
207 }\r
208 \r
209 /**\r
210   File style interface for console StdOut (Read).\r
211   \r
212   @param[in] This              Ignored.\r
213   @param[in, out] BufferSize   Ignored.\r
214   @param[out] Buffer           Ignored.\r
215   \r
216   @retval EFI_UNSUPPORTED\r
217 **/\r
218 EFI_STATUS\r
219 EFIAPI\r
220 FileInterfaceStdOutRead(\r
221   IN EFI_FILE_PROTOCOL *This,\r
222   IN OUT UINTN *BufferSize,\r
223   OUT VOID *Buffer\r
224   )\r
225 {\r
226   return (EFI_UNSUPPORTED);\r
227 }\r
228 \r
229 /**\r
230   File style interface for console StdErr (Read).\r
231   \r
232   @param[in] This              Ignored.\r
233   @param[in, out] BufferSize   Ignored.\r
234   @param[out] Buffer           Ignored.\r
235   \r
236   @retval EFI_UNSUPPORTED Always.\r
237 **/\r
238 EFI_STATUS\r
239 EFIAPI\r
240 FileInterfaceStdErrRead(\r
241   IN EFI_FILE_PROTOCOL *This,\r
242   IN OUT UINTN *BufferSize,\r
243   OUT VOID *Buffer\r
244   )\r
245 {\r
246   return (EFI_UNSUPPORTED);\r
247 }\r
248 \r
249 /**\r
250   File style interface for NUL file (Read).\r
251   \r
252   @param[in] This              Ignored.\r
253   @param[in, out] BufferSize   Poiner to 0 upon return.\r
254   @param[out] Buffer           Ignored.\r
255   \r
256   @retval EFI_SUCCESS Always.\r
257 **/\r
258 EFI_STATUS\r
259 EFIAPI\r
260 FileInterfaceNulRead(\r
261   IN      EFI_FILE_PROTOCOL *This,\r
262   IN OUT  UINTN             *BufferSize,\r
263   OUT     VOID              *Buffer\r
264   )\r
265 {\r
266   *BufferSize = 0;\r
267   return (EFI_SUCCESS);\r
268 }\r
269 \r
270 /**\r
271   File style interface for NUL file (Write).\r
272   \r
273   @param[in] This              Ignored.\r
274   @param[in, out] BufferSize   Ignored.\r
275   @param[in] Buffer            Ignored.\r
276   \r
277   @retval EFI_SUCCESS\r
278 **/\r
279 EFI_STATUS\r
280 EFIAPI\r
281 FileInterfaceNulWrite(\r
282   IN EFI_FILE_PROTOCOL *This,\r
283   IN OUT UINTN *BufferSize,\r
284   IN VOID *Buffer\r
285   )\r
286 {\r
287   return (EFI_SUCCESS);\r
288 }\r
289 \r
290 /**\r
291   File style interface for console (Read).\r
292 \r
293   This will return a single line of input from the console.\r
294 \r
295   @param This           A pointer to the EFI_FILE_PROTOCOL instance that is the\r
296                         file handle to read data from. Not used.\r
297   @param BufferSize     On input, the size of the Buffer. On output, the amount\r
298                         of data returned in Buffer. In both cases, the size is\r
299                         measured in bytes.\r
300   @param Buffer         The buffer into which the data is read.\r
301 \r
302 \r
303   @retval EFI_SUCCESS           The data was read.\r
304   @retval EFI_NO_MEDIA          The device has no medium.\r
305   @retval EFI_DEVICE_ERROR      The device reported an error.\r
306   @retval EFI_DEVICE_ERROR      An attempt was made to read from a deleted file.\r
307   @retval EFI_DEVICE_ERROR      On entry, the current file position is beyond the end of the file.\r
308   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.\r
309   @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to read the current directory\r
310                                 entry. BufferSize has been updated with the size\r
311                                 needed to complete the request.\r
312   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
313 **/\r
314 EFI_STATUS\r
315 EFIAPI\r
316 FileInterfaceStdInRead(\r
317   IN EFI_FILE_PROTOCOL *This,\r
318   IN OUT UINTN *BufferSize,\r
319   OUT VOID *Buffer\r
320   )\r
321 {\r
322   CHAR16              *CurrentString;\r
323   BOOLEAN             Done;\r
324   UINTN               Column;         // Column of current cursor\r
325   UINTN               Row;            // Row of current cursor\r
326   UINTN               StartColumn;    // Column at the beginning of the line\r
327   UINTN               Update;         // Line index for update\r
328   UINTN               Delete;         // Num of chars to delete from console after update\r
329   UINTN               StringLen;      // Total length of the line\r
330   UINTN               StringCurPos;   // Line index corresponding to the cursor\r
331   UINTN               MaxStr;         // Maximum possible line length\r
332   UINTN               Index;\r
333   UINTN               TotalColumn;     // Num of columns in the console\r
334   UINTN               TotalRow;       // Num of rows in the console\r
335   UINTN               SkipLength;\r
336   UINTN               OutputLength;   // Length of the update string\r
337   UINTN               TailRow;        // Row of end of line\r
338   UINTN               TailColumn;     // Column of end of line\r
339   EFI_INPUT_KEY       Key;\r
340 \r
341   BUFFER_LIST         *LinePos;\r
342   BUFFER_LIST         *NewPos;\r
343   BOOLEAN             InScrolling;\r
344   EFI_STATUS          Status;\r
345   BOOLEAN             InTabScrolling; // Whether in TAB-completion state\r
346   EFI_SHELL_FILE_INFO *FoundFileList;\r
347   EFI_SHELL_FILE_INFO *TabLinePos;\r
348   EFI_SHELL_FILE_INFO *TempPos;\r
349   CHAR16              *TabStr;\r
350   CHAR16              *TabOutputStr;\r
351   BOOLEAN             InQuotationMode;\r
352   CHAR16              *TempStr;\r
353   UINTN               TabPos;         // Start index of the string to search for TAB completion.\r
354   UINTN               TabUpdatePos;   // Start index of the string updated by TAB stroke\r
355 //  UINTN               Count;\r
356   UINTN               EventIndex;\r
357   CONST CHAR16        *Cwd;\r
358 \r
359   //\r
360   // If buffer is not large enough to hold a CHAR16, return minimum buffer size\r
361   //\r
362   if (*BufferSize < sizeof (CHAR16) * 2) {\r
363     *BufferSize = sizeof (CHAR16) * 2;\r
364     return (EFI_BUFFER_TOO_SMALL);\r
365   }\r
366 \r
367   Done              = FALSE;\r
368   CurrentString     = Buffer;\r
369   StringLen         = 0;\r
370   StringCurPos      = 0;\r
371   OutputLength      = 0;\r
372   Update            = 0;\r
373   Delete            = 0;\r
374   LinePos           = NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);\r
375   InScrolling       = FALSE;\r
376   InTabScrolling    = FALSE;\r
377   Status            = EFI_SUCCESS;\r
378   TabLinePos        = NULL;\r
379   FoundFileList     = NULL;\r
380   TempPos           = NULL;\r
381   TabPos            = 0;\r
382   TabUpdatePos      = 0;\r
383 \r
384   //\r
385   // Allocate buffers\r
386   //\r
387   TabStr            = AllocateZeroPool (*BufferSize);\r
388   if (TabStr == NULL) {\r
389     return EFI_OUT_OF_RESOURCES;\r
390   }\r
391   TabOutputStr      = AllocateZeroPool (*BufferSize);\r
392   if (TabOutputStr == NULL) {\r
393     FreePool(TabStr);\r
394     return EFI_OUT_OF_RESOURCES;\r
395   }\r
396 \r
397   //\r
398   // Get the screen setting and the current cursor location\r
399   //\r
400   Column      = StartColumn = gST->ConOut->Mode->CursorColumn;\r
401   Row         = gST->ConOut->Mode->CursorRow;\r
402   gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &TotalColumn, &TotalRow);\r
403 \r
404   //\r
405   // Limit the line length to the buffer size or the minimun size of the\r
406   // screen. (The smaller takes effect)\r
407   //\r
408   MaxStr = TotalColumn * (TotalRow - 1) - StartColumn;\r
409   if (MaxStr > *BufferSize / sizeof (CHAR16)) {\r
410     MaxStr = *BufferSize / sizeof (CHAR16);\r
411   }\r
412   ZeroMem (CurrentString, MaxStr * sizeof (CHAR16));\r
413   do {\r
414     //\r
415     // Read a key\r
416     //\r
417     gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
418     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
419     if (EFI_ERROR (Status)) {\r
420       break;\r
421     }\r
422 \r
423     //\r
424     // Press PageUp or PageDown to scroll the history screen up or down.\r
425     // Press any other key to quit scrolling.\r
426     //\r
427     if (Key.UnicodeChar == 0 && (Key.ScanCode == SCAN_PAGE_UP || Key.ScanCode == SCAN_PAGE_DOWN)) {\r
428       if (Key.ScanCode == SCAN_PAGE_UP) {\r
429         ConsoleLoggerDisplayHistory(FALSE, 0, ShellInfoObject.ConsoleInfo);\r
430       } else if (Key.ScanCode == SCAN_PAGE_DOWN) {\r
431         ConsoleLoggerDisplayHistory(TRUE, 0, ShellInfoObject.ConsoleInfo);\r
432       }\r
433 \r
434       InScrolling = TRUE;\r
435     } else {\r
436       if (InScrolling) {\r
437         ConsoleLoggerStopHistory(ShellInfoObject.ConsoleInfo);\r
438         InScrolling = FALSE;\r
439       }\r
440     }\r
441 \r
442     //\r
443     // If we are quitting TAB scrolling...\r
444     //\r
445     if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) {\r
446         if (FoundFileList != NULL) {\r
447           ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FoundFileList);\r
448           DEBUG_CODE(FoundFileList = NULL;);\r
449         }\r
450         InTabScrolling = FALSE;\r
451     }\r
452 \r
453     switch (Key.UnicodeChar) {\r
454     case CHAR_CARRIAGE_RETURN:\r
455       //\r
456       // All done, print a newline at the end of the string\r
457       //\r
458       TailRow     = Row + (StringLen - StringCurPos + Column) / TotalColumn;\r
459       TailColumn  = (StringLen - StringCurPos + Column) % TotalColumn;\r
460       ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n");\r
461       Done = TRUE;\r
462       break;\r
463 \r
464     case CHAR_BACKSPACE:\r
465       if (StringCurPos != 0) {\r
466         //\r
467         // If not move back beyond string beginning, move all characters behind\r
468         // the current position one character forward\r
469         //\r
470         StringCurPos--;\r
471         Update  = StringCurPos;\r
472         Delete  = 1;\r
473         CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));\r
474 \r
475         //\r
476         // Adjust the current column and row\r
477         //\r
478         MoveCursorBackward (TotalColumn, &Column, &Row);\r
479       }\r
480       break;\r
481 \r
482     case CHAR_TAB:\r
483       //\r
484       // handle auto complete of file and directory names...\r
485       //\r
486       if (InTabScrolling) {\r
487         ASSERT(FoundFileList != NULL);\r
488         ASSERT(TabLinePos != NULL);\r
489         TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link);\r
490         if (IsNull(&(FoundFileList->Link), &TabLinePos->Link)) {\r
491           TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link);\r
492         }\r
493       } else {\r
494         TabPos          = 0;\r
495         TabUpdatePos    = 0;\r
496         InQuotationMode = FALSE;\r
497         for (Index = 0; Index < StringLen; Index++) {\r
498           if (CurrentString[Index] == L'\"') {\r
499             InQuotationMode = (BOOLEAN)(!InQuotationMode);\r
500           }\r
501           if (CurrentString[Index] == L' ' && !InQuotationMode) {\r
502             TabPos = Index + 1;\r
503             TabUpdatePos = Index + 1;\r
504           }\r
505           if (CurrentString[Index] == L'\\') {\r
506             TabUpdatePos = Index + 1;\r
507           }\r
508         }\r
509         if (StrStr(CurrentString + TabPos, L":") == NULL) {\r
510           Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir(NULL);\r
511           if (Cwd != NULL) {\r
512             StrnCpy(TabStr, Cwd, (*BufferSize)/sizeof(CHAR16) - 1);\r
513             if (TabStr[StrLen(TabStr)-1] == L'\\' && *(CurrentString + TabPos) == L'\\' ) {\r
514               TabStr[StrLen(TabStr)-1] = CHAR_NULL;\r
515             }\r
516             StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16));\r
517           } else {\r
518             *TabStr = CHAR_NULL;\r
519             StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16));\r
520           }\r
521         } else {\r
522           StrnCpy(TabStr, CurrentString + TabPos, (*BufferSize)/sizeof(CHAR16) - 1);\r
523         }\r
524         StrnCat(TabStr, L"*", (*BufferSize)/sizeof(CHAR16) - 1 - StrLen(TabStr));\r
525         FoundFileList = NULL;\r
526         Status  = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FoundFileList);\r
527         for ( TempStr = CurrentString\r
528             ; *TempStr == L' '\r
529             ; TempStr++); // note the ';'... empty for loop\r
530         //\r
531         // make sure we have a list before we do anything more...\r
532         //\r
533         if (EFI_ERROR (Status) || FoundFileList == NULL) {\r
534           InTabScrolling = FALSE;\r
535           TabLinePos = NULL;\r
536           continue;\r
537         } else {\r
538           //\r
539           // enumerate through the list of files\r
540           //\r
541           for ( TempPos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(FoundFileList->Link))\r
542               ; !IsNull(&FoundFileList->Link, &TempPos->Link)\r
543               ; TempPos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &(TempPos->Link))\r
544              ){\r
545             //\r
546             // If "cd" is typed, only directory name will be auto-complete filled\r
547             // in either case . and .. will be removed.\r
548             //\r
549             if ((((TempStr[0] == L'c' || TempStr[0] == L'C') &&\r
550                 (TempStr[1] == L'd' || TempStr[1] == L'D')\r
551                ) && ((ShellIsDirectory(TempPos->FullName) != EFI_SUCCESS)\r
552                 ||(StrCmp(TempPos->FileName, L".") == 0)\r
553                 ||(StrCmp(TempPos->FileName, L"..") == 0)\r
554                )) || ((StrCmp(TempPos->FileName, L".") == 0)\r
555                 ||(StrCmp(TempPos->FileName, L"..") == 0))){\r
556                 TabLinePos = TempPos;\r
557                 TempPos = (EFI_SHELL_FILE_INFO*)(RemoveEntryList(&(TempPos->Link))->BackLink);\r
558                 InternalFreeShellFileInfoNode(TabLinePos);\r
559             }\r
560           }\r
561           if (FoundFileList != NULL && !IsListEmpty(&FoundFileList->Link)) {\r
562             TabLinePos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FoundFileList->Link);\r
563             InTabScrolling = TRUE;\r
564           } else {\r
565             FreePool(FoundFileList);\r
566             FoundFileList = NULL;\r
567           }\r
568         }\r
569       }\r
570       break;\r
571 \r
572     default:\r
573       if (Key.UnicodeChar >= ' ') {\r
574         //\r
575         // If we are at the buffer's end, drop the key\r
576         //\r
577         if (StringLen == MaxStr - 1 && (ShellInfoObject.ViewingSettings.InsertMode || StringCurPos == StringLen)) {\r
578           break;\r
579         }\r
580         //\r
581         // If in insert mode, make space by moving each other character 1\r
582         // space higher in the array\r
583         //\r
584         if (ShellInfoObject.ViewingSettings.InsertMode) {\r
585           CopyMem(CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof(CurrentString[0]));\r
586         }\r
587 \r
588         CurrentString[StringCurPos] = Key.UnicodeChar;\r
589         Update      = StringCurPos;\r
590 \r
591         StringCurPos += 1;\r
592         OutputLength = 1;\r
593       }\r
594       break;\r
595 \r
596     case 0:\r
597       switch (Key.ScanCode) {\r
598       case SCAN_DELETE:\r
599         //\r
600         // Move characters behind current position one character forward\r
601         //\r
602         if (StringLen != 0) {\r
603           Update  = StringCurPos;\r
604           Delete  = 1;\r
605           CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));\r
606         }\r
607         break;\r
608 \r
609       case SCAN_UP:\r
610         //\r
611         // Prepare to print the previous command\r
612         //\r
613         NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);\r
614         if (IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link)) {\r
615           NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);\r
616         }\r
617         break;\r
618 \r
619       case SCAN_DOWN:\r
620         //\r
621         // Prepare to print the next command\r
622         //\r
623         NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);\r
624         if (NewPos == (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {\r
625           NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);\r
626         }\r
627         break;\r
628 \r
629       case SCAN_LEFT:\r
630         //\r
631         // Adjust current cursor position\r
632         //\r
633         if (StringCurPos != 0) {\r
634           --StringCurPos;\r
635           MoveCursorBackward (TotalColumn, &Column, &Row);\r
636         }\r
637         break;\r
638 \r
639       case SCAN_RIGHT:\r
640         //\r
641         // Adjust current cursor position\r
642         //\r
643         if (StringCurPos < StringLen) {\r
644           ++StringCurPos;\r
645           MoveCursorForward (TotalColumn, TotalRow, &Column, &Row);\r
646         }\r
647         break;\r
648 \r
649       case SCAN_HOME:\r
650         //\r
651         // Move current cursor position to the beginning of the command line\r
652         //\r
653         Row -= (StringCurPos + StartColumn) / TotalColumn;\r
654         Column  = StartColumn;\r
655         StringCurPos  = 0;\r
656         break;\r
657 \r
658       case SCAN_END:\r
659         //\r
660         // Move current cursor position to the end of the command line\r
661         //\r
662         TailRow       = Row + (StringLen - StringCurPos + Column) / TotalColumn;\r
663         TailColumn    = (StringLen - StringCurPos + Column) % TotalColumn;\r
664         Row           = TailRow;\r
665         Column        = TailColumn;\r
666         StringCurPos  = StringLen;\r
667         break;\r
668 \r
669       case SCAN_ESC:\r
670         //\r
671         // Prepare to clear the current command line\r
672         //\r
673         CurrentString[0]  = 0;\r
674         Update  = 0;\r
675         Delete  = StringLen;\r
676         Row -= (StringCurPos + StartColumn) / TotalColumn;\r
677         Column        = StartColumn;\r
678         OutputLength  = 0;\r
679         break;\r
680 \r
681       case SCAN_INSERT:\r
682         //\r
683         // Toggle the SEnvInsertMode flag\r
684         //\r
685         ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN)!ShellInfoObject.ViewingSettings.InsertMode;\r
686         break;\r
687 \r
688       case SCAN_F7:\r
689         //\r
690         // Print command history\r
691         //\r
692         PrintCommandHistory (TotalColumn, TotalRow, 4);\r
693         *CurrentString  = CHAR_NULL;\r
694         Done  = TRUE;\r
695         break;\r
696       }\r
697     }\r
698 \r
699     if (Done) {\r
700       break;\r
701     }\r
702 \r
703     //\r
704     // If we are in auto-complete mode, we are preparing to print\r
705     // the next file or directory name\r
706     //\r
707     if (InTabScrolling) {\r
708       //\r
709       // Adjust the column and row to the start of TAB-completion string.\r
710       //\r
711       Column = (StartColumn + TabUpdatePos) % TotalColumn;\r
712       Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;\r
713       OutputLength = StrLen (TabLinePos->FileName);\r
714       //\r
715       // if the output string contains  blank space, quotation marks L'\"'\r
716       // should be added to the output.\r
717       //\r
718       if (StrStr(TabLinePos->FileName, L" ") != NULL){\r
719         TabOutputStr[0] = L'\"';\r
720         CopyMem (TabOutputStr + 1, TabLinePos->FileName, OutputLength * sizeof (CHAR16));\r
721         TabOutputStr[OutputLength + 1] = L'\"';\r
722         TabOutputStr[OutputLength + 2] = CHAR_NULL;\r
723       } else {\r
724         CopyMem (TabOutputStr, TabLinePos->FileName, OutputLength * sizeof (CHAR16));\r
725         TabOutputStr[OutputLength] = CHAR_NULL;\r
726       }\r
727       OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1;\r
728       CopyMem (CurrentString + TabUpdatePos, TabOutputStr, OutputLength * sizeof (CHAR16));\r
729       CurrentString[TabUpdatePos + OutputLength] = CHAR_NULL;\r
730       StringCurPos = TabUpdatePos + OutputLength;\r
731       Update = TabUpdatePos;\r
732       if (StringLen > TabUpdatePos + OutputLength) {\r
733         Delete = StringLen - TabUpdatePos - OutputLength;\r
734       }\r
735     }\r
736 \r
737     //\r
738     // If we have a new position, we are preparing to print a previous or\r
739     // next command.\r
740     //\r
741     if (NewPos != (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {\r
742       Column = StartColumn;\r
743       Row -= (StringCurPos + StartColumn) / TotalColumn;\r
744 \r
745       LinePos       = NewPos;\r
746       NewPos        = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);\r
747 \r
748       OutputLength  = StrLen (LinePos->Buffer) < MaxStr - 1 ? StrLen (LinePos->Buffer) : MaxStr - 1;\r
749       CopyMem (CurrentString, LinePos->Buffer, OutputLength * sizeof (CHAR16));\r
750       CurrentString[OutputLength] = CHAR_NULL;\r
751 \r
752       StringCurPos            = OutputLength;\r
753 \r
754       //\r
755       // Draw new input string\r
756       //\r
757       Update = 0;\r
758       if (StringLen > OutputLength) {\r
759         //\r
760         // If old string was longer, blank its tail\r
761         //\r
762         Delete = StringLen - OutputLength;\r
763       }\r
764     }\r
765     //\r
766     // If we need to update the output do so now\r
767     //\r
768     if (Update != (UINTN) -1) {\r
769       ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L"");\r
770       StringLen = StrLen (CurrentString);\r
771 \r
772       if (Delete != 0) {\r
773         SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL);\r
774       }\r
775 \r
776       if (StringCurPos > StringLen) {\r
777         StringCurPos = StringLen;\r
778       }\r
779 \r
780       Update = (UINTN) -1;\r
781 \r
782       //\r
783       // After using print to reflect newly updates, if we're not using\r
784       // BACKSPACE and DELETE, we need to move the cursor position forward,\r
785       // so adjust row and column here.\r
786       //\r
787       if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {\r
788         //\r
789         // Calulate row and column of the tail of current string\r
790         //\r
791         TailRow     = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn;\r
792         TailColumn  = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn;\r
793 \r
794         //\r
795         // If the tail of string reaches screen end, screen rolls up, so if\r
796         // Row does not equal TailRow, Row should be decremented\r
797         //\r
798         // (if we are recalling commands using UPPER and DOWN key, and if the\r
799         // old command is too long to fit the screen, TailColumn must be 79.\r
800         //\r
801         if (TailColumn == 0 && TailRow >= TotalRow && Row != TailRow) {\r
802           Row--;\r
803         }\r
804         //\r
805         // Calculate the cursor position after current operation. If cursor\r
806         // reaches line end, update both row and column, otherwise, only\r
807         // column will be changed.\r
808         //\r
809         if (Column + OutputLength >= TotalColumn) {\r
810           SkipLength = OutputLength - (TotalColumn - Column);\r
811 \r
812           Row += SkipLength / TotalColumn + 1;\r
813           if (Row > TotalRow - 1) {\r
814             Row = TotalRow - 1;\r
815           }\r
816 \r
817           Column = SkipLength % TotalColumn;\r
818         } else {\r
819           Column += OutputLength;\r
820         }\r
821       }\r
822 \r
823       Delete = 0;\r
824     }\r
825     //\r
826     // Set the cursor position for this key\r
827     //\r
828     gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);\r
829   } while (!Done);\r
830 \r
831   if (CurrentString != NULL && StrLen(CurrentString) > 0) {\r
832     //\r
833     // add the line to the history buffer\r
834     //\r
835     AddLineToCommandHistory(CurrentString);\r
836   }\r
837 \r
838   FreePool (TabStr);\r
839   FreePool (TabOutputStr);\r
840   //\r
841   // Return the data to the caller\r
842   //\r
843   *BufferSize = StringLen * sizeof (CHAR16);\r
844 \r
845   //\r
846   // if this was used it should be deallocated by now...\r
847   // prevent memory leaks...\r
848   //\r
849   ASSERT(FoundFileList == NULL);\r
850 \r
851   return Status;\r
852 }\r
853 \r
854 //\r
855 // FILE sytle interfaces for StdIn/StdOut/StdErr\r
856 //\r
857 EFI_FILE_PROTOCOL FileInterfaceStdIn = {\r
858   EFI_FILE_REVISION,\r
859   FileInterfaceOpenNotFound,\r
860   FileInterfaceNopGeneric,\r
861   FileInterfaceNopGeneric,\r
862   FileInterfaceStdInRead,\r
863   FileInterfaceStdInWrite,\r
864   FileInterfaceNopGetPosition,\r
865   FileInterfaceNopSetPosition,\r
866   FileInterfaceNopGetInfo,\r
867   FileInterfaceNopSetInfo,\r
868   FileInterfaceNopGeneric\r
869 };\r
870 \r
871 EFI_FILE_PROTOCOL FileInterfaceStdOut = {\r
872   EFI_FILE_REVISION,\r
873   FileInterfaceOpenNotFound,\r
874   FileInterfaceNopGeneric,\r
875   FileInterfaceNopGeneric,\r
876   FileInterfaceStdOutRead,\r
877   FileInterfaceStdOutWrite,\r
878   FileInterfaceNopGetPosition,\r
879   FileInterfaceNopSetPosition,\r
880   FileInterfaceNopGetInfo,\r
881   FileInterfaceNopSetInfo,\r
882   FileInterfaceNopGeneric\r
883 };\r
884 \r
885 EFI_FILE_PROTOCOL FileInterfaceStdErr = {\r
886   EFI_FILE_REVISION,\r
887   FileInterfaceOpenNotFound,\r
888   FileInterfaceNopGeneric,\r
889   FileInterfaceNopGeneric,\r
890   FileInterfaceStdErrRead,\r
891   FileInterfaceStdErrWrite,\r
892   FileInterfaceNopGetPosition,\r
893   FileInterfaceNopSetPosition,\r
894   FileInterfaceNopGetInfo,\r
895   FileInterfaceNopSetInfo,\r
896   FileInterfaceNopGeneric\r
897 };\r
898 \r
899 EFI_FILE_PROTOCOL FileInterfaceNulFile = {\r
900   EFI_FILE_REVISION,\r
901   FileInterfaceOpenNotFound,\r
902   FileInterfaceNopGeneric,\r
903   FileInterfaceNopGeneric,\r
904   FileInterfaceNulRead,\r
905   FileInterfaceNulWrite,\r
906   FileInterfaceNopGetPosition,\r
907   FileInterfaceNopSetPosition,\r
908   FileInterfaceNopGetInfo,\r
909   FileInterfaceNopSetInfo,\r
910   FileInterfaceNopGeneric\r
911 };\r
912 \r
913 \r
914 \r
915 \r
916 //\r
917 // This is identical to EFI_FILE_PROTOCOL except for the additional member\r
918 // for the name.\r
919 //\r
920 \r
921 typedef struct {\r
922   UINT64                Revision;\r
923   EFI_FILE_OPEN         Open;\r
924   EFI_FILE_CLOSE        Close;\r
925   EFI_FILE_DELETE       Delete;\r
926   EFI_FILE_READ         Read;\r
927   EFI_FILE_WRITE        Write;\r
928   EFI_FILE_GET_POSITION GetPosition;\r
929   EFI_FILE_SET_POSITION SetPosition;\r
930   EFI_FILE_GET_INFO     GetInfo;\r
931   EFI_FILE_SET_INFO     SetInfo;\r
932   EFI_FILE_FLUSH        Flush;\r
933   CHAR16                Name[1];\r
934 } EFI_FILE_PROTOCOL_ENVIRONMENT;\r
935 //ANSI compliance helper to get size of the struct.\r
936 #define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name)\r
937 \r
938 /**\r
939   File style interface for Environment Variable (Close).\r
940 \r
941   Frees the memory for this object.\r
942   \r
943   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
944   \r
945   @retval EFI_SUCCESS\r
946 **/\r
947 EFI_STATUS\r
948 EFIAPI\r
949 FileInterfaceEnvClose(\r
950   IN EFI_FILE_PROTOCOL *This\r
951   )\r
952 {\r
953   VOID*       NewBuffer;\r
954   UINTN       NewSize;\r
955   EFI_STATUS  Status;\r
956 \r
957   //\r
958   // Most if not all UEFI commands will have an '\r\n' at the end of any output. \r
959   // Since the output was redirected to a variable, it does not make sense to \r
960   // keep this.  So, before closing, strip the trailing '\r\n' from the variable\r
961   // if it exists.\r
962   //\r
963   NewBuffer   = NULL;\r
964   NewSize     = 0;\r
965 \r
966   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
967   if (Status == EFI_BUFFER_TOO_SMALL) {\r
968     NewBuffer = AllocateZeroPool(NewSize + sizeof(CHAR16));\r
969     if (NewBuffer == NULL) {\r
970       return EFI_OUT_OF_RESOURCES;\r
971     }  \r
972     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
973   }\r
974   \r
975   if (!EFI_ERROR(Status) && NewBuffer != NULL) {\r
976     \r
977     if (StrSize(NewBuffer) > 6)\r
978     {\r
979       if ((((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 2] == CHAR_LINEFEED) \r
980            && (((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] == CHAR_CARRIAGE_RETURN)) {\r
981         ((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] = CHAR_NULL;   \r
982       }\r
983     \r
984       if (IsVolatileEnv(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name)) {\r
985         Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
986       } else {\r
987         Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
988       }\r
989     }\r
990   } \r
991   \r
992   SHELL_FREE_NON_NULL(NewBuffer);\r
993   FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This);\r
994   return (Status);\r
995 }\r
996 \r
997 /**\r
998   File style interface for Environment Variable (Delete).\r
999   \r
1000   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
1001   \r
1002   @retval The return value from FileInterfaceEnvClose().\r
1003 **/\r
1004 EFI_STATUS\r
1005 EFIAPI\r
1006 FileInterfaceEnvDelete(\r
1007   IN EFI_FILE_PROTOCOL *This\r
1008   )\r
1009 {\r
1010   SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);\r
1011   return (FileInterfaceEnvClose(This));\r
1012 }\r
1013 \r
1014 /**\r
1015   File style interface for Environment Variable (Read).\r
1016   \r
1017   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
1018   @param[in, out] BufferSize   Size in bytes of Buffer.\r
1019   @param[out] Buffer           The pointer to the buffer to fill.\r
1020   \r
1021   @retval EFI_SUCCESS   The data was read.\r
1022 **/\r
1023 EFI_STATUS\r
1024 EFIAPI\r
1025 FileInterfaceEnvRead(\r
1026   IN EFI_FILE_PROTOCOL *This,\r
1027   IN OUT UINTN *BufferSize,\r
1028   OUT VOID *Buffer\r
1029   )\r
1030 {\r
1031   return (SHELL_GET_ENVIRONMENT_VARIABLE(\r
1032     ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
1033     BufferSize,\r
1034     Buffer));\r
1035 }\r
1036 \r
1037 /**\r
1038   File style interface for Volatile Environment Variable (Write).\r
1039   \r
1040   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
1041   @param[in, out] BufferSize   Size in bytes of Buffer.\r
1042   @param[in] Buffer            The pointer to the buffer to write.\r
1043   \r
1044   @retval EFI_SUCCESS   The data was read.\r
1045 **/\r
1046 EFI_STATUS\r
1047 EFIAPI\r
1048 FileInterfaceEnvVolWrite(\r
1049   IN EFI_FILE_PROTOCOL *This,\r
1050   IN OUT UINTN *BufferSize,\r
1051   IN VOID *Buffer\r
1052   )\r
1053 {\r
1054   VOID*       NewBuffer;\r
1055   UINTN       NewSize;\r
1056   EFI_STATUS  Status;\r
1057 \r
1058   NewBuffer   = NULL;\r
1059   NewSize     = 0;\r
1060 \r
1061   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
1062   if (Status == EFI_BUFFER_TOO_SMALL){\r
1063     NewBuffer = AllocateZeroPool(NewSize + *BufferSize + sizeof(CHAR16));\r
1064     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
1065   }\r
1066   if (!EFI_ERROR(Status) && NewBuffer != NULL) {\r
1067     while (((CHAR16*)NewBuffer)[NewSize/2] == CHAR_NULL) {\r
1068       //\r
1069       // We want to overwrite the CHAR_NULL\r
1070       //\r
1071       NewSize -= 2;\r
1072     }\r
1073     CopyMem((UINT8*)NewBuffer + NewSize + 2, Buffer, *BufferSize);\r
1074     Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
1075     FreePool(NewBuffer);\r
1076     return (Status);\r
1077   } else {\r
1078     SHELL_FREE_NON_NULL(NewBuffer);\r
1079     return (SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, *BufferSize, Buffer));\r
1080   }\r
1081 }\r
1082 \r
1083 \r
1084 /**\r
1085   File style interface for Non Volatile Environment Variable (Write).\r
1086   \r
1087   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
1088   @param[in, out] BufferSize   Size in bytes of Buffer.\r
1089   @param[in] Buffer            The pointer to the buffer to write.\r
1090   \r
1091   @retval EFI_SUCCESS   The data was read.\r
1092 **/\r
1093 EFI_STATUS\r
1094 EFIAPI\r
1095 FileInterfaceEnvNonVolWrite(\r
1096   IN EFI_FILE_PROTOCOL *This,\r
1097   IN OUT UINTN *BufferSize,\r
1098   IN VOID *Buffer\r
1099   )\r
1100 {\r
1101   VOID*       NewBuffer;\r
1102   UINTN       NewSize;\r
1103   EFI_STATUS  Status;\r
1104 \r
1105   NewBuffer   = NULL;\r
1106   NewSize     = 0;\r
1107 \r
1108   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
1109   if (Status == EFI_BUFFER_TOO_SMALL){\r
1110     NewBuffer = AllocateZeroPool(NewSize + *BufferSize);\r
1111     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
1112   }\r
1113   if (!EFI_ERROR(Status)) {\r
1114     CopyMem((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);\r
1115     return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(\r
1116     ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
1117     NewSize + *BufferSize,\r
1118     NewBuffer));\r
1119   } else {\r
1120     return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(\r
1121     ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
1122     *BufferSize,\r
1123     Buffer));\r
1124   }\r
1125 }\r
1126 \r
1127 /**\r
1128   Creates a EFI_FILE_PROTOCOL (almost) object for using to access\r
1129   environment variables through file operations.\r
1130 \r
1131   @param EnvName    The name of the Environment Variable to be operated on.\r
1132 \r
1133   @retval NULL      Memory could not be allocated.\r
1134   @return other     a pointer to an EFI_FILE_PROTOCOL structure\r
1135 **/\r
1136 EFI_FILE_PROTOCOL*\r
1137 EFIAPI\r
1138 CreateFileInterfaceEnv(\r
1139   IN CONST CHAR16 *EnvName\r
1140   )\r
1141 {\r
1142   EFI_FILE_PROTOCOL_ENVIRONMENT  *EnvFileInterface;\r
1143   UINTN                          EnvNameSize;\r
1144 \r
1145   if (EnvName == NULL) {\r
1146     return (NULL);\r
1147   }\r
1148 \r
1149   //\r
1150   // Get some memory\r
1151   //\r
1152   EnvNameSize = StrSize(EnvName);\r
1153   EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize);\r
1154   if (EnvFileInterface == NULL){\r
1155     return (NULL);\r
1156   }\r
1157 \r
1158   //\r
1159   // Assign the generic members\r
1160   //\r
1161   EnvFileInterface->Revision    = EFI_FILE_REVISION;\r
1162   EnvFileInterface->Open        = FileInterfaceOpenNotFound;\r
1163   EnvFileInterface->Close       = FileInterfaceEnvClose;\r
1164   EnvFileInterface->GetPosition = FileInterfaceNopGetPosition;\r
1165   EnvFileInterface->SetPosition = FileInterfaceNopSetPosition;\r
1166   EnvFileInterface->GetInfo     = FileInterfaceNopGetInfo;\r
1167   EnvFileInterface->SetInfo     = FileInterfaceNopSetInfo;\r
1168   EnvFileInterface->Flush       = FileInterfaceNopGeneric;\r
1169   EnvFileInterface->Delete      = FileInterfaceEnvDelete;\r
1170   EnvFileInterface->Read        = FileInterfaceEnvRead;\r
1171   \r
1172   CopyMem(EnvFileInterface->Name, EnvName, EnvNameSize);\r
1173 \r
1174   //\r
1175   // Assign the different members for Volatile and Non-Volatile variables\r
1176   //\r
1177   if (IsVolatileEnv(EnvName)) {\r
1178     EnvFileInterface->Write       = FileInterfaceEnvVolWrite;\r
1179   } else {\r
1180     EnvFileInterface->Write       = FileInterfaceEnvNonVolWrite;\r
1181   }\r
1182   return ((EFI_FILE_PROTOCOL *)EnvFileInterface);\r
1183 }\r
1184 \r
1185 /**\r
1186   Move the cursor position one character backward.\r
1187 \r
1188   @param[in] LineLength       Length of a line. Get it by calling QueryMode\r
1189   @param[in, out] Column      Current column of the cursor position\r
1190   @param[in, out] Row         Current row of the cursor position\r
1191 **/\r
1192 VOID\r
1193 EFIAPI\r
1194 MoveCursorBackward (\r
1195   IN     UINTN                   LineLength,\r
1196   IN OUT UINTN                   *Column,\r
1197   IN OUT UINTN                   *Row\r
1198   )\r
1199 {\r
1200   //\r
1201   // If current column is 0, move to the last column of the previous line,\r
1202   // otherwise, just decrement column.\r
1203   //\r
1204   if (*Column == 0) {\r
1205     *Column = LineLength - 1;\r
1206     if (*Row > 0) {\r
1207       (*Row)--;\r
1208     }\r
1209     return;\r
1210   }\r
1211   (*Column)--;\r
1212 }\r
1213 \r
1214 /**\r
1215   Move the cursor position one character forward.\r
1216 \r
1217   @param[in] LineLength       Length of a line.\r
1218   @param[in] TotalRow         Total row of a screen\r
1219   @param[in, out] Column      Current column of the cursor position\r
1220   @param[in, out] Row         Current row of the cursor position\r
1221 **/\r
1222 VOID\r
1223 EFIAPI\r
1224 MoveCursorForward (\r
1225   IN     UINTN                   LineLength,\r
1226   IN     UINTN                   TotalRow,\r
1227   IN OUT UINTN                   *Column,\r
1228   IN OUT UINTN                   *Row\r
1229   )\r
1230 {\r
1231   //\r
1232   // Increment Column.\r
1233   // If this puts column past the end of the line, move to first column\r
1234   // of the next row.\r
1235   //\r
1236   (*Column)++;\r
1237   if (*Column >= LineLength) {\r
1238     (*Column) = 0;\r
1239     if ((*Row) < TotalRow - 1) {\r
1240       (*Row)++;\r
1241     }\r
1242   }\r
1243 }\r
1244 \r
1245 /**\r
1246   Prints out each previously typed command in the command list history log.\r
1247 \r
1248   When each screen is full it will pause for a key before continuing.\r
1249 \r
1250   @param[in] TotalCols    How many columns are on the screen\r
1251   @param[in] TotalRows    How many rows are on the screen\r
1252   @param[in] StartColumn  which column to start at\r
1253 **/\r
1254 VOID\r
1255 EFIAPI\r
1256 PrintCommandHistory (\r
1257   IN CONST UINTN TotalCols,\r
1258   IN CONST UINTN TotalRows,\r
1259   IN CONST UINTN StartColumn\r
1260   )\r
1261 {\r
1262   BUFFER_LIST     *Node;\r
1263   UINTN           Index;\r
1264   UINTN           LineNumber;\r
1265   UINTN           LineCount;\r
1266 \r
1267   ShellPrintEx (-1, -1, L"\n");\r
1268   Index       = 0;\r
1269   LineNumber  = 0;\r
1270   //\r
1271   // go through history list...\r
1272   //\r
1273   for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link)\r
1274       ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)\r
1275       ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)\r
1276    ){\r
1277     Index++;\r
1278     LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1;\r
1279 \r
1280     if (LineNumber + LineCount >= TotalRows) {\r
1281       ShellPromptForResponseHii(\r
1282         ShellPromptResponseTypeEnterContinue,\r
1283         STRING_TOKEN (STR_SHELL_ENTER_TO_CONT),\r
1284         ShellInfoObject.HiiHandle,\r
1285         NULL\r
1286        );\r
1287       LineNumber = 0;\r
1288     }\r
1289     ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer);\r
1290     LineNumber += LineCount;\r
1291   }\r
1292 }\r
1293 \r
1294 \r
1295 \r
1296 \r
1297 \r
1298 \r
1299 //\r
1300 // This is identical to EFI_FILE_PROTOCOL except for the additional members\r
1301 // for the buffer, size, and position.\r
1302 //\r
1303 \r
1304 typedef struct {\r
1305   UINT64                Revision;\r
1306   EFI_FILE_OPEN         Open;\r
1307   EFI_FILE_CLOSE        Close;\r
1308   EFI_FILE_DELETE       Delete;\r
1309   EFI_FILE_READ         Read;\r
1310   EFI_FILE_WRITE        Write;\r
1311   EFI_FILE_GET_POSITION GetPosition;\r
1312   EFI_FILE_SET_POSITION SetPosition;\r
1313   EFI_FILE_GET_INFO     GetInfo;\r
1314   EFI_FILE_SET_INFO     SetInfo;\r
1315   EFI_FILE_FLUSH        Flush;\r
1316   VOID                  *Buffer;\r
1317   UINT64                Position;\r
1318   UINT64                BufferSize;\r
1319   BOOLEAN               Unicode;\r
1320 } EFI_FILE_PROTOCOL_MEM;\r
1321 \r
1322 /**\r
1323   File style interface for Mem (SetPosition).\r
1324   \r
1325   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
1326   @param[out] Position  The position to set.\r
1327   \r
1328   @retval EFI_SUCCESS             The position was successfully changed.\r
1329   @retval EFI_INVALID_PARAMETER   The Position was invalid.\r
1330 **/\r
1331 EFI_STATUS\r
1332 EFIAPI\r
1333 FileInterfaceMemSetPosition(\r
1334   IN EFI_FILE_PROTOCOL *This,\r
1335   OUT UINT64 Position\r
1336   )\r
1337 {\r
1338   if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) {\r
1339     ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position;\r
1340     return (EFI_SUCCESS);\r
1341   } else {\r
1342     return (EFI_INVALID_PARAMETER);\r
1343   }\r
1344 }\r
1345 \r
1346 /**\r
1347   File style interface for Mem (GetPosition).\r
1348   \r
1349   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
1350   @param[out] Position  The pointer to the position.\r
1351   \r
1352   @retval EFI_SUCCESS   The position was retrieved.\r
1353 **/ \r
1354 EFI_STATUS\r
1355 EFIAPI\r
1356 FileInterfaceMemGetPosition(\r
1357   IN EFI_FILE_PROTOCOL *This,\r
1358   OUT UINT64 *Position\r
1359   )\r
1360 {\r
1361   *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position;\r
1362   return (EFI_SUCCESS);\r
1363 }\r
1364 \r
1365 /**\r
1366   File style interface for Mem (Write).\r
1367   \r
1368   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
1369   @param[in, out] BufferSize   Size in bytes of Buffer.\r
1370   @param[in] Buffer            The pointer to the buffer to write.\r
1371   \r
1372   @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.\r
1373   @retval EFI_SUCCESS          The data was written.\r
1374 **/\r
1375 EFI_STATUS\r
1376 EFIAPI\r
1377 FileInterfaceMemWrite(\r
1378   IN EFI_FILE_PROTOCOL *This,\r
1379   IN OUT UINTN *BufferSize,\r
1380   IN VOID *Buffer\r
1381   )\r
1382 {\r
1383   CHAR8 *AsciiBuffer;\r
1384   if (((EFI_FILE_PROTOCOL_MEM*)This)->Unicode) {\r
1385     //\r
1386     // Unicode\r
1387     //\r
1388     if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) {\r
1389       ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer = ReallocatePool((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize), (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) + (*BufferSize) + 10, ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);\r
1390       ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += (*BufferSize) + 10;\r
1391     }\r
1392     CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, Buffer, *BufferSize);\r
1393     ((EFI_FILE_PROTOCOL_MEM*)This)->Position += (*BufferSize);\r
1394     return (EFI_SUCCESS);\r
1395   } else {\r
1396     //\r
1397     // Ascii\r
1398     //\r
1399     AsciiBuffer = AllocateZeroPool(*BufferSize);\r
1400     if (AsciiBuffer == NULL) {\r
1401       return (EFI_OUT_OF_RESOURCES);\r
1402     }\r
1403     AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);\r
1404     if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) {\r
1405       ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer = ReallocatePool((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize), (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) + AsciiStrSize(AsciiBuffer) + 10, ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);\r
1406       ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += AsciiStrSize(AsciiBuffer) + 10;\r
1407     }\r
1408     CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer));\r
1409     ((EFI_FILE_PROTOCOL_MEM*)This)->Position += AsciiStrSize(AsciiBuffer);\r
1410     FreePool(AsciiBuffer);\r
1411     return (EFI_SUCCESS);\r
1412   }\r
1413 }\r
1414 \r
1415 /**\r
1416   File style interface for Mem (Read).\r
1417   \r
1418   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
1419   @param[in, out] BufferSize   Size in bytes of Buffer.\r
1420   @param[in] Buffer            The pointer to the buffer to fill.\r
1421   \r
1422   @retval EFI_SUCCESS   The data was read.\r
1423 **/\r
1424 EFI_STATUS\r
1425 EFIAPI\r
1426 FileInterfaceMemRead(\r
1427   IN EFI_FILE_PROTOCOL *This,\r
1428   IN OUT UINTN *BufferSize,\r
1429   IN VOID *Buffer\r
1430   )\r
1431 {\r
1432   if (*BufferSize > (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position))) {\r
1433     (*BufferSize) = (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position));\r
1434   }\r
1435   CopyMem(Buffer, ((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, (*BufferSize));\r
1436   ((EFI_FILE_PROTOCOL_MEM*)This)->Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize);\r
1437   return (EFI_SUCCESS);\r
1438 }\r
1439 \r
1440 /**\r
1441   File style interface for Mem (Close).\r
1442 \r
1443   Frees all memory associated with this object.\r
1444   \r
1445   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
1446   \r
1447   @retval EFI_SUCCESS   The 'file' was closed.\r
1448 **/ \r
1449 EFI_STATUS\r
1450 EFIAPI\r
1451 FileInterfaceMemClose(\r
1452   IN EFI_FILE_PROTOCOL *This\r
1453   )\r
1454 {\r
1455   SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);\r
1456   SHELL_FREE_NON_NULL(This);\r
1457   return (EFI_SUCCESS);\r
1458 }\r
1459 \r
1460 /**\r
1461   Creates a EFI_FILE_PROTOCOL (almost) object for using to access\r
1462   a file entirely in memory through file operations.\r
1463 \r
1464   @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii.\r
1465 \r
1466   @retval NULL      Memory could not be allocated.\r
1467   @return other     A pointer to an EFI_FILE_PROTOCOL structure.\r
1468 **/\r
1469 EFI_FILE_PROTOCOL*\r
1470 EFIAPI\r
1471 CreateFileInterfaceMem(\r
1472   IN CONST BOOLEAN Unicode\r
1473   )\r
1474 {\r
1475   EFI_FILE_PROTOCOL_MEM  *FileInterface;\r
1476 \r
1477   //\r
1478   // Get some memory\r
1479   //\r
1480   FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM));\r
1481   if (FileInterface == NULL){\r
1482     return (NULL);\r
1483   }\r
1484 \r
1485   //\r
1486   // Assign the generic members\r
1487   //\r
1488   FileInterface->Revision    = EFI_FILE_REVISION;\r
1489   FileInterface->Open        = FileInterfaceOpenNotFound;\r
1490   FileInterface->Close       = FileInterfaceMemClose;\r
1491   FileInterface->GetPosition = FileInterfaceMemGetPosition;\r
1492   FileInterface->SetPosition = FileInterfaceMemSetPosition;\r
1493   FileInterface->GetInfo     = FileInterfaceNopGetInfo;\r
1494   FileInterface->SetInfo     = FileInterfaceNopSetInfo;\r
1495   FileInterface->Flush       = FileInterfaceNopGeneric;\r
1496   FileInterface->Delete      = FileInterfaceNopGeneric;\r
1497   FileInterface->Read        = FileInterfaceMemRead;\r
1498   FileInterface->Write       = FileInterfaceMemWrite;\r
1499   FileInterface->Unicode     = Unicode;\r
1500 \r
1501   ASSERT(FileInterface->Buffer      == NULL);\r
1502   ASSERT(FileInterface->BufferSize  == 0);\r
1503   ASSERT(FileInterface->Position    == 0);\r
1504 \r
1505   return ((EFI_FILE_PROTOCOL *)FileInterface);\r
1506 }\r
1507 \r
1508 typedef struct {\r
1509   UINT64                Revision;\r
1510   EFI_FILE_OPEN         Open;\r
1511   EFI_FILE_CLOSE        Close;\r
1512   EFI_FILE_DELETE       Delete;\r
1513   EFI_FILE_READ         Read;\r
1514   EFI_FILE_WRITE        Write;\r
1515   EFI_FILE_GET_POSITION GetPosition;\r
1516   EFI_FILE_SET_POSITION SetPosition;\r
1517   EFI_FILE_GET_INFO     GetInfo;\r
1518   EFI_FILE_SET_INFO     SetInfo;\r
1519   EFI_FILE_FLUSH        Flush;\r
1520   BOOLEAN               Unicode;\r
1521   EFI_FILE_PROTOCOL     *Orig;\r
1522 } EFI_FILE_PROTOCOL_FILE;\r
1523 \r
1524 /**\r
1525   Set a files current position\r
1526 \r
1527   @param  This            Protocol instance pointer.\r
1528   @param  Position        Byte position from the start of the file.\r
1529                           \r
1530   @retval EFI_SUCCESS     Data was written.\r
1531   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.\r
1532 \r
1533 **/\r
1534 EFI_STATUS\r
1535 EFIAPI\r
1536 FileInterfaceFileSetPosition(\r
1537   IN EFI_FILE_PROTOCOL        *This,\r
1538   IN UINT64                   Position\r
1539   )\r
1540 {\r
1541   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);\r
1542 }\r
1543 \r
1544 /**\r
1545   Get a file's current position\r
1546 \r
1547   @param  This            Protocol instance pointer.\r
1548   @param  Position        Byte position from the start of the file.\r
1549                           \r
1550   @retval EFI_SUCCESS     Data was written.\r
1551   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..\r
1552 \r
1553 **/\r
1554 EFI_STATUS\r
1555 EFIAPI\r
1556 FileInterfaceFileGetPosition(\r
1557   IN EFI_FILE_PROTOCOL        *This,\r
1558   OUT UINT64                  *Position\r
1559   )\r
1560 {\r
1561   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);\r
1562 }\r
1563 \r
1564 /**\r
1565   Get information about a file.\r
1566 \r
1567   @param  This            Protocol instance pointer.\r
1568   @param  InformationType Type of information to return in Buffer.\r
1569   @param  BufferSize      On input size of buffer, on output amount of data in buffer.\r
1570   @param  Buffer          The buffer to return data.\r
1571 \r
1572   @retval EFI_SUCCESS          Data was returned.\r
1573   @retval EFI_UNSUPPORT        InformationType is not supported.\r
1574   @retval EFI_NO_MEDIA         The device has no media.\r
1575   @retval EFI_DEVICE_ERROR     The device reported an error.\r
1576   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1577   @retval EFI_WRITE_PROTECTED  The device is write protected.\r
1578   @retval EFI_ACCESS_DENIED    The file was open for read only.\r
1579   @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.\r
1580 \r
1581 **/\r
1582 EFI_STATUS\r
1583 EFIAPI\r
1584 FileInterfaceFileGetInfo(\r
1585   IN EFI_FILE_PROTOCOL        *This,\r
1586   IN EFI_GUID                 *InformationType,\r
1587   IN OUT UINTN                *BufferSize,\r
1588   OUT VOID                    *Buffer\r
1589   )\r
1590 {\r
1591   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);\r
1592 }\r
1593 \r
1594 /**\r
1595   Set information about a file\r
1596 \r
1597   @param  This            Protocol instance pointer.\r
1598   @param  InformationType Type of information in Buffer.\r
1599   @param  BufferSize      Size of buffer.\r
1600   @param  Buffer          The data to write.\r
1601 \r
1602   @retval EFI_SUCCESS          Data was returned.\r
1603   @retval EFI_UNSUPPORT        InformationType is not supported.\r
1604   @retval EFI_NO_MEDIA         The device has no media.\r
1605   @retval EFI_DEVICE_ERROR     The device reported an error.\r
1606   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1607   @retval EFI_WRITE_PROTECTED  The device is write protected.\r
1608   @retval EFI_ACCESS_DENIED    The file was open for read only.\r
1609 \r
1610 **/\r
1611 EFI_STATUS\r
1612 EFIAPI\r
1613 FileInterfaceFileSetInfo(\r
1614   IN EFI_FILE_PROTOCOL        *This,\r
1615   IN EFI_GUID                 *InformationType,\r
1616   IN UINTN                    BufferSize,\r
1617   IN VOID                     *Buffer\r
1618   )\r
1619 {\r
1620   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);\r
1621 }\r
1622 \r
1623 /**\r
1624   Flush data back for the file handle.\r
1625 \r
1626   @param  This Protocol instance pointer.\r
1627 \r
1628   @retval EFI_SUCCESS          Data was written.\r
1629   @retval EFI_UNSUPPORT        Writes to Open directory are not supported.\r
1630   @retval EFI_NO_MEDIA         The device has no media.\r
1631   @retval EFI_DEVICE_ERROR     The device reported an error.\r
1632   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1633   @retval EFI_WRITE_PROTECTED  The device is write protected.\r
1634   @retval EFI_ACCESS_DENIED    The file was open for read only.\r
1635   @retval EFI_VOLUME_FULL      The volume is full.\r
1636 \r
1637 **/\r
1638 EFI_STATUS\r
1639 EFIAPI\r
1640 FileInterfaceFileFlush(\r
1641   IN EFI_FILE_PROTOCOL  *This\r
1642   )\r
1643 {\r
1644   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Flush(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);\r
1645 }\r
1646 \r
1647 /**\r
1648   Read data from the file.\r
1649 \r
1650   @param  This       Protocol instance pointer.\r
1651   @param  BufferSize On input size of buffer, on output amount of data in buffer.\r
1652   @param  Buffer     The buffer in which data is read.\r
1653 \r
1654   @retval EFI_SUCCESS          Data was read.\r
1655   @retval EFI_NO_MEDIA         The device has no media.\r
1656   @retval EFI_DEVICE_ERROR     The device reported an error.\r
1657   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1658   @retval EFI_BUFFER_TO_SMALL  BufferSize is too small. BufferSize contains required size.\r
1659 \r
1660 **/\r
1661 EFI_STATUS\r
1662 EFIAPI\r
1663 FileInterfaceFileRead(\r
1664   IN EFI_FILE_PROTOCOL        *This,\r
1665   IN OUT UINTN                *BufferSize,\r
1666   OUT VOID                    *Buffer\r
1667   )\r
1668 {\r
1669   CHAR8       *AsciiBuffer;\r
1670   UINTN       Size;\r
1671   EFI_STATUS  Status;\r
1672   if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {\r
1673     //\r
1674     // Unicode\r
1675     //\r
1676     return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));\r
1677   } else {\r
1678     //\r
1679     // Ascii\r
1680     //\r
1681     AsciiBuffer = AllocateZeroPool((Size = *BufferSize));\r
1682     Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer));\r
1683     UnicodeSPrint(Buffer, *BufferSize, L"%a", AsciiBuffer);\r
1684     FreePool(AsciiBuffer);\r
1685     return (Status);\r
1686   }\r
1687 }\r
1688 \r
1689 /**\r
1690   Opens a new file relative to the source file's location.\r
1691 \r
1692   @param[in]  This       The protocol instance pointer.\r
1693   @param[out]  NewHandle Returns File Handle for FileName.\r
1694   @param[in]  FileName   Null terminated string. "\", ".", and ".." are supported.\r
1695   @param[in]  OpenMode   Open mode for file.\r
1696   @param[in]  Attributes Only used for EFI_FILE_MODE_CREATE.\r
1697 \r
1698   @retval EFI_SUCCESS          The device was opened.\r
1699   @retval EFI_NOT_FOUND        The specified file could not be found on the device.\r
1700   @retval EFI_NO_MEDIA         The device has no media.\r
1701   @retval EFI_MEDIA_CHANGED    The media has changed.\r
1702   @retval EFI_DEVICE_ERROR     The device reported an error.\r
1703   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1704   @retval EFI_ACCESS_DENIED    The service denied access to the file.\r
1705   @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.\r
1706   @retval EFI_VOLUME_FULL      The volume is full.\r
1707 **/\r
1708 EFI_STATUS\r
1709 EFIAPI\r
1710 FileInterfaceFileOpen (\r
1711   IN EFI_FILE_PROTOCOL        *This,\r
1712   OUT EFI_FILE_PROTOCOL       **NewHandle,\r
1713   IN CHAR16                   *FileName,\r
1714   IN UINT64                   OpenMode,\r
1715   IN UINT64                   Attributes\r
1716   )\r
1717 {\r
1718   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Open(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, NewHandle, FileName, OpenMode, Attributes);\r
1719 }\r
1720 \r
1721 /**\r
1722   Close and delete the file handle.\r
1723 \r
1724   @param  This                     Protocol instance pointer.\r
1725                                    \r
1726   @retval EFI_SUCCESS              The device was opened.\r
1727   @retval EFI_WARN_DELETE_FAILURE  The handle was closed but the file was not deleted.\r
1728 \r
1729 **/\r
1730 EFI_STATUS\r
1731 EFIAPI\r
1732 FileInterfaceFileDelete(\r
1733   IN EFI_FILE_PROTOCOL  *This\r
1734   )\r
1735 {\r
1736   EFI_STATUS Status;\r
1737   Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Delete(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);\r
1738   FreePool(This);\r
1739   return (Status);\r
1740 }\r
1741 \r
1742 /**\r
1743   File style interface for File (Close).\r
1744   \r
1745   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
1746   \r
1747   @retval EFI_SUCCESS   The file was closed.\r
1748 **/\r
1749 EFI_STATUS\r
1750 EFIAPI\r
1751 FileInterfaceFileClose(\r
1752   IN EFI_FILE_PROTOCOL *This\r
1753   )\r
1754 {\r
1755   EFI_STATUS Status;\r
1756   Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);\r
1757   FreePool(This);\r
1758   return (Status);\r
1759 }\r
1760 \r
1761 /**\r
1762   File style interface for File (Write).\r
1763 \r
1764   If the file was opened with ASCII mode the data will be processed through \r
1765   AsciiSPrint before writing.\r
1766   \r
1767   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
1768   @param[in, out] BufferSize   Size in bytes of Buffer.\r
1769   @param[in] Buffer            The pointer to the buffer to write.\r
1770   \r
1771   @retval EFI_SUCCESS   The data was written.\r
1772 **/\r
1773 EFI_STATUS\r
1774 EFIAPI\r
1775 FileInterfaceFileWrite(\r
1776   IN     EFI_FILE_PROTOCOL  *This,\r
1777   IN OUT UINTN              *BufferSize,\r
1778   IN     VOID               *Buffer\r
1779   )\r
1780 {\r
1781   CHAR8       *AsciiBuffer;\r
1782   UINTN       Size;\r
1783   EFI_STATUS  Status;\r
1784   if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {\r
1785     //\r
1786     // Unicode\r
1787     //\r
1788     return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));\r
1789   } else {\r
1790     //\r
1791     // Ascii\r
1792     //\r
1793     AsciiBuffer = AllocateZeroPool(*BufferSize);\r
1794     AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);\r
1795     Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator)\r
1796     Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer));\r
1797     FreePool(AsciiBuffer);\r
1798     return (Status);\r
1799   }\r
1800 }\r
1801 \r
1802 /**\r
1803   Create a file interface with unicode information.\r
1804 \r
1805   This will create a new EFI_FILE_PROTOCOL identical to the Templace\r
1806   except that the new one has Unicode and Ascii knowledge.\r
1807   \r
1808   @param[in] Template   A pointer to the EFI_FILE_PROTOCOL object.\r
1809   @param[in] Unicode    TRUE for UCS-2, FALSE for ASCII.\r
1810   \r
1811   @return a new EFI_FILE_PROTOCOL object to be used instead of the template.\r
1812 **/\r
1813 EFI_FILE_PROTOCOL*\r
1814 CreateFileInterfaceFile(\r
1815   IN CONST EFI_FILE_PROTOCOL  *Template,\r
1816   IN CONST BOOLEAN            Unicode\r
1817   )\r
1818 {\r
1819   EFI_FILE_PROTOCOL_FILE *NewOne;\r
1820 \r
1821   NewOne = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_FILE));\r
1822   if (NewOne == NULL) {\r
1823     return (NULL);\r
1824   }\r
1825   CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE));\r
1826   NewOne->Orig        = (EFI_FILE_PROTOCOL *)Template;\r
1827   NewOne->Unicode     = Unicode;\r
1828   NewOne->Open        = FileInterfaceFileOpen;\r
1829   NewOne->Close       = FileInterfaceFileClose;\r
1830   NewOne->Delete      = FileInterfaceFileDelete;\r
1831   NewOne->Read        = FileInterfaceFileRead;\r
1832   NewOne->Write       = FileInterfaceFileWrite;\r
1833   NewOne->GetPosition = FileInterfaceFileGetPosition;\r
1834   NewOne->SetPosition = FileInterfaceFileSetPosition;\r
1835   NewOne->GetInfo     = FileInterfaceFileGetInfo;\r
1836   NewOne->SetInfo     = FileInterfaceFileSetInfo;\r
1837   NewOne->Flush       = FileInterfaceFileFlush;\r
1838 \r
1839   return ((EFI_FILE_PROTOCOL *)NewOne);\r
1840 }\r