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