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";
32 GetPackageDataFromPackageList (
33 IN EFI_HII_PACKAGE_LIST_HEADER
*HiiPackageList
,
34 IN UINT32 PackageIndex
,
35 OUT UINT32
*BufferLen
,
36 OUT EFI_HII_PACKAGE_HEADER
**Buffer
40 EFI_HII_PACKAGE_HEADER
*Package
;
42 UINT32 PackageListLength
;
43 EFI_HII_PACKAGE_HEADER PackageHeader
= {0, 0};
45 ASSERT(HiiPackageList
!= NULL
);
47 if ((BufferLen
== NULL
) || (Buffer
== NULL
)) {
48 return EFI_INVALID_PARAMETER
;
53 Offset
= sizeof (EFI_HII_PACKAGE_LIST_HEADER
);
54 CopyMem (&PackageListLength
, &HiiPackageList
->PackageLength
, sizeof (UINT32
));
55 while (Offset
< PackageListLength
) {
56 Package
= (EFI_HII_PACKAGE_HEADER
*) (((UINT8
*) HiiPackageList
) + Offset
);
57 CopyMem (&PackageHeader
, Package
, sizeof (EFI_HII_PACKAGE_HEADER
));
58 if (Index
== PackageIndex
) {
61 Offset
+= PackageHeader
.Length
;
64 if (Offset
>= PackageListLength
) {
66 // no package found in this Package List
71 *BufferLen
= PackageHeader
.Length
;
78 Draw a dialog and return the selected key.
80 @param NumberOfLines The number of lines for the dialog box
81 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
82 @param String Pointer to the first string in the list
83 @param ... A series of (quantity == NumberOfLines) text
84 strings which will be used to construct the dialog
87 @retval EFI_SUCCESS Displayed dialog and received user interaction
88 @retval EFI_INVALID_PARAMETER One of the parameters was invalid.
94 IN UINTN NumberOfLines
,
95 OUT EFI_INPUT_KEY
*KeyValue
,
109 UINTN DimensionsWidth
;
110 UINTN DimensionsHeight
;
118 CHAR16
**StringArray
;
119 EFI_EVENT TimerEvent
;
120 EFI_EVENT WaitList
[2];
121 UINTN CurrentAttribute
;
122 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*ConOut
;
124 if ((KeyValue
== NULL
) || (String
== NULL
)) {
125 return EFI_INVALID_PARAMETER
;
133 ConOut
= gST
->ConOut
;
134 ConOut
->QueryMode (ConOut
, ConOut
->Mode
->Mode
, &RightColumn
, &BottomRow
);
136 DimensionsWidth
= RightColumn
- LeftColumn
;
137 DimensionsHeight
= BottomRow
- TopRow
;
139 CurrentAttribute
= ConOut
->Mode
->Attribute
;
141 LineBuffer
= AllocateZeroPool (DimensionsWidth
* sizeof (CHAR16
));
142 ASSERT (LineBuffer
!= NULL
);
145 // Determine the largest string in the dialog box
146 // Notice we are starting with 1 since String is the first string
148 StringArray
= AllocateZeroPool (NumberOfLines
* sizeof (CHAR16
*));
149 LargestString
= StrLen (String
);
150 StringArray
[0] = String
;
152 VA_START (Marker
, String
);
153 for (Index
= 1; Index
< NumberOfLines
; Index
++) {
154 StackString
= VA_ARG (Marker
, CHAR16
*);
156 if (StackString
== NULL
) {
157 return EFI_INVALID_PARAMETER
;
160 StringArray
[Index
] = StackString
;
161 StringLen
= StrLen (StackString
);
162 if (StringLen
> LargestString
) {
163 LargestString
= StringLen
;
167 if ((LargestString
+ 2) > DimensionsWidth
) {
168 LargestString
= DimensionsWidth
- 2;
172 // Subtract the PopUp width from total Columns, allow for one space extra on
173 // each end plus a border.
175 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + LeftColumn
+ 1;
177 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + TopRow
- 1;
182 ConOut
->EnableCursor (ConOut
, FALSE
);
183 ConOut
->SetAttribute (ConOut
, EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
);
185 StringPtr
= &LineBuffer
[0];
186 *StringPtr
++ = BOXDRAW_DOWN_RIGHT
;
187 for (Index
= 0; Index
< LargestString
; Index
++) {
188 *StringPtr
++ = BOXDRAW_HORIZONTAL
;
190 *StringPtr
++ = BOXDRAW_DOWN_LEFT
;
193 ConOut
->SetCursorPosition (ConOut
, Start
, Top
);
194 ConOut
->OutputString (ConOut
, LineBuffer
);
196 for (Index
= 0; Index
< NumberOfLines
; Index
++) {
197 StringPtr
= &LineBuffer
[0];
198 *StringPtr
++ = BOXDRAW_VERTICAL
;
200 for (Count
= 0; Count
< LargestString
; Count
++) {
201 StringPtr
[Count
] = L
' ';
204 StringLen
= StrLen (StringArray
[Index
]);
205 if (StringLen
> LargestString
) {
206 StringLen
= LargestString
;
209 StringPtr
+ ((LargestString
- StringLen
) / 2),
211 StringLen
* sizeof (CHAR16
)
213 StringPtr
+= LargestString
;
215 *StringPtr
++ = BOXDRAW_VERTICAL
;
218 ConOut
->SetCursorPosition (ConOut
, Start
, Top
+ 1 + Index
);
219 ConOut
->OutputString (ConOut
, LineBuffer
);
222 StringPtr
= &LineBuffer
[0];
223 *StringPtr
++ = BOXDRAW_UP_RIGHT
;
224 for (Index
= 0; Index
< LargestString
; Index
++) {
225 *StringPtr
++ = BOXDRAW_HORIZONTAL
;
227 *StringPtr
++ = BOXDRAW_UP_LEFT
;
230 ConOut
->SetCursorPosition (ConOut
, Start
, Top
+ NumberOfLines
+ 1);
231 ConOut
->OutputString (ConOut
, LineBuffer
);
234 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
237 // Set a timer event of 1 second expiration
246 // Wait for the keystroke event or the timer
248 WaitList
[0] = gST
->ConIn
->WaitForKey
;
249 WaitList
[1] = TimerEvent
;
250 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
253 // Check for the timer expiration
255 if (!EFI_ERROR (Status
) && Index
== 1) {
256 Status
= EFI_TIMEOUT
;
259 gBS
->CloseEvent (TimerEvent
);
260 } while (Status
== EFI_TIMEOUT
);
262 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
263 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
265 ConOut
->SetAttribute (ConOut
, CurrentAttribute
);
266 ConOut
->EnableCursor (ConOut
, TRUE
);
273 Swap bytes in the buffer.
275 @param Buffer Binary buffer.
276 @param BufferSize Size of the buffer in bytes.
284 IN OUT UINT8
*Buffer
,
292 SwapCount
= (BufferSize
- 1) / 2;
293 for (Index
= 0; Index
< SwapCount
; Index
++) {
294 Temp
= Buffer
[Index
];
295 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
296 Buffer
[BufferSize
- 1 - Index
] = Temp
;
302 Converts binary buffer to Unicode string in reversed byte order from R8_BufToHexString().
304 @param Str String for output
305 @param Buffer Binary buffer.
306 @param BufferSize Size of the buffer in bytes.
308 @retval EFI_SUCCESS The function completed successfully.
323 NewBuffer
= AllocateCopyPool (BufferSize
, Buffer
);
324 SwapBuffer (NewBuffer
, BufferSize
);
326 StrBufferLen
= (BufferSize
+ 1) * sizeof (CHAR16
);
327 Status
= R8_BufToHexString (Str
, &StrBufferLen
, NewBuffer
, BufferSize
);
329 gBS
->FreePool (NewBuffer
);
336 Converts Hex String to binary buffer in reversed byte order from R8_HexStringToBuf().
338 @param Buffer Pointer to buffer that receives the data.
339 @param BufferSize Length in bytes of the buffer to hold converted
340 data. If routine return with EFI_SUCCESS,
341 containing length of converted data. If routine
342 return with EFI_BUFFER_TOO_SMALL, containg length
344 @param Str String to be converted from.
346 @retval EFI_SUCCESS The function completed successfully.
352 IN OUT UINT8
*Buffer
,
353 IN OUT UINTN
*BufferSize
,
358 UINTN ConvertedStrLen
;
361 Status
= R8_HexStringToBuf (Buffer
, BufferSize
, Str
, &ConvertedStrLen
);
362 if (!EFI_ERROR (Status
)) {
363 SwapBuffer (Buffer
, ConvertedStrLen
);
371 Construct <ConfigHdr> using routing information GUID/NAME/PATH.
373 @param ConfigHdr Pointer to the ConfigHdr string.
374 @param StrBufferLen On input: Length in bytes of buffer to hold the
375 ConfigHdr string. Includes tailing '\0' character.
376 On output: If return EFI_SUCCESS, containing
377 length of ConfigHdr string buffer. If return
378 EFI_BUFFER_TOO_SMALL, containg length of string
380 @param Guid Routing information: GUID.
381 @param Name Routing information: NAME.
382 @param DriverHandle Driver handle which contains the routing
385 @retval EFI_SUCCESS Routine success.
386 @retval EFI_BUFFER_TOO_SMALL The ConfigHdr string buffer is too small.
392 IN OUT CHAR16
*ConfigHdr
,
393 IN OUT UINTN
*StrBufferLen
,
395 IN CHAR16
*Name
, OPTIONAL
396 IN EFI_HANDLE
*DriverHandle
401 UINTN DevicePathSize
;
404 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
408 // There will be no "NAME" in <ConfigHdr> for Name/Value storage
413 // For buffer storage
415 NameStrLen
= StrLen (Name
);
419 // Retrieve DevicePath Protocol associated with this HiiPackageList
421 Status
= gBS
->HandleProtocol (
423 &gEfiDevicePathProtocolGuid
,
424 (VOID
**) &DevicePath
426 if (EFI_ERROR (Status
)) {
430 DevicePathSize
= GetDevicePathSize (DevicePath
);
433 // GUID=<HexCh>32&NAME=<Alpha>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
434 // | 5 | 32 | 6 | NameStrLen | 6 | DevicePathStrLen |
436 BufferSize
= (5 + 32 + 6 + NameStrLen
+ 6 + DevicePathSize
* 2 + 1) * sizeof (CHAR16
);
437 if (*StrBufferLen
< BufferSize
) {
438 *StrBufferLen
= BufferSize
;
439 return EFI_BUFFER_TOO_SMALL
;
442 *StrBufferLen
= BufferSize
;
446 StrCpy (StrPtr
, L
"GUID=");
448 BufferToHexString (StrPtr
, (UINT8
*) Guid
, sizeof (EFI_GUID
));
451 StrCpy (StrPtr
, L
"&NAME=");
454 StrCpy (StrPtr
, Name
);
455 StrPtr
+= NameStrLen
;
458 StrCpy (StrPtr
, L
"&PATH=");
460 BufferToHexString (StrPtr
, (UINT8
*) DevicePath
, DevicePathSize
);
467 Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
469 @param String The string to be searched in.
470 @param Offset Offset in BlockName.
471 @param Width Width in BlockName.
473 @retval TRUE Block name found.
474 @retval FALSE Block name not found.
479 IN OUT CHAR16
*String
,
487 UINTN ConvertedStrLen
;
489 while ((String
= StrStr (String
, L
"&OFFSET=")) != NULL
) {
496 BufferSize
= sizeof (UINTN
);
497 Status
= R8_HexStringToBuf ((UINT8
*) &Data
, &BufferSize
, String
, &ConvertedStrLen
);
498 if (EFI_ERROR (Status
)) {
501 String
= String
+ ConvertedStrLen
;
503 if (Data
!= Offset
) {
507 if (StrnCmp (String
, L
"&WIDTH=", 7) != 0) {
513 BufferSize
= sizeof (UINTN
);
514 Status
= R8_HexStringToBuf ((UINT8
*) &Data
, &BufferSize
, String
, &ConvertedStrLen
);
515 if (EFI_ERROR (Status
)) {
522 String
= String
+ ConvertedStrLen
;
530 This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
532 @param VariableGuid An optional field to indicate the target variable
534 @param VariableName An optional field to indicate the target
535 human-readable variable name.
536 @param BufferSize On input: Length in bytes of buffer to hold
537 retrived data. On output: If return
538 EFI_BUFFER_TOO_SMALL, containg length of buffer
540 @param Buffer Buffer to hold retrived data.
542 @retval EFI_SUCCESS Routine success.
543 @retval EFI_BUFFER_TOO_SMALL The intput buffer is too small.
549 EFI_GUID
*VariableGuid
, OPTIONAL
550 CHAR16
*VariableName
, OPTIONAL
562 EFI_FORM_BROWSER2_PROTOCOL
*FormBrowser2
;
563 EFI_HII_CONFIG_ROUTING_PROTOCOL
*HiiConfigRouting
;
566 // Locate protocols for use
568 Status
= gBS
->LocateProtocol (&gEfiFormBrowser2ProtocolGuid
, NULL
, (VOID
**) &FormBrowser2
);
569 if (EFI_ERROR (Status
)) {
573 Status
= gBS
->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid
, NULL
, (VOID
**) &HiiConfigRouting
);
574 if (EFI_ERROR (Status
)) {
579 // Retrive formset storage data from Form Browser
581 ConfigHdr
= mFakeConfigHdr
;
582 HeaderLen
= StrLen (ConfigHdr
);
585 ConfigResp
= AllocateZeroPool (BufferLen
+ HeaderLen
);
587 StringPtr
= ConfigResp
+ HeaderLen
;
591 Status
= FormBrowser2
->BrowserCallback (
599 if (Status
== EFI_BUFFER_TOO_SMALL
) {
600 gBS
->FreePool (ConfigResp
);
601 ConfigResp
= AllocateZeroPool (BufferLen
+ HeaderLen
);
603 StringPtr
= ConfigResp
+ HeaderLen
;
607 Status
= FormBrowser2
->BrowserCallback (
616 if (EFI_ERROR (Status
)) {
617 gBS
->FreePool (ConfigResp
);
620 CopyMem (ConfigResp
, ConfigHdr
, HeaderLen
* sizeof (UINT16
));
623 // Convert <ConfigResp> to buffer data
625 Status
= HiiConfigRouting
->ConfigToBlock (
632 gBS
->FreePool (ConfigResp
);
639 This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
641 @param VariableGuid An optional field to indicate the target variable
643 @param VariableName An optional field to indicate the target
644 human-readable variable name.
645 @param BufferSize Length in bytes of buffer to hold retrived data.
646 @param Buffer Buffer to hold retrived data.
647 @param RequestElement An optional field to specify which part of the
648 buffer data will be send back to Browser. If NULL,
649 the whole buffer of data will be committed to
650 Browser. <RequestElement> ::=
651 &OFFSET=<Number>&WIDTH=<Number>*
653 @retval EFI_SUCCESS Routine success.
654 @retval Other Updating Browser uncommitted data failed.
660 EFI_GUID
*VariableGuid
, OPTIONAL
661 CHAR16
*VariableName
, OPTIONAL
664 CHAR16
*RequestElement OPTIONAL
674 EFI_FORM_BROWSER2_PROTOCOL
*FormBrowser2
;
675 EFI_HII_CONFIG_ROUTING_PROTOCOL
*HiiConfigRouting
;
676 CHAR16 BlockName
[33];
677 CHAR16
*ConfigRequest
;
681 // Locate protocols for use
683 Status
= gBS
->LocateProtocol (&gEfiFormBrowser2ProtocolGuid
, NULL
, (VOID
**) &FormBrowser2
);
684 if (EFI_ERROR (Status
)) {
688 Status
= gBS
->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid
, NULL
, (VOID
**) &HiiConfigRouting
);
689 if (EFI_ERROR (Status
)) {
694 // Prepare <ConfigRequest>
696 ConfigHdr
= mFakeConfigHdr
;
697 HeaderLen
= StrLen (ConfigHdr
);
699 if (RequestElement
== NULL
) {
701 // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
703 BlockName
[0] = L
'\0';
704 StrCpy (BlockName
, L
"&OFFSET=0&WIDTH=");
707 // String lenghth of L"&OFFSET=0&WIDTH=" is 16
709 StringPtr
= BlockName
+ 16;
710 BufferLen
= sizeof (BlockName
) - (16 * sizeof (CHAR16
));
711 R8_BufToHexString (StringPtr
, &BufferLen
, (UINT8
*) &BufferSize
, sizeof (UINTN
));
715 Request
= RequestElement
;
718 BufferLen
= HeaderLen
* sizeof (CHAR16
) + StrSize (Request
);
719 ConfigRequest
= AllocateZeroPool (BufferLen
);
721 CopyMem (ConfigRequest
, ConfigHdr
, HeaderLen
* sizeof (CHAR16
));
722 StringPtr
= ConfigRequest
+ HeaderLen
;
723 StrCpy (StringPtr
, Request
);
726 // Convert buffer to <ConfigResp>
728 Status
= HiiConfigRouting
->BlockToConfig (
736 if (EFI_ERROR (Status
)) {
737 gBS
->FreePool (ConfigResp
);
742 // Skip <ConfigHdr> and '&'
744 StringPtr
= ConfigResp
+ HeaderLen
+ 1;
747 // Change uncommitted data in Browser
749 Status
= FormBrowser2
->BrowserCallback (
757 gBS
->FreePool (ConfigResp
);