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