]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/FileHandleWrappers.c
udk2010.up2.shell initial release.
[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 (c) 2009 - 2010, 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 **/
30 EFI_STATUS
31 EFIAPI
32 FileInterfaceOpenNotFound(
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 **/
50 EFI_STATUS
51 EFIAPI
52 FileInterfaceNopGeneric(
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 **/
67 EFI_STATUS
68 EFIAPI
69 FileInterfaceNopGetPosition(
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 **/
85 EFI_STATUS
86 EFIAPI
87 FileInterfaceNopSetPosition(
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 **/
105 EFI_STATUS
106 EFIAPI
107 FileInterfaceNopGetInfo(
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 **/
127 EFI_STATUS
128 EFIAPI
129 FileInterfaceNopSetInfo(
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 **/
151 EFI_STATUS
152 EFIAPI
153 FileInterfaceStdOutWrite(
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] BufferSize Ignored.
171 @param[in] Buffer Ignored.
172
173 @retval EFI_UNSUPPORTED
174 **/
175 EFI_STATUS
176 EFIAPI
177 FileInterfaceStdInWrite(
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 **/
197 EFI_STATUS
198 EFIAPI
199 FileInterfaceStdErrWrite(
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 **/
217 EFI_STATUS
218 EFIAPI
219 FileInterfaceStdOutRead(
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
236 **/
237 EFI_STATUS
238 EFIAPI
239 FileInterfaceStdErrRead(
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 Ignored.
253 @param[in] Buffer Ignored.
254
255 @retval EFI_SUCCESS
256 **/
257 EFI_STATUS
258 EFIAPI
259 FileInterfaceNulRead(
260 IN EFI_FILE_PROTOCOL *This,
261 IN OUT UINTN *BufferSize,
262 OUT VOID *Buffer
263 )
264 {
265 return (EFI_SUCCESS);
266 }
267
268 /**
269 File style interface for NUL file (Write).
270
271 @param[in] This Ignored.
272 @param[in,out] BufferSize Ignored.
273 @param[in] Buffer Ignored.
274
275 @retval EFI_SUCCESS
276 **/
277 EFI_STATUS
278 EFIAPI
279 FileInterfaceNulWrite(
280 IN EFI_FILE_PROTOCOL *This,
281 IN OUT UINTN *BufferSize,
282 IN VOID *Buffer
283 )
284 {
285 return (EFI_SUCCESS);
286 }
287
288 /**
289 File style interface for console (Read).
290
291 This will return a single line of input from the console.
292
293 @param This A pointer to the EFI_FILE_PROTOCOL instance that is the
294 file handle to read data from. Not used.
295 @param BufferSize On input, the size of the Buffer. On output, the amount
296 of data returned in Buffer. In both cases, the size is
297 measured in bytes.
298 @param Buffer The buffer into which the data is read.
299
300
301 @retval EFI_SUCCESS The data was read.
302 @retval EFI_NO_MEDIA The device has no medium.
303 @retval EFI_DEVICE_ERROR The device reported an error.
304 @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file.
305 @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file.
306 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
307 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory
308 entry. BufferSize has been updated with the size
309 needed to complete the request.
310 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
311 **/
312 EFI_STATUS
313 EFIAPI
314 FileInterfaceStdInRead(
315 IN EFI_FILE_PROTOCOL *This,
316 IN OUT UINTN *BufferSize,
317 OUT VOID *Buffer
318 )
319 {
320 CHAR16 *CurrentString;
321 BOOLEAN Done;
322 UINTN Column; // Column of current cursor
323 UINTN Row; // Row of current cursor
324 UINTN StartColumn; // Column at the beginning of the line
325 UINTN Update; // Line index for update
326 UINTN Delete; // Num of chars to delete from console after update
327 UINTN StringLen; // Total length of the line
328 UINTN StringCurPos; // Line index corresponding to the cursor
329 UINTN MaxStr; // Maximum possible line length
330 UINTN Index;
331 UINTN TotalColumn; // Num of columns in the console
332 UINTN TotalRow; // Num of rows in the console
333 UINTN SkipLength;
334 UINTN OutputLength; // Length of the update string
335 UINTN TailRow; // Row of end of line
336 UINTN TailColumn; // Column of end of line
337 EFI_INPUT_KEY Key;
338
339 BUFFER_LIST *LinePos;
340 BUFFER_LIST *NewPos;
341 BOOLEAN InScrolling;
342 EFI_STATUS Status;
343 BOOLEAN InTabScrolling; // Whether in TAB-completion state
344 EFI_SHELL_FILE_INFO *FoundFileList;
345 EFI_SHELL_FILE_INFO *TabLinePos;
346 EFI_SHELL_FILE_INFO *TempPos;
347 CHAR16 *TabStr;
348 CHAR16 *TabOutputStr;
349 BOOLEAN InQuotationMode;
350 CHAR16 *TempStr;
351 UINTN TabPos; // Start index of the string to search for TAB completion.
352 UINTN TabUpdatePos; // Start index of the string updated by TAB stroke
353 // UINTN Count;
354 UINTN EventIndex;
355 CONST CHAR16 *Cwd;
356
357 //
358 // If buffer is not large enough to hold a CHAR16, return minimum buffer size
359 //
360 if (*BufferSize < sizeof (CHAR16) * 2) {
361 *BufferSize = sizeof (CHAR16) * 2;
362 return (EFI_BUFFER_TOO_SMALL);
363 }
364
365 Done = FALSE;
366 CurrentString = Buffer;
367 StringLen = 0;
368 StringCurPos = 0;
369 OutputLength = 0;
370 Update = 0;
371 Delete = 0;
372 LinePos = NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);
373 InScrolling = FALSE;
374 InTabScrolling = FALSE;
375 Status = EFI_SUCCESS;
376 TabLinePos = NULL;
377 FoundFileList = NULL;
378 TempPos = NULL;
379 TabPos = 0;
380 TabUpdatePos = 0;
381
382 //
383 // Allocate buffers
384 //
385 TabStr = AllocateZeroPool (*BufferSize);
386 if (TabStr == NULL) {
387 return EFI_OUT_OF_RESOURCES;
388 }
389 TabOutputStr = AllocateZeroPool (*BufferSize);
390 if (TabOutputStr == NULL) {
391 FreePool(TabStr);
392 return EFI_OUT_OF_RESOURCES;
393 }
394
395 //
396 // Get the screen setting and the current cursor location
397 //
398 Column = StartColumn = gST->ConOut->Mode->CursorColumn;
399 Row = gST->ConOut->Mode->CursorRow;
400 gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &TotalColumn, &TotalRow);
401
402 //
403 // Limit the line length to the buffer size or the minimun size of the
404 // screen. (The smaller takes effect)
405 //
406 MaxStr = TotalColumn * (TotalRow - 1) - StartColumn;
407 if (MaxStr > *BufferSize / sizeof (CHAR16)) {
408 MaxStr = *BufferSize / sizeof (CHAR16);
409 }
410 ZeroMem (CurrentString, MaxStr * sizeof (CHAR16));
411 do {
412 //
413 // Read a key
414 //
415 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
416 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
417 if (EFI_ERROR (Status)) {
418 continue;
419 }
420
421 //
422 // Press PageUp or PageDown to scroll the history screen up or down.
423 // Press any other key to quit scrolling.
424 //
425 if (Key.UnicodeChar == 0 && (Key.ScanCode == SCAN_PAGE_UP || Key.ScanCode == SCAN_PAGE_DOWN)) {
426 if (Key.ScanCode == SCAN_PAGE_UP) {
427 ConsoleLoggerDisplayHistory(FALSE, 0, ShellInfoObject.ConsoleInfo);
428 } else if (Key.ScanCode == SCAN_PAGE_DOWN) {
429 ConsoleLoggerDisplayHistory(TRUE, 0, ShellInfoObject.ConsoleInfo);
430 }
431
432 InScrolling = TRUE;
433 } else {
434 if (InScrolling) {
435 ConsoleLoggerStopHistory(ShellInfoObject.ConsoleInfo);
436 InScrolling = FALSE;
437 }
438 }
439
440 //
441 // If we are quitting TAB scrolling...
442 //
443 if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) {
444 if (FoundFileList != NULL) {
445 ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FoundFileList);
446 DEBUG_CODE(FoundFileList = NULL;);
447 }
448 InTabScrolling = FALSE;
449 }
450
451 switch (Key.UnicodeChar) {
452 case CHAR_CARRIAGE_RETURN:
453 //
454 // All done, print a newline at the end of the string
455 //
456 TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn;
457 TailColumn = (StringLen - StringCurPos + Column) % TotalColumn;
458 ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n");
459 Done = TRUE;
460 break;
461
462 case CHAR_BACKSPACE:
463 if (StringCurPos != 0) {
464 //
465 // If not move back beyond string beginning, move all characters behind
466 // the current position one character forward
467 //
468 StringCurPos--;
469 Update = StringCurPos;
470 Delete = 1;
471 CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
472
473 //
474 // Adjust the current column and row
475 //
476 MoveCursorBackward (TotalColumn, &Column, &Row);
477 }
478 break;
479
480 case CHAR_TAB:
481 //
482 // handle auto complete of file and directory names...
483 //
484 if (InTabScrolling) {
485 ASSERT(FoundFileList != NULL);
486 ASSERT(TabLinePos != NULL);
487 TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link);
488 if (IsNull(&(FoundFileList->Link), &TabLinePos->Link)) {
489 TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link);
490 }
491 } else {
492 TabPos = 0;
493 TabUpdatePos = 0;
494 InQuotationMode = FALSE;
495 for (Index = 0; Index < StringLen; Index++) {
496 if (CurrentString[Index] == L'\"') {
497 InQuotationMode = (BOOLEAN)(!InQuotationMode);
498 }
499 if (CurrentString[Index] == L' ' && !InQuotationMode) {
500 TabPos = Index + 1;
501 TabUpdatePos = Index + 1;
502 }
503 if (CurrentString[Index] == L'\\') {
504 TabUpdatePos = Index + 1;
505 }
506 }
507 if (StrStr(CurrentString + TabPos, L":") == NULL) {
508 Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir(NULL);
509 if (Cwd != NULL) {
510 StrCpy(TabStr, Cwd);
511 if (TabStr[StrLen(TabStr)-1] == L'\\' && *(CurrentString + TabPos) == L'\\' ) {
512 TabStr[StrLen(TabStr)-1] = CHAR_NULL;
513 }
514 StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16));
515 } else {
516 StrCpy(TabStr, L"");
517 StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16));
518 }
519 } else {
520 StrCpy(TabStr, CurrentString + TabPos);
521 }
522 StrCat(TabStr, L"*");
523 FoundFileList = NULL;
524 // TabStr = CleanPath(TabStr);
525 Status = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FoundFileList);
526 for ( TempStr = CurrentString
527 ; *TempStr == L' '
528 ; TempStr++); // note the ';'... empty for loop
529 //
530 // make sure we have a list before we do anything more...
531 //
532 if (EFI_ERROR (Status) || FoundFileList == NULL) {
533 InTabScrolling = FALSE;
534 TabLinePos = NULL;
535 continue;
536 } else {
537 //
538 // enumerate through the list of files
539 //
540 for ( TempPos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(FoundFileList->Link))
541 ; !IsNull(&FoundFileList->Link, &TempPos->Link)
542 ; TempPos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &(TempPos->Link))
543 ){
544 //
545 // If "cd" is typed, only directory name will be auto-complete filled
546 // in either case . and .. will be removed.
547 //
548 if ((((TempStr[0] == L'c' || TempStr[0] == L'C') &&
549 (TempStr[1] == L'd' || TempStr[1] == L'D')
550 ) && ((ShellIsDirectory(TempPos->FullName) != EFI_SUCCESS)
551 ||(StrCmp(TempPos->FileName, L".") == 0)
552 ||(StrCmp(TempPos->FileName, L"..") == 0)
553 )) || ((StrCmp(TempPos->FileName, L".") == 0)
554 ||(StrCmp(TempPos->FileName, L"..") == 0))){
555 TabLinePos = TempPos;
556 TempPos = (EFI_SHELL_FILE_INFO*)(RemoveEntryList(&(TempPos->Link))->BackLink);
557 InternalFreeShellFileInfoNode(TabLinePos);
558 }
559 }
560 if (FoundFileList != NULL && !IsListEmpty(&FoundFileList->Link)) {
561 TabLinePos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FoundFileList->Link);
562 InTabScrolling = TRUE;
563 } else {
564 FreePool(FoundFileList);
565 FoundFileList = NULL;
566 }
567 }
568 }
569 break;
570
571 default:
572 if (Key.UnicodeChar >= ' ') {
573 //
574 // If we are at the buffer's end, drop the key
575 //
576 if (StringLen == MaxStr - 1 && (ShellInfoObject.ViewingSettings.InsertMode || StringCurPos == StringLen)) {
577 break;
578 }
579 //
580 // If in insert mode, make space by moving each other character 1
581 // space higher in the array
582 //
583 if (ShellInfoObject.ViewingSettings.InsertMode) {
584 CopyMem(CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof(CurrentString[0]));
585 }
586
587 CurrentString[StringCurPos] = Key.UnicodeChar;
588 Update = StringCurPos;
589
590 StringCurPos += 1;
591 OutputLength = 1;
592 }
593 break;
594
595 case 0:
596 switch (Key.ScanCode) {
597 case SCAN_DELETE:
598 //
599 // Move characters behind current position one character forward
600 //
601 if (StringLen != 0) {
602 Update = StringCurPos;
603 Delete = 1;
604 CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
605 }
606 break;
607
608 case SCAN_UP:
609 //
610 // Prepare to print the previous command
611 //
612 NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
613 if (IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link)) {
614 NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
615 }
616 break;
617
618 case SCAN_DOWN:
619 //
620 // Prepare to print the next command
621 //
622 NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
623 if (NewPos == (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
624 NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
625 }
626 break;
627
628 case SCAN_LEFT:
629 //
630 // Adjust current cursor position
631 //
632 if (StringCurPos != 0) {
633 --StringCurPos;
634 MoveCursorBackward (TotalColumn, &Column, &Row);
635 }
636 break;
637
638 case SCAN_RIGHT:
639 //
640 // Adjust current cursor position
641 //
642 if (StringCurPos < StringLen) {
643 ++StringCurPos;
644 MoveCursorForward (TotalColumn, TotalRow, &Column, &Row);
645 }
646 break;
647
648 case SCAN_HOME:
649 //
650 // Move current cursor position to the beginning of the command line
651 //
652 Row -= (StringCurPos + StartColumn) / TotalColumn;
653 Column = StartColumn;
654 StringCurPos = 0;
655 break;
656
657 case SCAN_END:
658 //
659 // Move current cursor position to the end of the command line
660 //
661 TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn;
662 TailColumn = (StringLen - StringCurPos + Column) % TotalColumn;
663 Row = TailRow;
664 Column = TailColumn;
665 StringCurPos = StringLen;
666 break;
667
668 case SCAN_ESC:
669 //
670 // Prepare to clear the current command line
671 //
672 CurrentString[0] = 0;
673 Update = 0;
674 Delete = StringLen;
675 Row -= (StringCurPos + StartColumn) / TotalColumn;
676 Column = StartColumn;
677 OutputLength = 0;
678 break;
679
680 case SCAN_INSERT:
681 //
682 // Toggle the SEnvInsertMode flag
683 //
684 ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN)!ShellInfoObject.ViewingSettings.InsertMode;
685 break;
686
687 case SCAN_F7:
688 //
689 // Print command history
690 //
691 PrintCommandHistory (TotalColumn, TotalRow, 4);
692 *CurrentString = CHAR_NULL;
693 Done = TRUE;
694 break;
695 }
696 }
697
698 if (Done) {
699 break;
700 }
701
702 //
703 // If we are in auto-complete mode, we are preparing to print
704 // the next file or directory name
705 //
706 if (InTabScrolling) {
707 //
708 // Adjust the column and row to the start of TAB-completion string.
709 //
710 Column = (StartColumn + TabUpdatePos) % TotalColumn;
711 Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;
712 OutputLength = StrLen (TabLinePos->FileName);
713 //
714 // if the output string contains blank space, quotation marks L'\"'
715 // should be added to the output.
716 //
717 if (StrStr(TabLinePos->FileName, L" ") != NULL){
718 TabOutputStr[0] = L'\"';
719 CopyMem (TabOutputStr + 1, TabLinePos->FileName, OutputLength * sizeof (CHAR16));
720 TabOutputStr[OutputLength + 1] = L'\"';
721 TabOutputStr[OutputLength + 2] = CHAR_NULL;
722 } else {
723 CopyMem (TabOutputStr, TabLinePos->FileName, OutputLength * sizeof (CHAR16));
724 TabOutputStr[OutputLength] = CHAR_NULL;
725 }
726 OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1;
727 CopyMem (CurrentString + TabUpdatePos, TabOutputStr, OutputLength * sizeof (CHAR16));
728 CurrentString[TabUpdatePos + OutputLength] = CHAR_NULL;
729 StringCurPos = TabUpdatePos + OutputLength;
730 Update = TabUpdatePos;
731 if (StringLen > TabUpdatePos + OutputLength) {
732 Delete = StringLen - TabUpdatePos - OutputLength;
733 }
734 }
735
736 //
737 // If we have a new position, we are preparing to print a previous or
738 // next command.
739 //
740 if (NewPos != (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
741 Column = StartColumn;
742 Row -= (StringCurPos + StartColumn) / TotalColumn;
743
744 LinePos = NewPos;
745 NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);
746
747 OutputLength = StrLen (LinePos->Buffer) < MaxStr - 1 ? StrLen (LinePos->Buffer) : MaxStr - 1;
748 CopyMem (CurrentString, LinePos->Buffer, OutputLength * sizeof (CHAR16));
749 CurrentString[OutputLength] = CHAR_NULL;
750
751 StringCurPos = OutputLength;
752
753 //
754 // Draw new input string
755 //
756 Update = 0;
757 if (StringLen > OutputLength) {
758 //
759 // If old string was longer, blank its tail
760 //
761 Delete = StringLen - OutputLength;
762 }
763 }
764 //
765 // If we need to update the output do so now
766 //
767 if (Update != (UINTN) -1) {
768 ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L"");
769 StringLen = StrLen (CurrentString);
770
771 if (Delete != 0) {
772 SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL);
773 }
774
775 if (StringCurPos > StringLen) {
776 StringCurPos = StringLen;
777 }
778
779 Update = (UINTN) -1;
780
781 //
782 // After using print to reflect newly updates, if we're not using
783 // BACKSPACE and DELETE, we need to move the cursor position forward,
784 // so adjust row and column here.
785 //
786 if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
787 //
788 // Calulate row and column of the tail of current string
789 //
790 TailRow = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn;
791 TailColumn = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn;
792
793 //
794 // If the tail of string reaches screen end, screen rolls up, so if
795 // Row does not equal TailRow, Row should be decremented
796 //
797 // (if we are recalling commands using UPPER and DOWN key, and if the
798 // old command is too long to fit the screen, TailColumn must be 79.
799 //
800 if (TailColumn == 0 && TailRow >= TotalRow && Row != TailRow) {
801 Row--;
802 }
803 //
804 // Calculate the cursor position after current operation. If cursor
805 // reaches line end, update both row and column, otherwise, only
806 // column will be changed.
807 //
808 if (Column + OutputLength >= TotalColumn) {
809 SkipLength = OutputLength - (TotalColumn - Column);
810
811 Row += SkipLength / TotalColumn + 1;
812 if (Row > TotalRow - 1) {
813 Row = TotalRow - 1;
814 }
815
816 Column = SkipLength % TotalColumn;
817 } else {
818 Column += OutputLength;
819 }
820 }
821
822 Delete = 0;
823 }
824 //
825 // Set the cursor position for this key
826 //
827 gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);
828 } while (!Done);
829
830 if (CurrentString != NULL && StrLen(CurrentString) > 0) {
831 //
832 // add the line to the history buffer
833 //
834 AddLineToCommandHistory(CurrentString);
835 }
836
837 FreePool (TabStr);
838 FreePool (TabOutputStr);
839 //
840 // Return the data to the caller
841 //
842 *BufferSize = StringLen * sizeof (CHAR16);
843
844 //
845 // if this was used it should be deallocated by now...
846 // prevent memory leaks...
847 //
848 ASSERT(FoundFileList == NULL);
849
850 return EFI_SUCCESS;
851 }
852
853 //
854 // FILE sytle interfaces for StdIn/StdOut/StdErr
855 //
856 EFI_FILE_PROTOCOL FileInterfaceStdIn = {
857 EFI_FILE_REVISION,
858 FileInterfaceOpenNotFound,
859 FileInterfaceNopGeneric,
860 FileInterfaceNopGeneric,
861 FileInterfaceStdInRead,
862 FileInterfaceStdInWrite,
863 FileInterfaceNopGetPosition,
864 FileInterfaceNopSetPosition,
865 FileInterfaceNopGetInfo,
866 FileInterfaceNopSetInfo,
867 FileInterfaceNopGeneric
868 };
869
870 EFI_FILE_PROTOCOL FileInterfaceStdOut = {
871 EFI_FILE_REVISION,
872 FileInterfaceOpenNotFound,
873 FileInterfaceNopGeneric,
874 FileInterfaceNopGeneric,
875 FileInterfaceStdOutRead,
876 FileInterfaceStdOutWrite,
877 FileInterfaceNopGetPosition,
878 FileInterfaceNopSetPosition,
879 FileInterfaceNopGetInfo,
880 FileInterfaceNopSetInfo,
881 FileInterfaceNopGeneric
882 };
883
884 EFI_FILE_PROTOCOL FileInterfaceStdErr = {
885 EFI_FILE_REVISION,
886 FileInterfaceOpenNotFound,
887 FileInterfaceNopGeneric,
888 FileInterfaceNopGeneric,
889 FileInterfaceStdErrRead,
890 FileInterfaceStdErrWrite,
891 FileInterfaceNopGetPosition,
892 FileInterfaceNopSetPosition,
893 FileInterfaceNopGetInfo,
894 FileInterfaceNopSetInfo,
895 FileInterfaceNopGeneric
896 };
897
898 EFI_FILE_PROTOCOL FileInterfaceNulFile = {
899 EFI_FILE_REVISION,
900 FileInterfaceOpenNotFound,
901 FileInterfaceNopGeneric,
902 FileInterfaceNopGeneric,
903 FileInterfaceNulRead,
904 FileInterfaceNulWrite,
905 FileInterfaceNopGetPosition,
906 FileInterfaceNopSetPosition,
907 FileInterfaceNopGetInfo,
908 FileInterfaceNopSetInfo,
909 FileInterfaceNopGeneric
910 };
911
912
913
914
915 //
916 // This is identical to EFI_FILE_PROTOCOL except for the additional member
917 // for the name.
918 //
919
920 typedef struct {
921 UINT64 Revision;
922 EFI_FILE_OPEN Open;
923 EFI_FILE_CLOSE Close;
924 EFI_FILE_DELETE Delete;
925 EFI_FILE_READ Read;
926 EFI_FILE_WRITE Write;
927 EFI_FILE_GET_POSITION GetPosition;
928 EFI_FILE_SET_POSITION SetPosition;
929 EFI_FILE_GET_INFO GetInfo;
930 EFI_FILE_SET_INFO SetInfo;
931 EFI_FILE_FLUSH Flush;
932 CHAR16 Name[1];
933 } EFI_FILE_PROTOCOL_ENVIRONMENT;
934 //ANSI compliance helper to get size of the struct.
935 #define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name)
936
937 /**
938 File style interface for Environment Variable (Close).
939
940 Frees the memory for this object.
941
942 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
943
944 @retval EFI_SUCCESS
945 **/
946 EFI_STATUS
947 EFIAPI
948 FileInterfaceEnvClose(
949 IN EFI_FILE_PROTOCOL *This
950 )
951 {
952 FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This);
953 return (EFI_SUCCESS);
954 }
955
956 /**
957 File style interface for Environment Variable (Delete).
958
959 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
960
961 @retval The return value from FileInterfaceEnvClose().
962 **/
963 EFI_STATUS
964 EFIAPI
965 FileInterfaceEnvDelete(
966 IN EFI_FILE_PROTOCOL *This
967 )
968 {
969 SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
970 return (FileInterfaceEnvClose(This));
971 }
972
973 /**
974 File style interface for Environment Variable (Read).
975
976 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
977 @param[in,out] BufferSize Size in bytes of Buffer.
978 @param[out] Buffer The pointer to the buffer to fill.
979
980 @retval EFI_SUCCESS The data was read.
981 **/
982 EFI_STATUS
983 EFIAPI
984 FileInterfaceEnvRead(
985 IN EFI_FILE_PROTOCOL *This,
986 IN OUT UINTN *BufferSize,
987 OUT VOID *Buffer
988 )
989 {
990 return (SHELL_GET_ENVIRONMENT_VARIABLE(
991 ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
992 BufferSize,
993 Buffer));
994 }
995
996 /**
997 File style interface for Volatile Environment Variable (Write).
998
999 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1000 @param[in,out] BufferSize Size in bytes of Buffer.
1001 @param[in] Buffer The pointer to the buffer to write.
1002
1003 @retval EFI_SUCCESS The data was read.
1004 **/
1005 EFI_STATUS
1006 EFIAPI
1007 FileInterfaceEnvVolWrite(
1008 IN EFI_FILE_PROTOCOL *This,
1009 IN OUT UINTN *BufferSize,
1010 IN VOID *Buffer
1011 )
1012 {
1013 VOID* NewBuffer;
1014 UINTN NewSize;
1015 EFI_STATUS Status;
1016
1017 NewBuffer = NULL;
1018 NewSize = 0;
1019
1020 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1021 if (Status == EFI_BUFFER_TOO_SMALL){
1022 NewBuffer = AllocateZeroPool(NewSize + *BufferSize + sizeof(CHAR16));
1023 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1024 }
1025 if (!EFI_ERROR(Status) && NewBuffer != NULL) {
1026 while (((CHAR16*)NewBuffer)[NewSize/2] == CHAR_NULL) {
1027 //
1028 // We want to overwrite the CHAR_NULL
1029 //
1030 NewSize -= 2;
1031 }
1032 CopyMem((UINT8*)NewBuffer + NewSize + 2, Buffer, *BufferSize);
1033 Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);
1034 FreePool(NewBuffer);
1035 return (Status);
1036 } else {
1037 SHELL_FREE_NON_NULL(NewBuffer);
1038 return (SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, *BufferSize, Buffer));
1039 }
1040 }
1041
1042
1043 /**
1044 File style interface for Non Volatile Environment Variable (Write).
1045
1046 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1047 @param[in,out] BufferSize Size in bytes of Buffer.
1048 @param[in] Buffer The pointer to the buffer to write.
1049
1050 @retval EFI_SUCCESS The data was read.
1051 **/
1052 EFI_STATUS
1053 EFIAPI
1054 FileInterfaceEnvNonVolWrite(
1055 IN EFI_FILE_PROTOCOL *This,
1056 IN OUT UINTN *BufferSize,
1057 IN VOID *Buffer
1058 )
1059 {
1060 VOID* NewBuffer;
1061 UINTN NewSize;
1062 EFI_STATUS Status;
1063
1064 NewBuffer = NULL;
1065 NewSize = 0;
1066
1067 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1068 if (Status == EFI_BUFFER_TOO_SMALL){
1069 NewBuffer = AllocateZeroPool(NewSize + *BufferSize);
1070 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1071 }
1072 if (!EFI_ERROR(Status)) {
1073 CopyMem((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);
1074 return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(
1075 ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1076 NewSize + *BufferSize,
1077 NewBuffer));
1078 } else {
1079 return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(
1080 ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1081 *BufferSize,
1082 Buffer));
1083 }
1084 }
1085
1086 /**
1087 Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1088 environment variables through file operations.
1089
1090 @param EnvName The name of the Environment Variable to be operated on.
1091
1092 @retval NULL Memory could not be allocated.
1093 @return other a pointer to an EFI_FILE_PROTOCOL structure
1094 **/
1095 EFI_FILE_PROTOCOL*
1096 EFIAPI
1097 CreateFileInterfaceEnv(
1098 IN CONST CHAR16 *EnvName
1099 )
1100 {
1101 EFI_FILE_PROTOCOL_ENVIRONMENT *EnvFileInterface;
1102
1103 if (EnvName == NULL) {
1104 return (NULL);
1105 }
1106
1107 //
1108 // Get some memory
1109 //
1110 EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+StrSize(EnvName));
1111 if (EnvFileInterface == NULL){
1112 return (NULL);
1113 }
1114
1115 //
1116 // Assign the generic members
1117 //
1118 EnvFileInterface->Revision = EFI_FILE_REVISION;
1119 EnvFileInterface->Open = FileInterfaceOpenNotFound;
1120 EnvFileInterface->Close = FileInterfaceEnvClose;
1121 EnvFileInterface->GetPosition = FileInterfaceNopGetPosition;
1122 EnvFileInterface->SetPosition = FileInterfaceNopSetPosition;
1123 EnvFileInterface->GetInfo = FileInterfaceNopGetInfo;
1124 EnvFileInterface->SetInfo = FileInterfaceNopSetInfo;
1125 EnvFileInterface->Flush = FileInterfaceNopGeneric;
1126 EnvFileInterface->Delete = FileInterfaceEnvDelete;
1127 EnvFileInterface->Read = FileInterfaceEnvRead;
1128
1129 StrCpy(EnvFileInterface->Name, EnvName);
1130
1131 //
1132 // Assign the different members for Volatile and Non-Volatile variables
1133 //
1134 if (IsVolatileEnv(EnvName)) {
1135 EnvFileInterface->Write = FileInterfaceEnvVolWrite;
1136 } else {
1137 EnvFileInterface->Write = FileInterfaceEnvNonVolWrite;
1138 }
1139 return ((EFI_FILE_PROTOCOL *)EnvFileInterface);
1140 }
1141
1142 /**
1143 Move the cursor position one character backward.
1144
1145 @param[in] LineLength Length of a line. Get it by calling QueryMode
1146 @param[in,out] Column Current column of the cursor position
1147 @param[in,out] Row Current row of the cursor position
1148 **/
1149 VOID
1150 EFIAPI
1151 MoveCursorBackward (
1152 IN UINTN LineLength,
1153 IN OUT UINTN *Column,
1154 IN OUT UINTN *Row
1155 )
1156 {
1157 //
1158 // If current column is 0, move to the last column of the previous line,
1159 // otherwise, just decrement column.
1160 //
1161 if (*Column == 0) {
1162 *Column = LineLength - 1;
1163 if (*Row > 0) {
1164 (*Row)--;
1165 }
1166 return;
1167 }
1168 (*Column)--;
1169 }
1170
1171 /**
1172 Move the cursor position one character forward.
1173
1174 @param[in] LineLength Length of a line.
1175 @param[in] TotalRow Total row of a screen
1176 @param[in,out] Column Current column of the cursor position
1177 @param[in,out] Row Current row of the cursor position
1178 **/
1179 VOID
1180 EFIAPI
1181 MoveCursorForward (
1182 IN UINTN LineLength,
1183 IN UINTN TotalRow,
1184 IN OUT UINTN *Column,
1185 IN OUT UINTN *Row
1186 )
1187 {
1188 //
1189 // Increment Column.
1190 // If this puts column past the end of the line, move to first column
1191 // of the next row.
1192 //
1193 (*Column)++;
1194 if (*Column >= LineLength) {
1195 (*Column) = 0;
1196 if ((*Row) < TotalRow - 1) {
1197 (*Row)++;
1198 }
1199 }
1200 }
1201
1202 /**
1203 Prints out each previously typed command in the command list history log.
1204
1205 When each screen is full it will pause for a key before continuing.
1206
1207 @param[in] TotalCols How many columns are on the screen
1208 @param[in] TotalRows How many rows are on the screen
1209 @param[in] StartColumn which column to start at
1210 **/
1211 VOID
1212 EFIAPI
1213 PrintCommandHistory (
1214 IN CONST UINTN TotalCols,
1215 IN CONST UINTN TotalRows,
1216 IN CONST UINTN StartColumn
1217 )
1218 {
1219 BUFFER_LIST *Node;
1220 UINTN Index;
1221 UINTN LineNumber;
1222 UINTN LineCount;
1223
1224 ShellPrintEx (-1, -1, L"\n");
1225 Index = 0;
1226 LineNumber = 0;
1227 //
1228 // go through history list...
1229 //
1230 for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link)
1231 ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)
1232 ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)
1233 ){
1234 Index++;
1235 LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1;
1236
1237 if (LineNumber + LineCount >= TotalRows) {
1238 ShellPromptForResponseHii(
1239 ShellPromptResponseTypeEnterContinue,
1240 STRING_TOKEN (STR_SHELL_ENTER_TO_CONT),
1241 ShellInfoObject.HiiHandle,
1242 NULL
1243 );
1244 LineNumber = 0;
1245 }
1246 ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer);
1247 LineNumber += LineCount;
1248 }
1249 }
1250
1251
1252
1253
1254
1255
1256 //
1257 // This is identical to EFI_FILE_PROTOCOL except for the additional members
1258 // for the buffer, size, and position.
1259 //
1260
1261 typedef struct {
1262 UINT64 Revision;
1263 EFI_FILE_OPEN Open;
1264 EFI_FILE_CLOSE Close;
1265 EFI_FILE_DELETE Delete;
1266 EFI_FILE_READ Read;
1267 EFI_FILE_WRITE Write;
1268 EFI_FILE_GET_POSITION GetPosition;
1269 EFI_FILE_SET_POSITION SetPosition;
1270 EFI_FILE_GET_INFO GetInfo;
1271 EFI_FILE_SET_INFO SetInfo;
1272 EFI_FILE_FLUSH Flush;
1273 VOID *Buffer;
1274 UINT64 Position;
1275 UINT64 BufferSize;
1276 BOOLEAN Unicode;
1277 } EFI_FILE_PROTOCOL_MEM;
1278
1279 /**
1280 File style interface for Mem (SetPosition).
1281
1282 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1283 @param[out] Position The position to set.
1284
1285 @retval EFI_SUCCESS The position was successfully changed.
1286 @retval EFI_INVALID_PARAMETER The Position was invalid.
1287 **/
1288 EFI_STATUS
1289 EFIAPI
1290 FileInterfaceMemSetPosition(
1291 IN EFI_FILE_PROTOCOL *This,
1292 OUT UINT64 Position
1293 )
1294 {
1295 if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) {
1296 ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position;
1297 return (EFI_SUCCESS);
1298 } else {
1299 return (EFI_INVALID_PARAMETER);
1300 }
1301 }
1302
1303 /**
1304 File style interface for Mem (GetPosition).
1305
1306 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1307 @param[out] Position The pointer to the position.
1308
1309 @retval EFI_SUCCESS The position was retrieved.
1310 **/
1311 EFI_STATUS
1312 EFIAPI
1313 FileInterfaceMemGetPosition(
1314 IN EFI_FILE_PROTOCOL *This,
1315 OUT UINT64 *Position
1316 )
1317 {
1318 *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position;
1319 return (EFI_SUCCESS);
1320 }
1321
1322 /**
1323 File style interface for Mem (Write).
1324
1325 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1326 @param[in,out] BufferSize Size in bytes of Buffer.
1327 @param[in] Buffer The pointer to the buffer to write.
1328
1329 @retval EFI_SUCCESS The data was written.
1330 **/
1331 EFI_STATUS
1332 EFIAPI
1333 FileInterfaceMemWrite(
1334 IN EFI_FILE_PROTOCOL *This,
1335 IN OUT UINTN *BufferSize,
1336 IN VOID *Buffer
1337 )
1338 {
1339 CHAR8 *AsciiBuffer;
1340 if (((EFI_FILE_PROTOCOL_MEM*)This)->Unicode) {
1341 //
1342 // Unicode
1343 //
1344 if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) {
1345 ((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);
1346 ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += (*BufferSize) + 10;
1347 }
1348 CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, Buffer, *BufferSize);
1349 ((EFI_FILE_PROTOCOL_MEM*)This)->Position += (*BufferSize);
1350 return (EFI_SUCCESS);
1351 } else {
1352 //
1353 // Ascii
1354 //
1355 AsciiBuffer = AllocatePool(*BufferSize);
1356 AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);
1357 if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) {
1358 ((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);
1359 ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += AsciiStrSize(AsciiBuffer) + 10;
1360 }
1361 CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer));
1362 ((EFI_FILE_PROTOCOL_MEM*)This)->Position += AsciiStrSize(AsciiBuffer);
1363 FreePool(AsciiBuffer);
1364 return (EFI_SUCCESS);
1365 }
1366 }
1367
1368 /**
1369 File style interface for Mem (Read).
1370
1371 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1372 @param[in,out] BufferSize Size in bytes of Buffer.
1373 @param[in] Buffer The pointer to the buffer to fill.
1374
1375 @retval EFI_SUCCESS The data was read.
1376 **/
1377 EFI_STATUS
1378 EFIAPI
1379 FileInterfaceMemRead(
1380 IN EFI_FILE_PROTOCOL *This,
1381 IN OUT UINTN *BufferSize,
1382 IN VOID *Buffer
1383 )
1384 {
1385 if (*BufferSize > (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position))) {
1386 (*BufferSize) = (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position));
1387 }
1388 CopyMem(Buffer, ((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, (*BufferSize));
1389 ((EFI_FILE_PROTOCOL_MEM*)This)->Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize);
1390 return (EFI_SUCCESS);
1391 }
1392
1393 /**
1394 File style interface for Mem (Close).
1395
1396 Frees all memory associated with this object.
1397
1398 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1399
1400 @retval EFI_SUCCESS The 'file' was closed.
1401 **/
1402 EFI_STATUS
1403 EFIAPI
1404 FileInterfaceMemClose(
1405 IN EFI_FILE_PROTOCOL *This
1406 )
1407 {
1408 SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);
1409 SHELL_FREE_NON_NULL((EFI_FILE_PROTOCOL_MEM*)This);
1410 return (EFI_SUCCESS);
1411 }
1412
1413 /**
1414 Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1415 a file entirely in memory through file operations.
1416
1417 @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii.
1418
1419 @retval NULL Memory could not be allocated.
1420 @return other A pointer to an EFI_FILE_PROTOCOL structure.
1421 **/
1422 EFI_FILE_PROTOCOL*
1423 EFIAPI
1424 CreateFileInterfaceMem(
1425 IN CONST BOOLEAN Unicode
1426 )
1427 {
1428 EFI_FILE_PROTOCOL_MEM *FileInterface;
1429
1430 //
1431 // Get some memory
1432 //
1433 FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM));
1434 if (FileInterface == NULL){
1435 return (NULL);
1436 }
1437
1438 //
1439 // Assign the generic members
1440 //
1441 FileInterface->Revision = EFI_FILE_REVISION;
1442 FileInterface->Open = FileInterfaceOpenNotFound;
1443 FileInterface->Close = FileInterfaceMemClose;
1444 FileInterface->GetPosition = FileInterfaceMemGetPosition;
1445 FileInterface->SetPosition = FileInterfaceMemSetPosition;
1446 FileInterface->GetInfo = FileInterfaceNopGetInfo;
1447 FileInterface->SetInfo = FileInterfaceNopSetInfo;
1448 FileInterface->Flush = FileInterfaceNopGeneric;
1449 FileInterface->Delete = FileInterfaceNopGeneric;
1450 FileInterface->Read = FileInterfaceMemRead;
1451 FileInterface->Write = FileInterfaceMemWrite;
1452 FileInterface->Unicode = Unicode;
1453
1454 ASSERT(FileInterface->Buffer == NULL);
1455 ASSERT(FileInterface->BufferSize == 0);
1456 ASSERT(FileInterface->Position == 0);
1457
1458 return ((EFI_FILE_PROTOCOL *)FileInterface);
1459 }
1460
1461 typedef struct {
1462 UINT64 Revision;
1463 EFI_FILE_OPEN Open;
1464 EFI_FILE_CLOSE Close;
1465 EFI_FILE_DELETE Delete;
1466 EFI_FILE_READ Read;
1467 EFI_FILE_WRITE Write;
1468 EFI_FILE_GET_POSITION GetPosition;
1469 EFI_FILE_SET_POSITION SetPosition;
1470 EFI_FILE_GET_INFO GetInfo;
1471 EFI_FILE_SET_INFO SetInfo;
1472 EFI_FILE_FLUSH Flush;
1473 BOOLEAN Unicode;
1474 EFI_FILE_PROTOCOL *Orig;
1475 } EFI_FILE_PROTOCOL_FILE;
1476
1477 /**
1478 File style interface for File (Close).
1479
1480 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1481
1482 @retval EFI_SUCCESS The file was closed.
1483 **/
1484 EFI_STATUS
1485 EFIAPI
1486 FileInterfaceFileClose(
1487 IN EFI_FILE_PROTOCOL *This
1488 )
1489 {
1490 ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
1491 FreePool(This);
1492 return (EFI_SUCCESS);
1493 }
1494
1495 /**
1496 File style interface for File (Write).
1497
1498 If the file was opened with ASCII mode the data will be processed through
1499 AsciiSPrint before writing.
1500
1501 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1502 @param[in] BufferSize Size in bytes of Buffer.
1503 @param[in] Buffer The pointer to the buffer to write.
1504
1505 @retval EFI_SUCCESS The data was written.
1506 **/
1507 EFI_STATUS
1508 EFIAPI
1509 FileInterfaceFileWrite(
1510 IN EFI_FILE_PROTOCOL *This,
1511 IN OUT UINTN *BufferSize,
1512 IN VOID *Buffer
1513 )
1514 {
1515 CHAR8 *AsciiBuffer;
1516 UINTN Size;
1517 EFI_STATUS Status;
1518 if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {
1519 //
1520 // Unicode
1521 //
1522 return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));
1523 } else {
1524 //
1525 // Ascii
1526 //
1527 AsciiBuffer = AllocatePool(*BufferSize);
1528 AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);
1529 Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator)
1530 Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer));
1531 FreePool(AsciiBuffer);
1532 return (Status);
1533 }
1534 }
1535
1536 /**
1537 Create a file interface with unicode information.
1538
1539 This will create a new EFI_FILE_PROTOCOL identical to the Templace
1540 except that the new one has Unicode and Ascii knowledge.
1541
1542 @param[in] Template A pointer to the EFI_FILE_PROTOCOL object.
1543 @param[in] Unicode TRUE for UCS-2, FALSE for ASCII.
1544
1545 @return a new EFI_FILE_PROTOCOL object to be used instead of the template.
1546 **/
1547 EFI_FILE_PROTOCOL*
1548 CreateFileInterfaceFile(
1549 IN CONST EFI_FILE_PROTOCOL *Template,
1550 IN CONST BOOLEAN Unicode
1551 )
1552 {
1553 EFI_FILE_PROTOCOL_FILE *NewOne;
1554
1555 NewOne = AllocatePool(sizeof(EFI_FILE_PROTOCOL_FILE));
1556 CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE));
1557 NewOne->Orig = (EFI_FILE_PROTOCOL *)Template;
1558 NewOne->Unicode = Unicode;
1559 NewOne->Close = FileInterfaceFileClose;
1560 NewOne->Write = FileInterfaceFileWrite;
1561
1562 return ((EFI_FILE_PROTOCOL *)NewOne);
1563 }