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