]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/IfrSupportLib/UefiIfrForm.c
Add IfrLibCreatePopUp2 and HiiLibExportPackageLists.
[mirror_edk2.git] / MdePkg / Library / IfrSupportLib / UefiIfrForm.c
1 /** @file
2 Utility functions which helps in opcode creation, HII configuration string manipulations,
3 pop up window creations, setup browser persistence data set and get.
4
5 Copyright (c) 2007- 2008, Intel Corporation
6 All rights reserved. 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 "UefiIfrLibraryInternal.h"
17
18 //
19 // Fake <ConfigHdr>
20 //
21 GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT16 mFakeConfigHdr[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=0";
22
23 /**
24 Draw a dialog and return the selected key.
25
26 @param NumberOfLines The number of lines for the dialog box
27 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
28 @param String Pointer to the first string in the list
29 @param ... A series of (quantity == NumberOfLines - 1) text
30 strings which will be used to construct the dialog
31 box
32
33 @retval EFI_SUCCESS Displayed dialog and received user interaction
34 @retval EFI_INVALID_PARAMETER One of the parameters was invalid.
35
36 **/
37 EFI_STATUS
38 EFIAPI
39 IfrLibCreatePopUp2 (
40 IN UINTN NumberOfLines,
41 OUT EFI_INPUT_KEY *KeyValue,
42 IN VA_LIST Marker
43 )
44 {
45 UINTN Index;
46 UINTN Count;
47 UINTN Start;
48 UINTN Top;
49 CHAR16 *StringPtr;
50 UINTN LeftColumn;
51 UINTN RightColumn;
52 UINTN TopRow;
53 UINTN BottomRow;
54 UINTN DimensionsWidth;
55 UINTN DimensionsHeight;
56 EFI_INPUT_KEY Key;
57 UINTN LargestString;
58 CHAR16 *StackString;
59 EFI_STATUS Status;
60 UINTN StringLen;
61 CHAR16 *LineBuffer;
62 CHAR16 **StringArray;
63 EFI_EVENT TimerEvent;
64 EFI_EVENT WaitList[2];
65 UINTN CurrentAttribute;
66 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
67 CHAR16 *String;
68
69 String = VA_ARG (Marker, CHAR16 *);
70
71 if ((KeyValue == NULL) || (String == NULL)) {
72 return EFI_INVALID_PARAMETER;
73 }
74
75 TopRow = 0;
76 BottomRow = 0;
77 LeftColumn = 0;
78 RightColumn = 0;
79
80 ConOut = gST->ConOut;
81 ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow);
82
83 DimensionsWidth = RightColumn - LeftColumn;
84 DimensionsHeight = BottomRow - TopRow;
85
86 CurrentAttribute = ConOut->Mode->Attribute;
87
88 LineBuffer = AllocateZeroPool (DimensionsWidth * sizeof (CHAR16));
89 ASSERT (LineBuffer != NULL);
90
91 //
92 // Determine the largest string in the dialog box
93 // Notice we are starting with 1 since String is the first string
94 //
95 StringArray = AllocateZeroPool (NumberOfLines * sizeof (CHAR16 *));
96 LargestString = StrLen (String);
97 StringArray[0] = String;
98
99 for (Index = 1; Index < NumberOfLines; Index++) {
100 StackString = VA_ARG (Marker, CHAR16 *);
101
102 if (StackString == NULL) {
103 return EFI_INVALID_PARAMETER;
104 }
105
106 StringArray[Index] = StackString;
107 StringLen = StrLen (StackString);
108 if (StringLen > LargestString) {
109 LargestString = StringLen;
110 }
111 }
112
113 if ((LargestString + 2) > DimensionsWidth) {
114 LargestString = DimensionsWidth - 2;
115 }
116
117 //
118 // Subtract the PopUp width from total Columns, allow for one space extra on
119 // each end plus a border.
120 //
121 Start = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1;
122
123 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1;
124
125 //
126 // Disable cursor
127 //
128 ConOut->EnableCursor (ConOut, FALSE);
129 ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
130
131 StringPtr = &LineBuffer[0];
132 *StringPtr++ = BOXDRAW_DOWN_RIGHT;
133 for (Index = 0; Index < LargestString; Index++) {
134 *StringPtr++ = BOXDRAW_HORIZONTAL;
135 }
136 *StringPtr++ = BOXDRAW_DOWN_LEFT;
137 *StringPtr = L'\0';
138
139 ConOut->SetCursorPosition (ConOut, Start, Top);
140 ConOut->OutputString (ConOut, LineBuffer);
141
142 for (Index = 0; Index < NumberOfLines; Index++) {
143 StringPtr = &LineBuffer[0];
144 *StringPtr++ = BOXDRAW_VERTICAL;
145
146 for (Count = 0; Count < LargestString; Count++) {
147 StringPtr[Count] = L' ';
148 }
149
150 StringLen = StrLen (StringArray[Index]);
151 if (StringLen > LargestString) {
152 StringLen = LargestString;
153 }
154 CopyMem (
155 StringPtr + ((LargestString - StringLen) / 2),
156 StringArray[Index],
157 StringLen * sizeof (CHAR16)
158 );
159 StringPtr += LargestString;
160
161 *StringPtr++ = BOXDRAW_VERTICAL;
162 *StringPtr = L'\0';
163
164 ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index);
165 ConOut->OutputString (ConOut, LineBuffer);
166 }
167
168 StringPtr = &LineBuffer[0];
169 *StringPtr++ = BOXDRAW_UP_RIGHT;
170 for (Index = 0; Index < LargestString; Index++) {
171 *StringPtr++ = BOXDRAW_HORIZONTAL;
172 }
173 *StringPtr++ = BOXDRAW_UP_LEFT;
174 *StringPtr = L'\0';
175
176 ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1);
177 ConOut->OutputString (ConOut, LineBuffer);
178
179 do {
180 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
181
182 //
183 // Set a timer event of 1 second expiration
184 //
185 gBS->SetTimer (
186 TimerEvent,
187 TimerRelative,
188 10000000
189 );
190
191 //
192 // Wait for the keystroke event or the timer
193 //
194 WaitList[0] = gST->ConIn->WaitForKey;
195 WaitList[1] = TimerEvent;
196 Status = gBS->WaitForEvent (2, WaitList, &Index);
197
198 //
199 // Check for the timer expiration
200 //
201 if (!EFI_ERROR (Status) && Index == 1) {
202 Status = EFI_TIMEOUT;
203 }
204
205 gBS->CloseEvent (TimerEvent);
206 } while (Status == EFI_TIMEOUT);
207
208 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
209 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
210
211 ConOut->SetAttribute (ConOut, CurrentAttribute);
212 ConOut->EnableCursor (ConOut, TRUE);
213
214 return Status;}
215
216
217 /**
218 Draw a dialog and return the selected key.
219
220 @param NumberOfLines The number of lines for the dialog box
221 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
222 @param String Pointer to the first string in the list
223 @param ... A series of (quantity == NumberOfLines - 1) text
224 strings which will be used to construct the dialog
225 box
226
227 @retval EFI_SUCCESS Displayed dialog and received user interaction
228 @retval EFI_INVALID_PARAMETER One of the parameters was invalid.
229
230 **/
231 EFI_STATUS
232 EFIAPI
233 IfrLibCreatePopUp (
234 IN UINTN NumberOfLines,
235 OUT EFI_INPUT_KEY *KeyValue,
236 IN CHAR16 *String,
237 ...
238 )
239 {
240 EFI_STATUS Status;
241 VA_LIST Marker;
242
243 VA_START (Marker, KeyValue);
244
245 Status = IfrLibCreatePopUp2 (NumberOfLines, KeyValue, Marker);
246
247 VA_END (Marker);
248
249 return Status;
250 }
251
252 /**
253 Swap bytes in the buffer. This is a internal function.
254
255 @param Buffer Binary buffer.
256 @param BufferSize Size of the buffer in bytes.
257
258 @return None.
259
260 **/
261 VOID
262 SwapBuffer (
263 IN OUT UINT8 *Buffer,
264 IN UINTN BufferSize
265 )
266 {
267 UINTN Index;
268 UINT8 Temp;
269 UINTN SwapCount;
270
271 SwapCount = BufferSize / 2;
272 for (Index = 0; Index < SwapCount; Index++) {
273 Temp = Buffer[Index];
274 Buffer[Index] = Buffer[BufferSize - 1 - Index];
275 Buffer[BufferSize - 1 - Index] = Temp;
276 }
277 }
278
279 /**
280 Converts the unicode character of the string from uppercase to lowercase.
281 This is a internal function.
282
283 @param Str String to be converted
284
285 **/
286 VOID
287 EFIAPI
288 ToLower (
289 IN OUT CHAR16 *Str
290 )
291 {
292 CHAR16 *Ptr;
293
294 for (Ptr = Str; *Ptr != L'\0'; Ptr++) {
295 if (*Ptr >= L'A' && *Ptr <= L'Z') {
296 *Ptr = (CHAR16) (*Ptr - L'A' + L'a');
297 }
298 }
299 }
300
301
302 /**
303 Converts binary buffer to Unicode string in reversed byte order from BufToHexString().
304
305 @param Str String for output
306 @param Buffer Binary buffer.
307 @param BufferSize Size of the buffer in bytes.
308
309 @retval EFI_SUCCESS The function completed successfully.
310
311 **/
312 EFI_STATUS
313 EFIAPI
314 BufferToHexString (
315 IN OUT CHAR16 *Str,
316 IN UINT8 *Buffer,
317 IN UINTN BufferSize
318 )
319 {
320 EFI_STATUS Status;
321 UINT8 *NewBuffer;
322 UINTN StrBufferLen;
323
324 NewBuffer = AllocateCopyPool (BufferSize, Buffer);
325 SwapBuffer (NewBuffer, BufferSize);
326
327 StrBufferLen = BufferSize * sizeof (CHAR16) + 1;
328 Status = BufToHexString (Str, &StrBufferLen, NewBuffer, BufferSize);
329
330 FreePool (NewBuffer);
331 //
332 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
333 //
334 ToLower (Str);
335
336 return Status;
337 }
338
339
340 /**
341 Converts Hex String to binary buffer in reversed byte order from HexStringToBuf().
342
343 @param Buffer Pointer to buffer that receives the data.
344 @param BufferSize Length in bytes of the buffer to hold converted
345 data. If routine return with EFI_SUCCESS,
346 containing length of converted data. If routine
347 return with EFI_BUFFER_TOO_SMALL, containg length
348 of buffer desired.
349 @param Str String to be converted from.
350
351 @retval EFI_SUCCESS The function completed successfully.
352
353 **/
354 EFI_STATUS
355 EFIAPI
356 HexStringToBuffer (
357 IN OUT UINT8 *Buffer,
358 IN OUT UINTN *BufferSize,
359 IN CHAR16 *Str
360 )
361 {
362 EFI_STATUS Status;
363 UINTN ConvertedStrLen;
364
365 ConvertedStrLen = 0;
366 Status = HexStringToBuf (Buffer, BufferSize, Str, &ConvertedStrLen);
367 if (!EFI_ERROR (Status)) {
368 SwapBuffer (Buffer, ConvertedStrLen);
369 }
370
371 return Status;
372 }
373
374 /**
375 Convert binary representation Config string (e.g. "0041004200430044") to the
376 original string (e.g. "ABCD"). Config string appears in <ConfigHdr> (i.e.
377 "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
378
379 @param UnicodeString Original Unicode string.
380 @param StrBufferLen On input: Length in bytes of buffer to hold the Unicode string.
381 Includes tailing '\0' character.
382 On output:
383 If return EFI_SUCCESS, containing length of Unicode string buffer.
384 If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
385 @param ConfigString Binary representation of Unicode String, <string> := (<HexCh>4)+
386
387 @retval EFI_SUCCESS Routine success.
388 @retval EFI_BUFFER_TOO_SMALL The string buffer is too small.
389
390 **/
391 EFI_STATUS
392 EFIAPI
393 ConfigStringToUnicode (
394 IN OUT CHAR16 *UnicodeString,
395 IN OUT UINTN *StrBufferLen,
396 IN CHAR16 *ConfigString
397 )
398 {
399 UINTN Index;
400 UINTN Len;
401 UINTN BufferSize;
402 CHAR16 BackupChar;
403
404 Len = StrLen (ConfigString) / 4;
405 BufferSize = (Len + 1) * sizeof (CHAR16);
406
407 if (*StrBufferLen < BufferSize) {
408 *StrBufferLen = BufferSize;
409 return EFI_BUFFER_TOO_SMALL;
410 }
411
412 *StrBufferLen = BufferSize;
413
414 for (Index = 0; Index < Len; Index++) {
415 BackupChar = ConfigString[4];
416 ConfigString[4] = L'\0';
417
418 HexStringToBuf ((UINT8 *) UnicodeString, &BufferSize, ConfigString, NULL);
419
420 ConfigString[4] = BackupChar;
421
422 ConfigString += 4;
423 UnicodeString += 1;
424 }
425
426 //
427 // Add tailing '\0' character
428 //
429 *UnicodeString = L'\0';
430
431 return EFI_SUCCESS;
432 }
433
434 /**
435 Convert Unicode string to binary representation Config string, e.g.
436 "ABCD" => "0041004200430044". Config string appears in <ConfigHdr> (i.e.
437 "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
438
439 @param ConfigString Binary representation of Unicode String, <string> := (<HexCh>4)+
440 @param StrBufferLen On input: Length in bytes of buffer to hold the Unicode string.
441 Includes tailing '\0' character.
442 On output:
443 If return EFI_SUCCESS, containing length of Unicode string buffer.
444 If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
445 @param UnicodeString Original Unicode string.
446
447 @retval EFI_SUCCESS Routine success.
448 @retval EFI_BUFFER_TOO_SMALL The string buffer is too small.
449
450 **/
451 EFI_STATUS
452 EFIAPI
453 UnicodeToConfigString (
454 IN OUT CHAR16 *ConfigString,
455 IN OUT UINTN *StrBufferLen,
456 IN CHAR16 *UnicodeString
457 )
458 {
459 UINTN Index;
460 UINTN Len;
461 UINTN BufferSize;
462 CHAR16 *String;
463
464 Len = StrLen (UnicodeString);
465 BufferSize = (Len * 4 + 1) * sizeof (CHAR16);
466
467 if (*StrBufferLen < BufferSize) {
468 *StrBufferLen = BufferSize;
469 return EFI_BUFFER_TOO_SMALL;
470 }
471
472 *StrBufferLen = BufferSize;
473 String = ConfigString;
474
475 for (Index = 0; Index < Len; Index++) {
476 BufToHexString (ConfigString, &BufferSize, (UINT8 *) UnicodeString, 2);
477
478 ConfigString += 4;
479 UnicodeString += 1;
480 }
481
482 //
483 // Add tailing '\0' character
484 //
485 *ConfigString = L'\0';
486
487 //
488 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
489 //
490 ToLower (String);
491 return EFI_SUCCESS;
492 }
493
494 /**
495 Construct <ConfigHdr> using routing information GUID/NAME/PATH.
496
497 @param ConfigHdr Pointer to the ConfigHdr string.
498 @param StrBufferLen On input: Length in bytes of buffer to hold the
499 ConfigHdr string. Includes tailing '\0' character.
500 On output: If return EFI_SUCCESS, containing
501 length of ConfigHdr string buffer. If return
502 EFI_BUFFER_TOO_SMALL, containg length of string
503 buffer desired.
504 @param Guid Routing information: GUID.
505 @param Name Routing information: NAME.
506 @param DriverHandle Driver handle which contains the routing
507 information: PATH.
508
509 @retval EFI_SUCCESS Routine success.
510 @retval EFI_BUFFER_TOO_SMALL The ConfigHdr string buffer is too small.
511
512 **/
513 EFI_STATUS
514 EFIAPI
515 ConstructConfigHdr (
516 IN OUT CHAR16 *ConfigHdr,
517 IN OUT UINTN *StrBufferLen,
518 IN EFI_GUID *Guid,
519 IN CHAR16 *Name, OPTIONAL
520 IN EFI_HANDLE *DriverHandle
521 )
522 {
523 EFI_STATUS Status;
524 UINTN NameStrLen;
525 UINTN DevicePathSize;
526 UINTN BufferSize;
527 CHAR16 *StrPtr;
528 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
529
530 if (Name == NULL) {
531 //
532 // There will be no "NAME" in <ConfigHdr> for Name/Value storage
533 //
534 NameStrLen = 0;
535 } else {
536 //
537 // For buffer storage
538 //
539 NameStrLen = StrLen (Name);
540 }
541
542 //
543 // Retrieve DevicePath Protocol associated with this HiiPackageList
544 //
545 Status = gBS->HandleProtocol (
546 DriverHandle,
547 &gEfiDevicePathProtocolGuid,
548 (VOID **) &DevicePath
549 );
550 if (EFI_ERROR (Status)) {
551 return Status;
552 }
553
554 DevicePathSize = GetDevicePathSize (DevicePath);
555
556 //
557 // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
558 // | 5 | 32 | 6 | NameStrLen*4 | 6 | DevicePathStrLen | 1 |
559 //
560 BufferSize = (5 + 32 + 6 + NameStrLen * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16);
561 if (*StrBufferLen < BufferSize) {
562 *StrBufferLen = BufferSize;
563 return EFI_BUFFER_TOO_SMALL;
564 }
565
566 *StrBufferLen = BufferSize;
567
568 StrPtr = ConfigHdr;
569
570 StrCpy (StrPtr, L"GUID=");
571 StrPtr += 5;
572 BufferToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID));
573 StrPtr += 32;
574
575 //
576 // Convert name string, e.g. name "ABCD" => "&NAME=0041004200430044"
577 //
578 StrCpy (StrPtr, L"&NAME=");
579 StrPtr += 6;
580 if (Name != NULL) {
581 BufferSize = (NameStrLen * 4 + 1) * sizeof (CHAR16);
582 UnicodeToConfigString (StrPtr, &BufferSize, Name);
583 StrPtr += (NameStrLen * 4);
584 }
585
586 StrCpy (StrPtr, L"&PATH=");
587 StrPtr += 6;
588 BufferToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize);
589
590 return EFI_SUCCESS;
591 }
592
593
594 /**
595 Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
596
597 @param String The string to be searched in.
598 @param Offset Offset in BlockName.
599 @param Width Width in BlockName.
600
601 @retval TRUE Block name found.
602 @retval FALSE Block name not found.
603
604 **/
605 BOOLEAN
606 EFIAPI
607 FindBlockName (
608 IN OUT CHAR16 *String,
609 UINTN Offset,
610 UINTN Width
611 )
612 {
613 EFI_STATUS Status;
614 UINTN Data;
615 UINTN BufferSize;
616 UINTN ConvertedStrLen;
617
618 while ((String = StrStr (String, L"&OFFSET=")) != NULL) {
619 //
620 // Skip '&OFFSET='
621 //
622 String = String + 8;
623
624 Data = 0;
625 BufferSize = sizeof (UINTN);
626 Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
627 if (EFI_ERROR (Status)) {
628 return FALSE;
629 }
630 String = String + ConvertedStrLen;
631
632 if (Data != Offset) {
633 continue;
634 }
635
636 if (StrnCmp (String, L"&WIDTH=", 7) != 0) {
637 return FALSE;
638 }
639 String = String + 7;
640
641 Data = 0;
642 BufferSize = sizeof (UINTN);
643 Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
644 if (EFI_ERROR (Status)) {
645 return FALSE;
646 }
647 if (Data == Width) {
648 return TRUE;
649 }
650
651 String = String + ConvertedStrLen;
652 }
653
654 return FALSE;
655 }
656
657
658 /**
659 This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
660
661 @param VariableGuid An optional field to indicate the target variable
662 GUID name to use.
663 @param VariableName An optional field to indicate the target
664 human-readable variable name.
665 @param BufferSize On input: Length in bytes of buffer to hold
666 retrived data. On output: If return
667 EFI_BUFFER_TOO_SMALL, containg length of buffer
668 desired.
669 @param Buffer Buffer to hold retrived data.
670
671 @retval EFI_SUCCESS Routine success.
672 @retval EFI_BUFFER_TOO_SMALL The intput buffer is too small.
673
674 **/
675 EFI_STATUS
676 EFIAPI
677 GetBrowserData (
678 EFI_GUID *VariableGuid, OPTIONAL
679 CHAR16 *VariableName, OPTIONAL
680 UINTN *BufferSize,
681 UINT8 *Buffer
682 )
683 {
684 EFI_STATUS Status;
685 CONST CHAR16 *ConfigHdr;
686 CHAR16 *ConfigResp;
687 CHAR16 *StringPtr;
688 UINTN HeaderLen;
689 UINTN BufferLen;
690 CHAR16 *Progress;
691 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
692 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
693
694 //
695 // Locate protocols for use
696 //
697 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
698 if (EFI_ERROR (Status)) {
699 return Status;
700 }
701
702 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
703 if (EFI_ERROR (Status)) {
704 return Status;
705 }
706
707 //
708 // Retrive formset storage data from Form Browser
709 //
710 ConfigHdr = mFakeConfigHdr;
711 HeaderLen = StrLen (ConfigHdr);
712
713 BufferLen = 0x4000;
714 ConfigResp = AllocateZeroPool (BufferLen + HeaderLen);
715
716 StringPtr = ConfigResp + HeaderLen;
717 *StringPtr = L'&';
718 StringPtr++;
719
720 Status = FormBrowser2->BrowserCallback (
721 FormBrowser2,
722 &BufferLen,
723 StringPtr,
724 TRUE,
725 VariableGuid,
726 VariableName
727 );
728 if (Status == EFI_BUFFER_TOO_SMALL) {
729 FreePool (ConfigResp);
730 ConfigResp = AllocateZeroPool (BufferLen + HeaderLen);
731
732 StringPtr = ConfigResp + HeaderLen;
733 *StringPtr = L'&';
734 StringPtr++;
735
736 Status = FormBrowser2->BrowserCallback (
737 FormBrowser2,
738 &BufferLen,
739 StringPtr,
740 TRUE,
741 VariableGuid,
742 VariableName
743 );
744 }
745 if (EFI_ERROR (Status)) {
746 FreePool (ConfigResp);
747 return Status;
748 }
749 CopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16));
750
751 //
752 // Convert <ConfigResp> to buffer data
753 //
754 Status = HiiConfigRouting->ConfigToBlock (
755 HiiConfigRouting,
756 ConfigResp,
757 Buffer,
758 BufferSize,
759 &Progress
760 );
761 FreePool (ConfigResp);
762
763 return Status;
764 }
765
766
767 /**
768 This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
769
770 @param VariableGuid An optional field to indicate the target variable
771 GUID name to use.
772 @param VariableName An optional field to indicate the target
773 human-readable variable name.
774 @param BufferSize Length in bytes of buffer to hold retrived data.
775 @param Buffer Buffer to hold retrived data.
776 @param RequestElement An optional field to specify which part of the
777 buffer data will be send back to Browser. If NULL,
778 the whole buffer of data will be committed to
779 Browser. <RequestElement> ::=
780 &OFFSET=<Number>&WIDTH=<Number>*
781
782 @retval EFI_SUCCESS Routine success.
783 @retval Other Updating Browser uncommitted data failed.
784
785 **/
786 EFI_STATUS
787 EFIAPI
788 SetBrowserData (
789 EFI_GUID *VariableGuid, OPTIONAL
790 CHAR16 *VariableName, OPTIONAL
791 UINTN BufferSize,
792 UINT8 *Buffer,
793 CHAR16 *RequestElement OPTIONAL
794 )
795 {
796 EFI_STATUS Status;
797 CONST CHAR16 *ConfigHdr;
798 CHAR16 *ConfigResp;
799 CHAR16 *StringPtr;
800 UINTN HeaderLen;
801 UINTN BufferLen;
802 CHAR16 *Progress;
803 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
804 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
805 CHAR16 BlockName[33];
806 CHAR16 *ConfigRequest;
807 CHAR16 *Request;
808
809 //
810 // Locate protocols for use
811 //
812 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
813 if (EFI_ERROR (Status)) {
814 return Status;
815 }
816
817 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
818 if (EFI_ERROR (Status)) {
819 return Status;
820 }
821
822 //
823 // Prepare <ConfigRequest>
824 //
825 ConfigHdr = mFakeConfigHdr;
826 HeaderLen = StrLen (ConfigHdr);
827
828 if (RequestElement == NULL) {
829 //
830 // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
831 //
832 BlockName[0] = L'\0';
833 StrCpy (BlockName, L"&OFFSET=0&WIDTH=");
834
835 //
836 // String lenghth of L"&OFFSET=0&WIDTH=" is 16
837 //
838 StringPtr = BlockName + 16;
839 BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16));
840 BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN));
841
842 Request = BlockName;
843 } else {
844 Request = RequestElement;
845 }
846
847 BufferLen = HeaderLen * sizeof (CHAR16) + StrSize (Request);
848 ConfigRequest = AllocateZeroPool (BufferLen);
849
850 CopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16));
851 StringPtr = ConfigRequest + HeaderLen;
852 StrCpy (StringPtr, Request);
853
854 //
855 // Convert buffer to <ConfigResp>
856 //
857 Status = HiiConfigRouting->BlockToConfig (
858 HiiConfigRouting,
859 ConfigRequest,
860 Buffer,
861 BufferSize,
862 &ConfigResp,
863 &Progress
864 );
865 if (EFI_ERROR (Status)) {
866 FreePool (ConfigResp);
867 return Status;
868 }
869
870 //
871 // Skip <ConfigHdr> and '&'
872 //
873 StringPtr = ConfigResp + HeaderLen + 1;
874
875 //
876 // Change uncommitted data in Browser
877 //
878 Status = FormBrowser2->BrowserCallback (
879 FormBrowser2,
880 &BufferSize,
881 StringPtr,
882 FALSE,
883 NULL,
884 NULL
885 );
886 FreePool (ConfigResp);
887 return Status;
888 }