3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Common Library Routines to assist handle HII elements.
23 #include "UefiIfrLibraryInternal.h"
28 UINT16 mFakeConfigHdr
[] = L
"GUID=00000000000000000000000000000000&NAME=0000&PATH=0";
33 GetPackageDataFromPackageList (
34 IN EFI_HII_PACKAGE_LIST_HEADER
*HiiPackageList
,
35 IN UINT32 PackageIndex
,
36 OUT UINT32
*BufferLen
,
37 OUT EFI_HII_PACKAGE_HEADER
**Buffer
41 EFI_HII_PACKAGE_HEADER
*Package
;
43 UINT32 PackageListLength
;
44 EFI_HII_PACKAGE_HEADER PackageHeader
= {0, 0};
46 ASSERT(HiiPackageList
!= NULL
);
48 if ((BufferLen
== NULL
) || (Buffer
== NULL
)) {
49 return EFI_INVALID_PARAMETER
;
54 Offset
= sizeof (EFI_HII_PACKAGE_LIST_HEADER
);
55 CopyMem (&PackageListLength
, &HiiPackageList
->PackageLength
, sizeof (UINT32
));
56 while (Offset
< PackageListLength
) {
57 Package
= (EFI_HII_PACKAGE_HEADER
*) (((UINT8
*) HiiPackageList
) + Offset
);
58 CopyMem (&PackageHeader
, Package
, sizeof (EFI_HII_PACKAGE_HEADER
));
59 if (Index
== PackageIndex
) {
62 Offset
+= PackageHeader
.Length
;
65 if (Offset
>= PackageListLength
) {
67 // no package found in this Package List
72 *BufferLen
= PackageHeader
.Length
;
80 Draw a dialog and return the selected key.
82 @param NumberOfLines The number of lines for the dialog box
83 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
84 @param String Pointer to the first string in the list
85 @param ... A series of (quantity == NumberOfLines) text
86 strings which will be used to construct the dialog
89 @retval EFI_SUCCESS Displayed dialog and received user interaction
90 @retval EFI_INVALID_PARAMETER One of the parameters was invalid.
96 IN UINTN NumberOfLines
,
97 OUT EFI_INPUT_KEY
*KeyValue
,
111 UINTN DimensionsWidth
;
112 UINTN DimensionsHeight
;
120 CHAR16
**StringArray
;
121 EFI_EVENT TimerEvent
;
122 EFI_EVENT WaitList
[2];
123 UINTN CurrentAttribute
;
124 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*ConOut
;
126 if ((KeyValue
== NULL
) || (String
== NULL
)) {
127 return EFI_INVALID_PARAMETER
;
135 ConOut
= gST
->ConOut
;
136 ConOut
->QueryMode (ConOut
, ConOut
->Mode
->Mode
, &RightColumn
, &BottomRow
);
138 DimensionsWidth
= RightColumn
- LeftColumn
;
139 DimensionsHeight
= BottomRow
- TopRow
;
141 CurrentAttribute
= ConOut
->Mode
->Attribute
;
143 LineBuffer
= AllocateZeroPool (DimensionsWidth
* sizeof (CHAR16
));
144 ASSERT (LineBuffer
!= NULL
);
147 // Determine the largest string in the dialog box
148 // Notice we are starting with 1 since String is the first string
150 StringArray
= AllocateZeroPool (NumberOfLines
* sizeof (CHAR16
*));
151 LargestString
= StrLen (String
);
152 StringArray
[0] = String
;
154 VA_START (Marker
, String
);
155 for (Index
= 1; Index
< NumberOfLines
; Index
++) {
156 StackString
= VA_ARG (Marker
, CHAR16
*);
158 if (StackString
== NULL
) {
159 return EFI_INVALID_PARAMETER
;
162 StringArray
[Index
] = StackString
;
163 StringLen
= StrLen (StackString
);
164 if (StringLen
> LargestString
) {
165 LargestString
= StringLen
;
169 if ((LargestString
+ 2) > DimensionsWidth
) {
170 LargestString
= DimensionsWidth
- 2;
174 // Subtract the PopUp width from total Columns, allow for one space extra on
175 // each end plus a border.
177 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + LeftColumn
+ 1;
179 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + TopRow
- 1;
184 ConOut
->EnableCursor (ConOut
, FALSE
);
185 ConOut
->SetAttribute (ConOut
, EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
);
187 StringPtr
= &LineBuffer
[0];
188 *StringPtr
++ = BOXDRAW_DOWN_RIGHT
;
189 for (Index
= 0; Index
< LargestString
; Index
++) {
190 *StringPtr
++ = BOXDRAW_HORIZONTAL
;
192 *StringPtr
++ = BOXDRAW_DOWN_LEFT
;
195 ConOut
->SetCursorPosition (ConOut
, Start
, Top
);
196 ConOut
->OutputString (ConOut
, LineBuffer
);
198 for (Index
= 0; Index
< NumberOfLines
; Index
++) {
199 StringPtr
= &LineBuffer
[0];
200 *StringPtr
++ = BOXDRAW_VERTICAL
;
202 for (Count
= 0; Count
< LargestString
; Count
++) {
203 StringPtr
[Count
] = L
' ';
206 StringLen
= StrLen (StringArray
[Index
]);
207 if (StringLen
> LargestString
) {
208 StringLen
= LargestString
;
211 StringPtr
+ ((LargestString
- StringLen
) / 2),
213 StringLen
* sizeof (CHAR16
)
215 StringPtr
+= LargestString
;
217 *StringPtr
++ = BOXDRAW_VERTICAL
;
220 ConOut
->SetCursorPosition (ConOut
, Start
, Top
+ 1 + Index
);
221 ConOut
->OutputString (ConOut
, LineBuffer
);
224 StringPtr
= &LineBuffer
[0];
225 *StringPtr
++ = BOXDRAW_UP_RIGHT
;
226 for (Index
= 0; Index
< LargestString
; Index
++) {
227 *StringPtr
++ = BOXDRAW_HORIZONTAL
;
229 *StringPtr
++ = BOXDRAW_UP_LEFT
;
232 ConOut
->SetCursorPosition (ConOut
, Start
, Top
+ NumberOfLines
+ 1);
233 ConOut
->OutputString (ConOut
, LineBuffer
);
236 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
239 // Set a timer event of 1 second expiration
248 // Wait for the keystroke event or the timer
250 WaitList
[0] = gST
->ConIn
->WaitForKey
;
251 WaitList
[1] = TimerEvent
;
252 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
255 // Check for the timer expiration
257 if (!EFI_ERROR (Status
) && Index
== 1) {
258 Status
= EFI_TIMEOUT
;
261 gBS
->CloseEvent (TimerEvent
);
262 } while (Status
== EFI_TIMEOUT
);
264 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
265 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
267 ConOut
->SetAttribute (ConOut
, CurrentAttribute
);
268 ConOut
->EnableCursor (ConOut
, TRUE
);
275 Swap bytes in the buffer.
277 @param Buffer Binary buffer.
278 @param BufferSize Size of the buffer in bytes.
286 IN OUT UINT8
*Buffer
,
294 SwapCount
= (BufferSize
- 1) / 2;
295 for (Index
= 0; Index
< SwapCount
; Index
++) {
296 Temp
= Buffer
[Index
];
297 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
298 Buffer
[BufferSize
- 1 - Index
] = Temp
;
304 Converts binary buffer to Unicode string in reversed byte order from R8_BufToHexString().
306 @param Str String for output
307 @param Buffer Binary buffer.
308 @param BufferSize Size of the buffer in bytes.
310 @retval EFI_SUCCESS The function completed successfully.
325 NewBuffer
= AllocateCopyPool (BufferSize
, Buffer
);
326 SwapBuffer (NewBuffer
, BufferSize
);
328 StrBufferLen
= (BufferSize
+ 1) * sizeof (CHAR16
);
329 Status
= R8_BufToHexString (Str
, &StrBufferLen
, NewBuffer
, BufferSize
);
331 gBS
->FreePool (NewBuffer
);
338 Converts Hex String to binary buffer in reversed byte order from R8_HexStringToBuf().
340 @param Buffer Pointer to buffer that receives the data.
341 @param BufferSize Length in bytes of the buffer to hold converted
342 data. If routine return with EFI_SUCCESS,
343 containing length of converted data. If routine
344 return with EFI_BUFFER_TOO_SMALL, containg length
346 @param Str String to be converted from.
348 @retval EFI_SUCCESS The function completed successfully.
354 IN OUT UINT8
*Buffer
,
355 IN OUT UINTN
*BufferSize
,
360 UINTN ConvertedStrLen
;
363 Status
= R8_HexStringToBuf (Buffer
, BufferSize
, Str
, &ConvertedStrLen
);
364 if (!EFI_ERROR (Status
)) {
365 SwapBuffer (Buffer
, ConvertedStrLen
);
373 Construct <ConfigHdr> using routing information GUID/NAME/PATH.
375 @param ConfigHdr Pointer to the ConfigHdr string.
376 @param StrBufferLen On input: Length in bytes of buffer to hold the
377 ConfigHdr string. Includes tailing '\0' character.
378 On output: If return EFI_SUCCESS, containing
379 length of ConfigHdr string buffer. If return
380 EFI_BUFFER_TOO_SMALL, containg length of string
382 @param Guid Routing information: GUID.
383 @param Name Routing information: NAME.
384 @param DriverHandle Driver handle which contains the routing
387 @retval EFI_SUCCESS Routine success.
388 @retval EFI_BUFFER_TOO_SMALL The ConfigHdr string buffer is too small.
394 IN OUT CHAR16
*ConfigHdr
,
395 IN OUT UINTN
*StrBufferLen
,
397 IN CHAR16
*Name
, OPTIONAL
398 IN EFI_HANDLE
*DriverHandle
403 UINTN DevicePathSize
;
406 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
410 // There will be no "NAME" in <ConfigHdr> for Name/Value storage
415 // For buffer storage
417 NameStrLen
= StrLen (Name
);
421 // Retrieve DevicePath Protocol associated with this HiiPackageList
423 Status
= gBS
->HandleProtocol (
425 &gEfiDevicePathProtocolGuid
,
426 (VOID
**) &DevicePath
428 if (EFI_ERROR (Status
)) {
432 DevicePathSize
= GetDevicePathSize (DevicePath
);
435 // GUID=<HexCh>32&NAME=<Alpha>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
436 // | 5 | 32 | 6 | NameStrLen | 6 | DevicePathStrLen |
438 BufferSize
= (5 + 32 + 6 + NameStrLen
+ 6 + DevicePathSize
* 2 + 1) * sizeof (CHAR16
);
439 if (*StrBufferLen
< BufferSize
) {
440 *StrBufferLen
= BufferSize
;
441 return EFI_BUFFER_TOO_SMALL
;
444 *StrBufferLen
= BufferSize
;
448 StrCpy (StrPtr
, L
"GUID=");
450 BufferToHexString (StrPtr
, (UINT8
*) Guid
, sizeof (EFI_GUID
));
453 StrCpy (StrPtr
, L
"&NAME=");
456 StrCpy (StrPtr
, Name
);
457 StrPtr
+= NameStrLen
;
460 StrCpy (StrPtr
, L
"&PATH=");
462 BufferToHexString (StrPtr
, (UINT8
*) DevicePath
, DevicePathSize
);
469 Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
471 @param String The string to be searched in.
472 @param Offset Offset in BlockName.
473 @param Width Width in BlockName.
475 @retval TRUE Block name found.
476 @retval FALSE Block name not found.
481 IN OUT CHAR16
*String
,
489 UINTN ConvertedStrLen
;
491 while ((String
= StrStr (String
, L
"&OFFSET=")) != NULL
) {
498 BufferSize
= sizeof (UINTN
);
499 Status
= R8_HexStringToBuf ((UINT8
*) &Data
, &BufferSize
, String
, &ConvertedStrLen
);
500 if (EFI_ERROR (Status
)) {
503 String
= String
+ ConvertedStrLen
;
505 if (Data
!= Offset
) {
509 if (StrnCmp (String
, L
"&WIDTH=", 7) != 0) {
515 BufferSize
= sizeof (UINTN
);
516 Status
= R8_HexStringToBuf ((UINT8
*) &Data
, &BufferSize
, String
, &ConvertedStrLen
);
517 if (EFI_ERROR (Status
)) {
524 String
= String
+ ConvertedStrLen
;
532 This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
534 @param VariableGuid An optional field to indicate the target variable
536 @param VariableName An optional field to indicate the target
537 human-readable variable name.
538 @param BufferSize On input: Length in bytes of buffer to hold
539 retrived data. On output: If return
540 EFI_BUFFER_TOO_SMALL, containg length of buffer
542 @param Buffer Buffer to hold retrived data.
544 @retval EFI_SUCCESS Routine success.
545 @retval EFI_BUFFER_TOO_SMALL The intput buffer is too small.
551 EFI_GUID
*VariableGuid
, OPTIONAL
552 CHAR16
*VariableName
, OPTIONAL
564 EFI_FORM_BROWSER2_PROTOCOL
*FormBrowser2
;
565 EFI_HII_CONFIG_ROUTING_PROTOCOL
*HiiConfigRouting
;
568 // Locate protocols for use
570 Status
= gBS
->LocateProtocol (&gEfiFormBrowser2ProtocolGuid
, NULL
, (VOID
**) &FormBrowser2
);
571 if (EFI_ERROR (Status
)) {
575 Status
= gBS
->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid
, NULL
, (VOID
**) &HiiConfigRouting
);
576 if (EFI_ERROR (Status
)) {
581 // Retrive formset storage data from Form Browser
583 ConfigHdr
= mFakeConfigHdr
;
584 HeaderLen
= StrLen (ConfigHdr
);
587 ConfigResp
= AllocateZeroPool (BufferLen
+ HeaderLen
);
589 StringPtr
= ConfigResp
+ HeaderLen
;
593 Status
= FormBrowser2
->BrowserCallback (
601 if (Status
== EFI_BUFFER_TOO_SMALL
) {
602 gBS
->FreePool (ConfigResp
);
603 ConfigResp
= AllocateZeroPool (BufferLen
+ HeaderLen
);
605 StringPtr
= ConfigResp
+ HeaderLen
;
609 Status
= FormBrowser2
->BrowserCallback (
618 if (EFI_ERROR (Status
)) {
619 gBS
->FreePool (ConfigResp
);
622 CopyMem (ConfigResp
, ConfigHdr
, HeaderLen
* sizeof (UINT16
));
625 // Convert <ConfigResp> to buffer data
627 Status
= HiiConfigRouting
->ConfigToBlock (
634 gBS
->FreePool (ConfigResp
);
641 This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
643 @param VariableGuid An optional field to indicate the target variable
645 @param VariableName An optional field to indicate the target
646 human-readable variable name.
647 @param BufferSize Length in bytes of buffer to hold retrived data.
648 @param Buffer Buffer to hold retrived data.
649 @param RequestElement An optional field to specify which part of the
650 buffer data will be send back to Browser. If NULL,
651 the whole buffer of data will be committed to
652 Browser. <RequestElement> ::=
653 &OFFSET=<Number>&WIDTH=<Number>*
655 @retval EFI_SUCCESS Routine success.
656 @retval Other Updating Browser uncommitted data failed.
662 EFI_GUID
*VariableGuid
, OPTIONAL
663 CHAR16
*VariableName
, OPTIONAL
666 CHAR16
*RequestElement OPTIONAL
676 EFI_FORM_BROWSER2_PROTOCOL
*FormBrowser2
;
677 EFI_HII_CONFIG_ROUTING_PROTOCOL
*HiiConfigRouting
;
678 CHAR16 BlockName
[33];
679 CHAR16
*ConfigRequest
;
683 // Locate protocols for use
685 Status
= gBS
->LocateProtocol (&gEfiFormBrowser2ProtocolGuid
, NULL
, (VOID
**) &FormBrowser2
);
686 if (EFI_ERROR (Status
)) {
690 Status
= gBS
->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid
, NULL
, (VOID
**) &HiiConfigRouting
);
691 if (EFI_ERROR (Status
)) {
696 // Prepare <ConfigRequest>
698 ConfigHdr
= mFakeConfigHdr
;
699 HeaderLen
= StrLen (ConfigHdr
);
701 if (RequestElement
== NULL
) {
703 // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
705 BlockName
[0] = L
'\0';
706 StrCpy (BlockName
, L
"&OFFSET=0&WIDTH=");
709 // String lenghth of L"&OFFSET=0&WIDTH=" is 16
711 StringPtr
= BlockName
+ 16;
712 BufferLen
= sizeof (BlockName
) - (16 * sizeof (CHAR16
));
713 R8_BufToHexString (StringPtr
, &BufferLen
, (UINT8
*) &BufferSize
, sizeof (UINTN
));
717 Request
= RequestElement
;
720 BufferLen
= HeaderLen
* sizeof (CHAR16
) + StrSize (Request
);
721 ConfigRequest
= AllocateZeroPool (BufferLen
);
723 CopyMem (ConfigRequest
, ConfigHdr
, HeaderLen
* sizeof (CHAR16
));
724 StringPtr
= ConfigRequest
+ HeaderLen
;
725 StrCpy (StringPtr
, Request
);
728 // Convert buffer to <ConfigResp>
730 Status
= HiiConfigRouting
->BlockToConfig (
738 if (EFI_ERROR (Status
)) {
739 gBS
->FreePool (ConfigResp
);
744 // Skip <ConfigHdr> and '&'
746 StringPtr
= ConfigResp
+ HeaderLen
+ 1;
749 // Change uncommitted data in Browser
751 Status
= FormBrowser2
->BrowserCallback (
759 gBS
->FreePool (ConfigResp
);