2 Utility functions which helps in opcode creation, HII configuration string manipulations,
3 pop up window creations, setup browser persistence data set and get.
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
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.
16 #include "UefiIfrLibraryInternal.h"
21 UINT16 mFakeConfigHdr
[] = L
"GUID=00000000000000000000000000000000&NAME=0000&PATH=0";
24 Draw a dialog and return the selected key.
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) text
30 strings which will be used to construct the dialog
33 @retval EFI_SUCCESS Displayed dialog and received user interaction
34 @retval EFI_INVALID_PARAMETER One of the parameters was invalid.
40 IN UINTN NumberOfLines
,
41 OUT EFI_INPUT_KEY
*KeyValue
,
55 UINTN DimensionsWidth
;
56 UINTN DimensionsHeight
;
66 EFI_EVENT WaitList
[2];
67 UINTN CurrentAttribute
;
68 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*ConOut
;
70 if ((KeyValue
== NULL
) || (String
== NULL
)) {
71 return EFI_INVALID_PARAMETER
;
80 ConOut
->QueryMode (ConOut
, ConOut
->Mode
->Mode
, &RightColumn
, &BottomRow
);
82 DimensionsWidth
= RightColumn
- LeftColumn
;
83 DimensionsHeight
= BottomRow
- TopRow
;
85 CurrentAttribute
= ConOut
->Mode
->Attribute
;
87 LineBuffer
= AllocateZeroPool (DimensionsWidth
* sizeof (CHAR16
));
88 ASSERT (LineBuffer
!= NULL
);
91 // Determine the largest string in the dialog box
92 // Notice we are starting with 1 since String is the first string
94 StringArray
= AllocateZeroPool (NumberOfLines
* sizeof (CHAR16
*));
95 LargestString
= StrLen (String
);
96 StringArray
[0] = String
;
98 VA_START (Marker
, String
);
99 for (Index
= 1; Index
< NumberOfLines
; Index
++) {
100 StackString
= VA_ARG (Marker
, CHAR16
*);
102 if (StackString
== NULL
) {
103 return EFI_INVALID_PARAMETER
;
106 StringArray
[Index
] = StackString
;
107 StringLen
= StrLen (StackString
);
108 if (StringLen
> LargestString
) {
109 LargestString
= StringLen
;
113 if ((LargestString
+ 2) > DimensionsWidth
) {
114 LargestString
= DimensionsWidth
- 2;
118 // Subtract the PopUp width from total Columns, allow for one space extra on
119 // each end plus a border.
121 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + LeftColumn
+ 1;
123 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + TopRow
- 1;
128 ConOut
->EnableCursor (ConOut
, FALSE
);
129 ConOut
->SetAttribute (ConOut
, EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
);
131 StringPtr
= &LineBuffer
[0];
132 *StringPtr
++ = BOXDRAW_DOWN_RIGHT
;
133 for (Index
= 0; Index
< LargestString
; Index
++) {
134 *StringPtr
++ = BOXDRAW_HORIZONTAL
;
136 *StringPtr
++ = BOXDRAW_DOWN_LEFT
;
139 ConOut
->SetCursorPosition (ConOut
, Start
, Top
);
140 ConOut
->OutputString (ConOut
, LineBuffer
);
142 for (Index
= 0; Index
< NumberOfLines
; Index
++) {
143 StringPtr
= &LineBuffer
[0];
144 *StringPtr
++ = BOXDRAW_VERTICAL
;
146 for (Count
= 0; Count
< LargestString
; Count
++) {
147 StringPtr
[Count
] = L
' ';
150 StringLen
= StrLen (StringArray
[Index
]);
151 if (StringLen
> LargestString
) {
152 StringLen
= LargestString
;
155 StringPtr
+ ((LargestString
- StringLen
) / 2),
157 StringLen
* sizeof (CHAR16
)
159 StringPtr
+= LargestString
;
161 *StringPtr
++ = BOXDRAW_VERTICAL
;
164 ConOut
->SetCursorPosition (ConOut
, Start
, Top
+ 1 + Index
);
165 ConOut
->OutputString (ConOut
, LineBuffer
);
168 StringPtr
= &LineBuffer
[0];
169 *StringPtr
++ = BOXDRAW_UP_RIGHT
;
170 for (Index
= 0; Index
< LargestString
; Index
++) {
171 *StringPtr
++ = BOXDRAW_HORIZONTAL
;
173 *StringPtr
++ = BOXDRAW_UP_LEFT
;
176 ConOut
->SetCursorPosition (ConOut
, Start
, Top
+ NumberOfLines
+ 1);
177 ConOut
->OutputString (ConOut
, LineBuffer
);
180 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
183 // Set a timer event of 1 second expiration
192 // Wait for the keystroke event or the timer
194 WaitList
[0] = gST
->ConIn
->WaitForKey
;
195 WaitList
[1] = TimerEvent
;
196 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
199 // Check for the timer expiration
201 if (!EFI_ERROR (Status
) && Index
== 1) {
202 Status
= EFI_TIMEOUT
;
205 gBS
->CloseEvent (TimerEvent
);
206 } while (Status
== EFI_TIMEOUT
);
208 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
209 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
211 ConOut
->SetAttribute (ConOut
, CurrentAttribute
);
212 ConOut
->EnableCursor (ConOut
, TRUE
);
219 Swap bytes in the buffer. This is a internal function.
221 @param Buffer Binary buffer.
222 @param BufferSize Size of the buffer in bytes.
229 IN OUT UINT8
*Buffer
,
237 SwapCount
= BufferSize
/ 2;
238 for (Index
= 0; Index
< SwapCount
; Index
++) {
239 Temp
= Buffer
[Index
];
240 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
241 Buffer
[BufferSize
- 1 - Index
] = Temp
;
246 Converts the unicode character of the string from uppercase to lowercase.
247 This is a internal function.
249 @param Str String to be converted
259 for (Ptr
= Str
; *Ptr
!= L
'\0'; Ptr
++) {
260 if (*Ptr
>= L
'A' && *Ptr
<= L
'Z') {
261 *Ptr
= (CHAR16
) (*Ptr
- L
'A' + L
'a');
268 Converts binary buffer to Unicode string in reversed byte order from BufToHexString().
270 @param Str String for output
271 @param Buffer Binary buffer.
272 @param BufferSize Size of the buffer in bytes.
274 @retval EFI_SUCCESS The function completed successfully.
289 NewBuffer
= AllocateCopyPool (BufferSize
, Buffer
);
290 SwapBuffer (NewBuffer
, BufferSize
);
292 StrBufferLen
= BufferSize
* sizeof (CHAR16
) + 1;
293 Status
= BufToHexString (Str
, &StrBufferLen
, NewBuffer
, BufferSize
);
295 gBS
->FreePool (NewBuffer
);
297 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
306 Converts Hex String to binary buffer in reversed byte order from HexStringToBuf().
308 @param Buffer Pointer to buffer that receives the data.
309 @param BufferSize Length in bytes of the buffer to hold converted
310 data. If routine return with EFI_SUCCESS,
311 containing length of converted data. If routine
312 return with EFI_BUFFER_TOO_SMALL, containg length
314 @param Str String to be converted from.
316 @retval EFI_SUCCESS The function completed successfully.
322 IN OUT UINT8
*Buffer
,
323 IN OUT UINTN
*BufferSize
,
328 UINTN ConvertedStrLen
;
331 Status
= HexStringToBuf (Buffer
, BufferSize
, Str
, &ConvertedStrLen
);
332 if (!EFI_ERROR (Status
)) {
333 SwapBuffer (Buffer
, ConvertedStrLen
);
340 Convert binary representation Config string (e.g. "0041004200430044") to the
341 original string (e.g. "ABCD"). Config string appears in <ConfigHdr> (i.e.
342 "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
344 @param UnicodeString Original Unicode string.
345 @param StrBufferLen On input: Length in bytes of buffer to hold the Unicode string.
346 Includes tailing '\0' character.
348 If return EFI_SUCCESS, containing length of Unicode string buffer.
349 If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
350 @param ConfigString Binary representation of Unicode String, <string> := (<HexCh>4)+
352 @retval EFI_SUCCESS Routine success.
353 @retval EFI_BUFFER_TOO_SMALL The string buffer is too small.
357 ConfigStringToUnicode (
358 IN OUT CHAR16
*UnicodeString
,
359 IN OUT UINTN
*StrBufferLen
,
360 IN CHAR16
*ConfigString
368 Len
= StrLen (ConfigString
) / 4;
369 BufferSize
= (Len
+ 1) * sizeof (CHAR16
);
371 if (*StrBufferLen
< BufferSize
) {
372 *StrBufferLen
= BufferSize
;
373 return EFI_BUFFER_TOO_SMALL
;
376 *StrBufferLen
= BufferSize
;
378 for (Index
= 0; Index
< Len
; Index
++) {
379 BackupChar
= ConfigString
[4];
380 ConfigString
[4] = L
'\0';
382 HexStringToBuf ((UINT8
*) UnicodeString
, &BufferSize
, ConfigString
, NULL
);
384 ConfigString
[4] = BackupChar
;
391 // Add tailing '\0' character
393 *UnicodeString
= L
'\0';
399 Convert Unicode string to binary representation Config string, e.g.
400 "ABCD" => "0041004200430044". Config string appears in <ConfigHdr> (i.e.
401 "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
403 @param ConfigString Binary representation of Unicode String, <string> := (<HexCh>4)+
404 @param StrBufferLen On input: Length in bytes of buffer to hold the Unicode string.
405 Includes tailing '\0' character.
407 If return EFI_SUCCESS, containing length of Unicode string buffer.
408 If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
409 @param UnicodeString Original Unicode string.
411 @retval EFI_SUCCESS Routine success.
412 @retval EFI_BUFFER_TOO_SMALL The string buffer is too small.
416 UnicodeToConfigString (
417 IN OUT CHAR16
*ConfigString
,
418 IN OUT UINTN
*StrBufferLen
,
419 IN CHAR16
*UnicodeString
427 Len
= StrLen (UnicodeString
);
428 BufferSize
= (Len
* 4 + 1) * sizeof (CHAR16
);
430 if (*StrBufferLen
< BufferSize
) {
431 *StrBufferLen
= BufferSize
;
432 return EFI_BUFFER_TOO_SMALL
;
435 *StrBufferLen
= BufferSize
;
436 String
= ConfigString
;
438 for (Index
= 0; Index
< Len
; Index
++) {
439 BufToHexString (ConfigString
, &BufferSize
, (UINT8
*) UnicodeString
, 2);
446 // Add tailing '\0' character
448 *ConfigString
= L
'\0';
451 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
458 Construct <ConfigHdr> using routing information GUID/NAME/PATH.
460 @param ConfigHdr Pointer to the ConfigHdr string.
461 @param StrBufferLen On input: Length in bytes of buffer to hold the
462 ConfigHdr string. Includes tailing '\0' character.
463 On output: If return EFI_SUCCESS, containing
464 length of ConfigHdr string buffer. If return
465 EFI_BUFFER_TOO_SMALL, containg length of string
467 @param Guid Routing information: GUID.
468 @param Name Routing information: NAME.
469 @param DriverHandle Driver handle which contains the routing
472 @retval EFI_SUCCESS Routine success.
473 @retval EFI_BUFFER_TOO_SMALL The ConfigHdr string buffer is too small.
479 IN OUT CHAR16
*ConfigHdr
,
480 IN OUT UINTN
*StrBufferLen
,
482 IN CHAR16
*Name
, OPTIONAL
483 IN EFI_HANDLE
*DriverHandle
488 UINTN DevicePathSize
;
491 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
495 // There will be no "NAME" in <ConfigHdr> for Name/Value storage
500 // For buffer storage
502 NameStrLen
= StrLen (Name
);
506 // Retrieve DevicePath Protocol associated with this HiiPackageList
508 Status
= gBS
->HandleProtocol (
510 &gEfiDevicePathProtocolGuid
,
511 (VOID
**) &DevicePath
513 if (EFI_ERROR (Status
)) {
517 DevicePathSize
= GetDevicePathSize (DevicePath
);
520 // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
521 // | 5 | 32 | 6 | NameStrLen*4 | 6 | DevicePathStrLen | 1 |
523 BufferSize
= (5 + 32 + 6 + NameStrLen
* 4 + 6 + DevicePathSize
* 2 + 1) * sizeof (CHAR16
);
524 if (*StrBufferLen
< BufferSize
) {
525 *StrBufferLen
= BufferSize
;
526 return EFI_BUFFER_TOO_SMALL
;
529 *StrBufferLen
= BufferSize
;
533 StrCpy (StrPtr
, L
"GUID=");
535 BufferToHexString (StrPtr
, (UINT8
*) Guid
, sizeof (EFI_GUID
));
539 // Convert name string, e.g. name "ABCD" => "&NAME=0041004200430044"
541 StrCpy (StrPtr
, L
"&NAME=");
544 BufferSize
= (NameStrLen
* 4 + 1) * sizeof (CHAR16
);
545 UnicodeToConfigString (StrPtr
, &BufferSize
, Name
);
546 StrPtr
+= (NameStrLen
* 4);
549 StrCpy (StrPtr
, L
"&PATH=");
551 BufferToHexString (StrPtr
, (UINT8
*) DevicePath
, DevicePathSize
);
558 Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
560 @param String The string to be searched in.
561 @param Offset Offset in BlockName.
562 @param Width Width in BlockName.
564 @retval TRUE Block name found.
565 @retval FALSE Block name not found.
570 IN OUT CHAR16
*String
,
578 UINTN ConvertedStrLen
;
580 while ((String
= StrStr (String
, L
"&OFFSET=")) != NULL
) {
587 BufferSize
= sizeof (UINTN
);
588 Status
= HexStringToBuf ((UINT8
*) &Data
, &BufferSize
, String
, &ConvertedStrLen
);
589 if (EFI_ERROR (Status
)) {
592 String
= String
+ ConvertedStrLen
;
594 if (Data
!= Offset
) {
598 if (StrnCmp (String
, L
"&WIDTH=", 7) != 0) {
604 BufferSize
= sizeof (UINTN
);
605 Status
= HexStringToBuf ((UINT8
*) &Data
, &BufferSize
, String
, &ConvertedStrLen
);
606 if (EFI_ERROR (Status
)) {
613 String
= String
+ ConvertedStrLen
;
621 This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
623 @param VariableGuid An optional field to indicate the target variable
625 @param VariableName An optional field to indicate the target
626 human-readable variable name.
627 @param BufferSize On input: Length in bytes of buffer to hold
628 retrived data. On output: If return
629 EFI_BUFFER_TOO_SMALL, containg length of buffer
631 @param Buffer Buffer to hold retrived data.
633 @retval EFI_SUCCESS Routine success.
634 @retval EFI_BUFFER_TOO_SMALL The intput buffer is too small.
640 EFI_GUID
*VariableGuid
, OPTIONAL
641 CHAR16
*VariableName
, OPTIONAL
653 EFI_FORM_BROWSER2_PROTOCOL
*FormBrowser2
;
654 EFI_HII_CONFIG_ROUTING_PROTOCOL
*HiiConfigRouting
;
657 // Locate protocols for use
659 Status
= gBS
->LocateProtocol (&gEfiFormBrowser2ProtocolGuid
, NULL
, (VOID
**) &FormBrowser2
);
660 if (EFI_ERROR (Status
)) {
664 Status
= gBS
->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid
, NULL
, (VOID
**) &HiiConfigRouting
);
665 if (EFI_ERROR (Status
)) {
670 // Retrive formset storage data from Form Browser
672 ConfigHdr
= mFakeConfigHdr
;
673 HeaderLen
= StrLen (ConfigHdr
);
676 ConfigResp
= AllocateZeroPool (BufferLen
+ HeaderLen
);
678 StringPtr
= ConfigResp
+ HeaderLen
;
682 Status
= FormBrowser2
->BrowserCallback (
690 if (Status
== EFI_BUFFER_TOO_SMALL
) {
691 gBS
->FreePool (ConfigResp
);
692 ConfigResp
= AllocateZeroPool (BufferLen
+ HeaderLen
);
694 StringPtr
= ConfigResp
+ HeaderLen
;
698 Status
= FormBrowser2
->BrowserCallback (
707 if (EFI_ERROR (Status
)) {
708 gBS
->FreePool (ConfigResp
);
711 CopyMem (ConfigResp
, ConfigHdr
, HeaderLen
* sizeof (UINT16
));
714 // Convert <ConfigResp> to buffer data
716 Status
= HiiConfigRouting
->ConfigToBlock (
723 gBS
->FreePool (ConfigResp
);
730 This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
732 @param VariableGuid An optional field to indicate the target variable
734 @param VariableName An optional field to indicate the target
735 human-readable variable name.
736 @param BufferSize Length in bytes of buffer to hold retrived data.
737 @param Buffer Buffer to hold retrived data.
738 @param RequestElement An optional field to specify which part of the
739 buffer data will be send back to Browser. If NULL,
740 the whole buffer of data will be committed to
741 Browser. <RequestElement> ::=
742 &OFFSET=<Number>&WIDTH=<Number>*
744 @retval EFI_SUCCESS Routine success.
745 @retval Other Updating Browser uncommitted data failed.
751 EFI_GUID
*VariableGuid
, OPTIONAL
752 CHAR16
*VariableName
, OPTIONAL
755 CHAR16
*RequestElement OPTIONAL
765 EFI_FORM_BROWSER2_PROTOCOL
*FormBrowser2
;
766 EFI_HII_CONFIG_ROUTING_PROTOCOL
*HiiConfigRouting
;
767 CHAR16 BlockName
[33];
768 CHAR16
*ConfigRequest
;
772 // Locate protocols for use
774 Status
= gBS
->LocateProtocol (&gEfiFormBrowser2ProtocolGuid
, NULL
, (VOID
**) &FormBrowser2
);
775 if (EFI_ERROR (Status
)) {
779 Status
= gBS
->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid
, NULL
, (VOID
**) &HiiConfigRouting
);
780 if (EFI_ERROR (Status
)) {
785 // Prepare <ConfigRequest>
787 ConfigHdr
= mFakeConfigHdr
;
788 HeaderLen
= StrLen (ConfigHdr
);
790 if (RequestElement
== NULL
) {
792 // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
794 BlockName
[0] = L
'\0';
795 StrCpy (BlockName
, L
"&OFFSET=0&WIDTH=");
798 // String lenghth of L"&OFFSET=0&WIDTH=" is 16
800 StringPtr
= BlockName
+ 16;
801 BufferLen
= sizeof (BlockName
) - (16 * sizeof (CHAR16
));
802 BufToHexString (StringPtr
, &BufferLen
, (UINT8
*) &BufferSize
, sizeof (UINTN
));
806 Request
= RequestElement
;
809 BufferLen
= HeaderLen
* sizeof (CHAR16
) + StrSize (Request
);
810 ConfigRequest
= AllocateZeroPool (BufferLen
);
812 CopyMem (ConfigRequest
, ConfigHdr
, HeaderLen
* sizeof (CHAR16
));
813 StringPtr
= ConfigRequest
+ HeaderLen
;
814 StrCpy (StringPtr
, Request
);
817 // Convert buffer to <ConfigResp>
819 Status
= HiiConfigRouting
->BlockToConfig (
827 if (EFI_ERROR (Status
)) {
828 gBS
->FreePool (ConfigResp
);
833 // Skip <ConfigHdr> and '&'
835 StringPtr
= ConfigResp
+ HeaderLen
+ 1;
838 // Change uncommitted data in Browser
840 Status
= FormBrowser2
->BrowserCallback (
848 gBS
->FreePool (ConfigResp
);