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