]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/UefiIfrSupportLib/UefiIfrForm.c
Make use of MdePkg's FreePool library function to replace gBS->FreePool.
[mirror_edk2.git] / MdeModulePkg / Library / UefiIfrSupportLib / UefiIfrForm.c
CommitLineData
08e4b3cf 1/** @file\r
2Utility functions which helps in opcode creation, HII configuration string manipulations, \r
3pop up window creations, setup browser persistence data set and get.\r
4\r
5Copyright (c) 2007- 2008, Intel Corporation\r
6All rights reserved. This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "UefiIfrLibraryInternal.h"\r
17\r
18CONST EFI_FORM_BROWSER2_PROTOCOL *mFormBrowser2 = NULL;\r
19CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *mIfrSupportLibHiiConfigRouting = NULL;\r
ac7e320c 20GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mIfrSupportLibHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};\r
08e4b3cf 21\r
aa79b0b3 22//\r
23// Fake <ConfigHdr>\r
24//\r
25GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT16 mFakeConfigHdr[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=0";\r
26\r
08e4b3cf 27/**\r
28 This function locate FormBrowser2 protocols for later usage.\r
29\r
30 @return Status the status to locate protocol.\r
31**/\r
32EFI_STATUS\r
33LocateFormBrowser2Protocols (\r
34 VOID\r
35 )\r
36{\r
37 EFI_STATUS Status;\r
38 //\r
39 // Locate protocols for later usage\r
40 //\r
41 if (mFormBrowser2 == NULL) {\r
42 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &mFormBrowser2);\r
43 if (EFI_ERROR (Status)) {\r
44 return Status;\r
45 }\r
46 }\r
47 \r
48 if (mIfrSupportLibHiiConfigRouting == NULL) {\r
49 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &mIfrSupportLibHiiConfigRouting);\r
50 if (EFI_ERROR (Status)) {\r
51 return Status;\r
52 }\r
53 }\r
54\r
55 return EFI_SUCCESS;\r
56}\r
57\r
08e4b3cf 58/**\r
59 Draw a dialog and return the selected key.\r
60\r
61 @param NumberOfLines The number of lines for the dialog box\r
62 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..\r
35d59af3 63 @param String The first String to be displayed in the Pop-Up.\r
08e4b3cf 64 @param Marker A series of (quantity == NumberOfLines - 1) text\r
65 strings which will be used to construct the dialog\r
66 box\r
67\r
68 @retval EFI_SUCCESS Displayed dialog and received user interaction\r
69 @retval EFI_INVALID_PARAMETER One of the parameters was invalid.\r
70 @retval EFI_OUT_OF_RESOURCES There is no enough available memory space.\r
71\r
72**/\r
73EFI_STATUS\r
74EFIAPI\r
75IfrLibCreatePopUp2 (\r
76 IN UINTN NumberOfLines,\r
77 OUT EFI_INPUT_KEY *KeyValue,\r
35d59af3 78 IN CHAR16 *String,\r
08e4b3cf 79 IN VA_LIST Marker\r
80 )\r
81{\r
82 UINTN Index;\r
83 UINTN Count;\r
84 UINTN Start;\r
85 UINTN Top;\r
86 CHAR16 *StringPtr;\r
87 UINTN LeftColumn;\r
88 UINTN RightColumn;\r
89 UINTN TopRow;\r
90 UINTN BottomRow;\r
91 UINTN DimensionsWidth;\r
92 UINTN DimensionsHeight;\r
93 EFI_INPUT_KEY Key;\r
94 UINTN LargestString;\r
95 CHAR16 *StackString;\r
96 EFI_STATUS Status;\r
97 UINTN StringLen;\r
98 CHAR16 *LineBuffer;\r
99 CHAR16 **StringArray;\r
100 EFI_EVENT TimerEvent;\r
101 EFI_EVENT WaitList[2];\r
102 UINTN CurrentAttribute;\r
103 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;\r
08e4b3cf 104\r
08e4b3cf 105 if ((KeyValue == NULL) || (String == NULL)) {\r
106 return EFI_INVALID_PARAMETER;\r
107 }\r
108\r
109 TopRow = 0;\r
110 BottomRow = 0;\r
111 LeftColumn = 0;\r
112 RightColumn = 0;\r
113\r
114 ConOut = gST->ConOut;\r
115 ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow);\r
116\r
117 DimensionsWidth = RightColumn - LeftColumn;\r
118 DimensionsHeight = BottomRow - TopRow;\r
119\r
120 CurrentAttribute = ConOut->Mode->Attribute;\r
121\r
122 LineBuffer = AllocateZeroPool (DimensionsWidth * sizeof (CHAR16));\r
123 if (LineBuffer == NULL) {\r
124 return EFI_OUT_OF_RESOURCES;\r
125 }\r
126\r
127 //\r
128 // Determine the largest string in the dialog box\r
129 // Notice we are starting with 1 since String is the first string\r
130 //\r
131 StringArray = AllocateZeroPool (NumberOfLines * sizeof (CHAR16 *));\r
132 if (StringArray == NULL) {\r
133 FreePool (LineBuffer);\r
134 return EFI_OUT_OF_RESOURCES;\r
135 }\r
136 LargestString = StrLen (String);\r
137 StringArray[0] = String;\r
138\r
139 for (Index = 1; Index < NumberOfLines; Index++) {\r
140 StackString = VA_ARG (Marker, CHAR16 *);\r
141\r
142 if (StackString == NULL) {\r
143 FreePool (LineBuffer);\r
144 FreePool (StringArray);\r
145 return EFI_INVALID_PARAMETER;\r
146 }\r
147\r
148 StringArray[Index] = StackString;\r
149 StringLen = StrLen (StackString);\r
150 if (StringLen > LargestString) {\r
151 LargestString = StringLen;\r
152 }\r
153 }\r
154\r
155 if ((LargestString + 2) > DimensionsWidth) {\r
156 LargestString = DimensionsWidth - 2;\r
157 }\r
158\r
159 //\r
160 // Subtract the PopUp width from total Columns, allow for one space extra on\r
161 // each end plus a border.\r
162 //\r
163 Start = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1;\r
164\r
165 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1;\r
166\r
167 //\r
168 // Disable cursor\r
169 //\r
170 ConOut->EnableCursor (ConOut, FALSE);\r
171 ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);\r
172\r
173 StringPtr = &LineBuffer[0];\r
174 *StringPtr++ = BOXDRAW_DOWN_RIGHT;\r
175 for (Index = 0; Index < LargestString; Index++) {\r
176 *StringPtr++ = BOXDRAW_HORIZONTAL;\r
177 }\r
178 *StringPtr++ = BOXDRAW_DOWN_LEFT;\r
179 *StringPtr = L'\0';\r
180\r
181 ConOut->SetCursorPosition (ConOut, Start, Top);\r
182 ConOut->OutputString (ConOut, LineBuffer);\r
183\r
184 for (Index = 0; Index < NumberOfLines; Index++) {\r
185 StringPtr = &LineBuffer[0];\r
186 *StringPtr++ = BOXDRAW_VERTICAL;\r
187\r
188 for (Count = 0; Count < LargestString; Count++) {\r
189 StringPtr[Count] = L' ';\r
190 }\r
191\r
192 StringLen = StrLen (StringArray[Index]);\r
193 if (StringLen > LargestString) {\r
194 StringLen = LargestString;\r
195 }\r
196 CopyMem (\r
197 StringPtr + ((LargestString - StringLen) / 2),\r
198 StringArray[Index],\r
199 StringLen * sizeof (CHAR16)\r
200 );\r
201 StringPtr += LargestString;\r
202\r
203 *StringPtr++ = BOXDRAW_VERTICAL;\r
204 *StringPtr = L'\0';\r
205\r
206 ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index);\r
207 ConOut->OutputString (ConOut, LineBuffer);\r
208 }\r
209\r
210 StringPtr = &LineBuffer[0];\r
211 *StringPtr++ = BOXDRAW_UP_RIGHT;\r
212 for (Index = 0; Index < LargestString; Index++) {\r
213 *StringPtr++ = BOXDRAW_HORIZONTAL;\r
214 }\r
215 *StringPtr++ = BOXDRAW_UP_LEFT;\r
216 *StringPtr = L'\0';\r
217\r
218 ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1);\r
219 ConOut->OutputString (ConOut, LineBuffer);\r
220\r
221 do {\r
222 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
223\r
224 //\r
225 // Set a timer event of 1 second expiration\r
226 //\r
227 gBS->SetTimer (\r
228 TimerEvent,\r
229 TimerRelative,\r
230 10000000\r
231 );\r
232\r
233 //\r
234 // Wait for the keystroke event or the timer\r
235 //\r
236 WaitList[0] = gST->ConIn->WaitForKey;\r
237 WaitList[1] = TimerEvent;\r
238 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
239\r
240 //\r
241 // Check for the timer expiration\r
242 //\r
243 if (!EFI_ERROR (Status) && Index == 1) {\r
244 Status = EFI_TIMEOUT;\r
245 }\r
246\r
247 gBS->CloseEvent (TimerEvent);\r
248 } while (Status == EFI_TIMEOUT);\r
249\r
250 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
251 CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));\r
252\r
253 ConOut->SetAttribute (ConOut, CurrentAttribute);\r
254 ConOut->EnableCursor (ConOut, TRUE);\r
255\r
256 FreePool (LineBuffer);\r
257 FreePool (StringArray);\r
258\r
259 return Status;\r
260}\r
261\r
262\r
263/**\r
264 Draw a dialog and return the selected key.\r
265\r
266 @param NumberOfLines The number of lines for the dialog box\r
267 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..\r
268 @param String Pointer to the first string in the list\r
269 @param ... A series of (quantity == NumberOfLines - 1) text\r
270 strings which will be used to construct the dialog\r
271 box\r
272\r
273 @retval EFI_SUCCESS Displayed dialog and received user interaction\r
274 @retval EFI_INVALID_PARAMETER One of the parameters was invalid.\r
275\r
276**/\r
277EFI_STATUS\r
278EFIAPI\r
279IfrLibCreatePopUp (\r
280 IN UINTN NumberOfLines,\r
281 OUT EFI_INPUT_KEY *KeyValue,\r
282 IN CHAR16 *String,\r
283 ...\r
284 )\r
285{\r
286 EFI_STATUS Status;\r
287 VA_LIST Marker;\r
288\r
35d59af3 289 VA_START (Marker, String);\r
08e4b3cf 290\r
35d59af3 291 Status = IfrLibCreatePopUp2 (NumberOfLines, KeyValue, String, Marker);\r
08e4b3cf 292\r
293 VA_END (Marker);\r
294\r
295 return Status;\r
296}\r
297\r
298/**\r
299 Extract block name from the array generated by VFR compiler. The name of\r
300 this array is "Vfr + <StorageName> + BlockName", e.g. "VfrMyIfrNVDataBlockName".\r
301 Format of this array is:\r
302 Array length | 4-bytes\r
303 Offset | 2-bytes\r
304 Width | 2-bytes\r
305 Offset | 2-bytes\r
306 Width | 2-bytes\r
307 ... ...\r
308\r
309 @param Buffer Array generated by VFR compiler.\r
310 @param BlockName The returned <BlockName>\r
311\r
312 @retval EFI_OUT_OF_RESOURCES Run out of memory resource.\r
313 @retval EFI_INVALID_PARAMETER Buffer is NULL or BlockName is NULL.\r
314 @retval EFI_SUCCESS Operation successful.\r
315\r
316**/\r
317EFI_STATUS\r
318ExtractBlockName (\r
319 IN UINT8 *Buffer,\r
320 OUT CHAR16 **BlockName\r
321 )\r
322\r
323{\r
324 UINTN Index;\r
325 UINT32 Length;\r
326 UINT32 BlockNameNumber;\r
327 UINTN HexStringBufferLen;\r
328 CHAR16 *StringPtr;\r
329\r
330 if ((Buffer == NULL) || (BlockName == NULL)) {\r
331 return EFI_INVALID_PARAMETER;\r
332 }\r
333\r
334 //\r
335 // Calculate number of Offset/Width pair\r
336 //\r
337 CopyMem (&Length, Buffer, sizeof (UINT32));\r
338 BlockNameNumber = (Length - sizeof (UINT32)) / (sizeof (UINT16) * 2);\r
339\r
340 //\r
341 // <BlockName> ::= &OFFSET=1234&WIDTH=1234\r
342 // | 8 | 4 | 7 | 4 |\r
343 //\r
344 StringPtr = AllocateZeroPool ((BlockNameNumber * (8 + 4 + 7 + 4) + 1) * sizeof (CHAR16));\r
345 *BlockName = StringPtr;\r
346 if (StringPtr == NULL) {\r
347 return EFI_OUT_OF_RESOURCES;\r
348 }\r
349\r
350 Buffer += sizeof (UINT32);\r
351 for (Index = 0; Index < BlockNameNumber; Index++) {\r
352 StrCpy (StringPtr, L"&OFFSET=");\r
353 StringPtr += 8;\r
354\r
355 HexStringBufferLen = 5;\r
356 BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));\r
357 Buffer += sizeof (UINT16);\r
358 StringPtr += 4;\r
359\r
360 StrCpy (StringPtr, L"&WIDTH=");\r
361 StringPtr += 7;\r
362\r
363 HexStringBufferLen = 5;\r
364 BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));\r
365 Buffer += sizeof (UINT16);\r
366 StringPtr += 4;\r
367 }\r
368\r
369 return EFI_SUCCESS;\r
370}\r
371\r
372/**\r
373\r
374 Extract block config from the array generated by VFR compiler. The name of\r
375 this array is "Vfr + <StorageName> + Default<HexCh>4", e.g. "VfrMyIfrNVDataDefault0000".\r
376\r
377 @param Buffer - Array generated by VFR compiler.\r
378 @param BlockConfig - The returned <BlockConfig>\r
379\r
380 @retval EFI_OUT_OF_RESOURCES - Run out of memory resource.\r
381 @retval EFI_INVALID_PARAMETER - Buffer is NULL or BlockConfig is NULL.\r
382 @retval EFI_SUCCESS - Operation successful.\r
383\r
384**/\r
385EFI_STATUS\r
386ExtractBlockConfig (\r
387 IN UINT8 *Buffer,\r
388 OUT CHAR16 **BlockConfig\r
389 )\r
390{\r
391 UINT32 Length;\r
392 UINT16 Width;\r
393 UINTN HexStringBufferLen;\r
394 CHAR16 *StringPtr;\r
395 UINT8 *BufferEnd;\r
396 CHAR16 *StringEnd;\r
397 EFI_STATUS Status;\r
398\r
399 if ((Buffer == NULL) || (BlockConfig == NULL)) {\r
400 return EFI_INVALID_PARAMETER;\r
401 }\r
402\r
403 //\r
404 // Calculate length of AltResp string\r
405 // Format of Default value array is:\r
406 // Array length | 4-bytes\r
407 // Offset | 2-bytes\r
408 // Width | 2-bytes\r
409 // Value | Variable length\r
410 // Offset | 2-bytes\r
411 // Width | 2-bytes\r
412 // Value | Variable length\r
413 // ... ...\r
414 // When value is 1 byte in length, overhead of AltResp string will be maximum,\r
415 // BlockConfig ::= <&OFFSET=1234&WIDTH=1234&VALUE=12>+\r
416 // | 8 | 4 | 7 | 4 | 7 |2|\r
417 // so the maximum length of BlockConfig could be calculated as:\r
418 // (ArrayLength / 5) * (8 + 4 + 7 + 4 + 7 + 2) = ArrayLength * 6.4 < ArrayLength * 7\r
419 //\r
420 CopyMem (&Length, Buffer, sizeof (UINT32));\r
421 BufferEnd = Buffer + Length;\r
422 StringPtr = AllocatePool (Length * 7 * sizeof (CHAR16));\r
423 *BlockConfig = StringPtr;\r
424 if (StringPtr == NULL) {\r
425 return EFI_OUT_OF_RESOURCES;\r
426 }\r
427 StringEnd = StringPtr + (Length * 7);\r
428\r
429 Buffer += sizeof (UINT32);\r
430 while (Buffer < BufferEnd) {\r
431 StrCpy (StringPtr, L"&OFFSET=");\r
432 StringPtr += 8;\r
433\r
434 HexStringBufferLen = 5;\r
435 BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));\r
436 Buffer += sizeof (UINT16);\r
437 StringPtr += 4;\r
438\r
439 StrCpy (StringPtr, L"&WIDTH=");\r
440 StringPtr += 7;\r
441\r
442 HexStringBufferLen = 5;\r
443 BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));\r
444 CopyMem (&Width, Buffer, sizeof (UINT16));\r
445 Buffer += sizeof (UINT16);\r
446 StringPtr += 4;\r
447\r
448 StrCpy (StringPtr, L"&VALUE=");\r
449 StringPtr += 7;\r
450\r
451 HexStringBufferLen = StringEnd - StringPtr;\r
452 Status = BufToHexString (StringPtr, &HexStringBufferLen, Buffer, Width);\r
453 if (EFI_ERROR (Status)) {\r
454 return Status;\r
455 }\r
456 Buffer += Width;\r
457 StringPtr += (Width * 2);\r
458 }\r
459\r
460 return EFI_SUCCESS;\r
461}\r
462\r
463/**\r
464 Construct <ConfigAltResp> for a buffer storage.\r
465\r
466 @param ConfigRequest The Config request string. If set to NULL, all the\r
467 configurable elements will be extracted from BlockNameArray.\r
468 @param ConfigAltResp The returned <ConfigAltResp>.\r
469 @param Progress On return, points to a character in the Request.\r
470 @param Guid GUID of the buffer storage.\r
471 @param Name Name of the buffer storage.\r
472 @param DriverHandle The DriverHandle which is used to invoke HiiDatabase\r
473 protocol interface NewPackageList().\r
474 @param BufferStorage Content of the buffer storage.\r
475 @param BufferStorageSize Length in bytes of the buffer storage.\r
476 @param BlockNameArray Array generated by VFR compiler.\r
477 @param NumberAltCfg Number of Default value array generated by VFR compiler.\r
478 The sequential input parameters will be number of\r
479 AltCfgId and DefaultValueArray pairs. When set to 0,\r
480 there will be no <AltResp>.\r
481\r
482 retval EFI_OUT_OF_RESOURCES Run out of memory resource.\r
483 retval EFI_INVALID_PARAMETER ConfigAltResp is NULL.\r
484 retval EFI_SUCCESS Operation successful.\r
485\r
486**/\r
487EFI_STATUS\r
488ConstructConfigAltResp (\r
489 IN EFI_STRING ConfigRequest, OPTIONAL\r
490 OUT EFI_STRING *Progress,\r
491 OUT EFI_STRING *ConfigAltResp,\r
492 IN EFI_GUID *Guid,\r
493 IN CHAR16 *Name,\r
494 IN EFI_HANDLE *DriverHandle,\r
495 IN VOID *BufferStorage,\r
496 IN UINTN BufferStorageSize,\r
497 IN VOID *BlockNameArray, OPTIONAL\r
498 IN UINTN NumberAltCfg,\r
499 ...\r
500//IN UINT16 AltCfgId,\r
501//IN VOID *DefaultValueArray,\r
502 )\r
503{\r
504 EFI_STATUS Status;\r
505 CHAR16 *ConfigHdr;\r
506 CHAR16 *BlockName;\r
507 CHAR16 *DescHdr;\r
508 CHAR16 *StringPtr;\r
509 CHAR16 **AltCfg;\r
510 UINT16 AltCfgId;\r
511 VOID *DefaultValueArray;\r
512 UINTN StrBufferLen;\r
513 EFI_STRING ConfigResp;\r
514 EFI_STRING TempStr;\r
515 VA_LIST Args;\r
516 UINTN AltRespLen;\r
517 UINTN Index;\r
518 BOOLEAN NeedFreeConfigRequest;\r
519 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;\r
520 UINTN Len;\r
521\r
522 if (ConfigAltResp == NULL) {\r
523 return EFI_INVALID_PARAMETER;\r
524 }\r
525\r
526 //\r
527 // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..."\r
528 //\r
529 ConfigHdr = NULL;\r
530 StrBufferLen = 0;\r
531 Status = ConstructConfigHdr (\r
532 ConfigHdr,\r
533 &StrBufferLen,\r
534 Guid,\r
535 Name,\r
536 DriverHandle\r
537 );\r
538 if (Status == EFI_BUFFER_TOO_SMALL) {\r
539 ConfigHdr = AllocateZeroPool (StrBufferLen);\r
540 Status = ConstructConfigHdr (\r
541 ConfigHdr,\r
542 &StrBufferLen,\r
543 Guid,\r
544 Name,\r
545 DriverHandle\r
546 );\r
547 }\r
548\r
549 if (EFI_ERROR (Status)) {\r
550 return Status;\r
551 }\r
552\r
553 //\r
554 // Construct <ConfigResp>\r
555 //\r
556 NeedFreeConfigRequest = FALSE;\r
557 if (ConfigRequest == NULL) {\r
558 //\r
559 // If ConfigRequest is set to NULL, export all configurable elements in BlockNameArray\r
560 //\r
561 Status = ExtractBlockName (BlockNameArray, &BlockName);\r
562 if (EFI_ERROR (Status)) {\r
563 return Status;\r
564 }\r
565 \r
566 Len = StrSize (ConfigHdr);\r
567 ConfigRequest = AllocateZeroPool (Len + StrSize (BlockName) - sizeof (CHAR16));\r
568 StrCpy (ConfigRequest, ConfigHdr);\r
569 StrCat (ConfigRequest, BlockName);\r
570 NeedFreeConfigRequest = TRUE;\r
571 }\r
572\r
573 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);\r
574 if (EFI_ERROR (Status)) {\r
575 return Status;\r
576 }\r
577\r
578 Status = HiiConfigRouting->BlockToConfig (\r
579 HiiConfigRouting,\r
580 ConfigRequest,\r
581 BufferStorage,\r
582 BufferStorageSize,\r
583 &ConfigResp,\r
584 (Progress == NULL) ? &TempStr : Progress\r
585 );\r
586 if (EFI_ERROR (Status)) {\r
587 return Status;\r
588 }\r
589\r
590 //\r
591 // Construct <AltResp>\r
592 //\r
593 DescHdr = AllocateZeroPool (NumberAltCfg * 16 * sizeof (CHAR16));\r
594 StringPtr = DescHdr;\r
595 AltCfg = AllocateZeroPool (NumberAltCfg * sizeof (CHAR16 *));\r
596 AltRespLen = 0;\r
597 VA_START (Args, NumberAltCfg);\r
598 for (Index = 0; Index < NumberAltCfg; Index++) {\r
599 AltCfgId = (UINT16) VA_ARG (Args, UINT16);\r
600 DefaultValueArray = (UINT8 *) VA_ARG (Args, VOID *);\r
601\r
602 //\r
603 // '&' <ConfigHdr>\r
604 //\r
605 AltRespLen += (StrLen (ConfigHdr) + 1);\r
606\r
607 StringPtr = DescHdr + Index * 16;\r
608 StrCpy (StringPtr, L"&ALTCFG=");\r
609 AltRespLen += (8 + sizeof (UINT16) * 2);\r
610\r
611 StrBufferLen = 5;\r
612 BufToHexString (StringPtr + 8, &StrBufferLen, (UINT8 *) &AltCfgId, sizeof (UINT16));\r
613 Status = ExtractBlockConfig (DefaultValueArray, &AltCfg[Index]);\r
614 if (EFI_ERROR (Status)) {\r
615 return Status;\r
616 }\r
617 AltRespLen += StrLen (AltCfg[Index]);\r
618 }\r
619 VA_END (Args);\r
620\r
621 //\r
622 // Generate the final <ConfigAltResp>\r
623 //\r
624 StrBufferLen = (StrLen ((CHAR16 *) ConfigResp) + AltRespLen + 1) * sizeof (CHAR16);\r
625 TempStr = AllocateZeroPool (StrBufferLen);\r
626 *ConfigAltResp = TempStr;\r
627 if (TempStr == NULL) {\r
628 return EFI_OUT_OF_RESOURCES;\r
629 }\r
630\r
631 //\r
632 // <ConfigAltResp> ::= <ConfigResp> ['&' <AltResp>]*\r
633 //\r
634 StrCpy (TempStr, ConfigResp);\r
635 for (Index = 0; Index < NumberAltCfg; Index++) {\r
636 StrCat (TempStr, L"&");\r
637 StrCat (TempStr, ConfigHdr);\r
638 StrCat (TempStr, DescHdr + Index * 16);\r
639 StrCat (TempStr, AltCfg[Index]);\r
640\r
fca1cc71 641 FreePool (AltCfg[Index]);\r
08e4b3cf 642 }\r
643\r
644 if (NeedFreeConfigRequest) {\r
fca1cc71 645 FreePool (ConfigRequest);\r
08e4b3cf 646 }\r
fca1cc71 647 FreePool (ConfigHdr);\r
648 FreePool (ConfigResp);\r
649 FreePool (DescHdr);\r
650 FreePool (AltCfg);\r
08e4b3cf 651\r
652 return EFI_SUCCESS;\r
653}\r
654\r
655/**\r
656 Swap bytes in the buffer. This is a internal function.\r
657\r
658 @param Buffer Binary buffer.\r
659 @param BufferSize Size of the buffer in bytes.\r
660\r
661 @return None.\r
662\r
663**/\r
664VOID\r
665SwapBuffer (\r
666 IN OUT UINT8 *Buffer,\r
667 IN UINTN BufferSize\r
668 )\r
669{\r
670 UINTN Index;\r
671 UINT8 Temp;\r
672 UINTN SwapCount;\r
673\r
674 SwapCount = BufferSize / 2;\r
675 for (Index = 0; Index < SwapCount; Index++) {\r
676 Temp = Buffer[Index];\r
677 Buffer[Index] = Buffer[BufferSize - 1 - Index];\r
678 Buffer[BufferSize - 1 - Index] = Temp;\r
679 }\r
680}\r
681\r
682/**\r
683 Converts the unicode character of the string from uppercase to lowercase.\r
684 This is a internal function.\r
685\r
686 @param Str String to be converted\r
687\r
688**/\r
689VOID\r
690EFIAPI\r
691ToLower (\r
692 IN OUT CHAR16 *Str\r
693 )\r
694{\r
695 CHAR16 *Ptr;\r
696 \r
697 for (Ptr = Str; *Ptr != L'\0'; Ptr++) {\r
698 if (*Ptr >= L'A' && *Ptr <= L'Z') {\r
699 *Ptr = (CHAR16) (*Ptr - L'A' + L'a');\r
700 }\r
701 }\r
702}\r
703\r
704\r
705/**\r
706 Converts binary buffer to Unicode string in reversed byte order from BufToHexString().\r
707\r
708 @param Str String for output\r
709 @param Buffer Binary buffer.\r
710 @param BufferSize Size of the buffer in bytes.\r
711\r
712 @retval EFI_SUCCESS The function completed successfully.\r
713 @retval EFI_OUT_OF_RESOURCES There is no enough available memory space.\r
714\r
715**/\r
716EFI_STATUS\r
717EFIAPI\r
718BufInReverseOrderToHexString (\r
719 IN OUT CHAR16 *Str,\r
720 IN UINT8 *Buffer,\r
721 IN UINTN BufferSize\r
722 )\r
723{\r
724 EFI_STATUS Status;\r
725 UINT8 *NewBuffer;\r
726 UINTN StrBufferLen;\r
727\r
728 NewBuffer = AllocateCopyPool (BufferSize, Buffer);\r
729 if (NewBuffer == NULL) {\r
730 return EFI_OUT_OF_RESOURCES;\r
731 }\r
732 SwapBuffer (NewBuffer, BufferSize);\r
733\r
734 StrBufferLen = BufferSize * sizeof (CHAR16) + 1;\r
735 Status = BufToHexString (Str, &StrBufferLen, NewBuffer, BufferSize);\r
736\r
737 FreePool (NewBuffer);\r
738 //\r
739 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.\r
740 //\r
741 ToLower (Str);\r
742\r
743 return Status;\r
744}\r
745\r
746\r
747/**\r
748 Converts Hex String to binary buffer in reversed byte order from HexStringToBuf().\r
749\r
750 @param Buffer Pointer to buffer that receives the data.\r
751 @param BufferSize Length in bytes of the buffer to hold converted\r
752 data. If routine return with EFI_SUCCESS,\r
753 containing length of converted data. If routine\r
754 return with EFI_BUFFER_TOO_SMALL, containg length\r
755 of buffer desired.\r
756 @param Str String to be converted from.\r
757\r
758 @retval EFI_SUCCESS The function completed successfully.\r
759 @retval RETURN_BUFFER_TOO_SMALL The input BufferSize is too small to hold the output. BufferSize\r
760 will be updated to the size required for the converstion.\r
761\r
762**/\r
763EFI_STATUS\r
764EFIAPI\r
765HexStringToBufInReverseOrder (\r
766 IN OUT UINT8 *Buffer,\r
767 IN OUT UINTN *BufferSize,\r
768 IN CHAR16 *Str\r
769 )\r
770{\r
771 EFI_STATUS Status;\r
772 UINTN ConvertedStrLen;\r
773\r
774 ConvertedStrLen = 0;\r
775 Status = HexStringToBuf (Buffer, BufferSize, Str, &ConvertedStrLen);\r
776 if (!EFI_ERROR (Status)) {\r
777 SwapBuffer (Buffer, (ConvertedStrLen + 1) / 2);\r
778 }\r
779\r
780 return Status;\r
781}\r
782\r
783/**\r
784 Convert binary representation Config string (e.g. "0041004200430044") to the\r
785 original string (e.g. "ABCD"). Config string appears in <ConfigHdr> (i.e.\r
786 "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").\r
787\r
788 @param UnicodeString Original Unicode string.\r
789 @param StrBufferLen On input: Length in bytes of buffer to hold the Unicode string.\r
790 Includes tailing '\0' character.\r
791 On output:\r
792 If return EFI_SUCCESS, containing length of Unicode string buffer.\r
793 If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.\r
794 @param ConfigString Binary representation of Unicode String, <string> := (<HexCh>4)+\r
795\r
796 @retval EFI_SUCCESS Operation completes successfully.\r
797 @retval EFI_BUFFER_TOO_SMALL The string buffer is too small.\r
798\r
799**/\r
800EFI_STATUS\r
801EFIAPI\r
802ConfigStringToUnicode (\r
803 IN OUT CHAR16 *UnicodeString,\r
804 IN OUT UINTN *StrBufferLen,\r
805 IN CHAR16 *ConfigString\r
806 )\r
807{\r
808 UINTN Index;\r
809 UINTN Len;\r
810 UINTN BufferSize;\r
811 CHAR16 BackupChar;\r
812\r
813 Len = StrLen (ConfigString) / 4;\r
814 BufferSize = (Len + 1) * sizeof (CHAR16);\r
815\r
816 if (*StrBufferLen < BufferSize) {\r
817 *StrBufferLen = BufferSize;\r
818 return EFI_BUFFER_TOO_SMALL;\r
819 }\r
820\r
821 *StrBufferLen = BufferSize;\r
822\r
823 for (Index = 0; Index < Len; Index++) {\r
824 BackupChar = ConfigString[4];\r
825 ConfigString[4] = L'\0';\r
826\r
827 HexStringToBuf ((UINT8 *) UnicodeString, &BufferSize, ConfigString, NULL);\r
828\r
829 ConfigString[4] = BackupChar;\r
830\r
831 ConfigString += 4;\r
832 UnicodeString += 1;\r
833 }\r
834\r
835 //\r
836 // Add tailing '\0' character\r
837 //\r
838 *UnicodeString = L'\0';\r
839\r
840 return EFI_SUCCESS;\r
841}\r
842\r
843/**\r
844 Convert Unicode string to binary representation Config string, e.g.\r
845 "ABCD" => "0041004200430044". Config string appears in <ConfigHdr> (i.e.\r
846 "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").\r
847\r
848 @param ConfigString Binary representation of Unicode String, <string> := (<HexCh>4)+\r
849 @param StrBufferLen On input: Length in bytes of buffer to hold the Unicode string.\r
850 Includes tailing '\0' character.\r
851 On output:\r
852 If return EFI_SUCCESS, containing length of Unicode string buffer.\r
853 If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.\r
854 @param UnicodeString Original Unicode string.\r
855\r
856 @retval EFI_SUCCESS Operation completes successfully.\r
857 @retval EFI_BUFFER_TOO_SMALL The string buffer is too small.\r
858\r
859**/\r
860EFI_STATUS\r
861EFIAPI\r
862UnicodeToConfigString (\r
863 IN OUT CHAR16 *ConfigString,\r
864 IN OUT UINTN *StrBufferLen,\r
865 IN CHAR16 *UnicodeString\r
866 )\r
867{\r
868 UINTN Index;\r
869 UINTN Len;\r
870 UINTN BufferSize;\r
871 CHAR16 *String;\r
872\r
873 Len = StrLen (UnicodeString);\r
874 BufferSize = (Len * 4 + 1) * sizeof (CHAR16);\r
875\r
876 if (*StrBufferLen < BufferSize) {\r
877 *StrBufferLen = BufferSize;\r
878 return EFI_BUFFER_TOO_SMALL;\r
879 }\r
880\r
881 *StrBufferLen = BufferSize;\r
882 String = ConfigString;\r
883\r
884 for (Index = 0; Index < Len; Index++) {\r
885 BufToHexString (ConfigString, &BufferSize, (UINT8 *) UnicodeString, 2);\r
886\r
887 ConfigString += 4;\r
888 UnicodeString += 1;\r
889 }\r
890\r
891 //\r
892 // Add tailing '\0' character\r
893 //\r
894 *ConfigString = L'\0';\r
895\r
896 //\r
897 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.\r
898 //\r
899 ToLower (String); \r
900 return EFI_SUCCESS;\r
901}\r
902\r
903/**\r
904 Construct <ConfigHdr> using routing information GUID/NAME/PATH.\r
905\r
906 @param ConfigHdr Pointer to the ConfigHdr string.\r
907 @param StrBufferLen On input: Length in bytes of buffer to hold the\r
908 ConfigHdr string. Includes tailing '\0' character.\r
909 On output: If return EFI_SUCCESS, containing\r
910 length of ConfigHdr string buffer. If return\r
911 EFI_BUFFER_TOO_SMALL, containg length of string\r
912 buffer desired.\r
913 @param Guid Routing information: GUID.\r
914 @param Name Routing information: NAME.\r
915 @param DriverHandle Driver handle which contains the routing\r
916 information: PATH.\r
917\r
918 @retval EFI_SUCCESS Operation completes successfully.\r
919 @retval EFI_BUFFER_TOO_SMALL The ConfigHdr string buffer is too small.\r
920\r
921**/\r
922EFI_STATUS\r
923EFIAPI\r
924ConstructConfigHdr (\r
925 IN OUT CHAR16 *ConfigHdr,\r
926 IN OUT UINTN *StrBufferLen,\r
927 IN CONST EFI_GUID *Guid,\r
928 IN CHAR16 *Name, OPTIONAL\r
929 IN EFI_HANDLE *DriverHandle\r
930 )\r
931{\r
932 EFI_STATUS Status;\r
933 UINTN NameStrLen;\r
934 UINTN DevicePathSize;\r
935 UINTN BufferSize;\r
936 CHAR16 *StrPtr;\r
937 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
938\r
939 if (Name == NULL) {\r
940 //\r
941 // There will be no "NAME" in <ConfigHdr> for Name/Value storage\r
942 //\r
943 NameStrLen = 0;\r
944 } else {\r
945 //\r
946 // For buffer storage\r
947 //\r
948 NameStrLen = StrLen (Name);\r
949 }\r
950\r
951 //\r
952 // Retrieve DevicePath Protocol associated with this HiiPackageList\r
953 //\r
954 Status = gBS->HandleProtocol (\r
955 DriverHandle,\r
956 &gEfiDevicePathProtocolGuid,\r
957 (VOID **) &DevicePath\r
958 );\r
959 if (EFI_ERROR (Status)) {\r
960 return Status;\r
961 }\r
962\r
963 DevicePathSize = GetDevicePathSize (DevicePath);\r
964\r
965 //\r
966 // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>\r
967 // | 5 | 32 | 6 | NameStrLen*4 | 6 | DevicePathStrLen | 1 |\r
968 //\r
969 BufferSize = (5 + 32 + 6 + NameStrLen * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16);\r
970 if (*StrBufferLen < BufferSize) {\r
971 *StrBufferLen = BufferSize;\r
972 return EFI_BUFFER_TOO_SMALL;\r
973 }\r
974\r
975 *StrBufferLen = BufferSize;\r
976\r
977 StrPtr = ConfigHdr;\r
978\r
979 StrCpy (StrPtr, L"GUID=");\r
980 StrPtr += 5;\r
981 BufInReverseOrderToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID));\r
982 StrPtr += 32;\r
983\r
984 //\r
985 // Convert name string, e.g. name "ABCD" => "&NAME=0041004200430044"\r
986 //\r
987 StrCpy (StrPtr, L"&NAME=");\r
988 StrPtr += 6;\r
989 if (Name != NULL) {\r
990 BufferSize = (NameStrLen * 4 + 1) * sizeof (CHAR16);\r
991 UnicodeToConfigString (StrPtr, &BufferSize, Name);\r
992 StrPtr += (NameStrLen * 4);\r
993 }\r
994\r
995 StrCpy (StrPtr, L"&PATH=");\r
996 StrPtr += 6;\r
997 BufInReverseOrderToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize);\r
998\r
999 return EFI_SUCCESS;\r
1000}\r
1001\r
1002/**\r
1003 Determines if the Routing data (Guid and Name) is correct in <ConfigHdr>.\r
1004\r
1005 @param ConfigString Either <ConfigRequest> or <ConfigResp>.\r
1006 @param StorageGuid GUID of the storage.\r
1007 @param StorageName Name of the stoarge.\r
1008\r
1009 @retval TRUE Routing information is correct in ConfigString.\r
1010 @retval FALSE Routing information is incorrect in ConfigString.\r
1011\r
1012**/\r
1013BOOLEAN\r
1014IsConfigHdrMatch (\r
1015 IN EFI_STRING ConfigString,\r
1016 IN EFI_GUID *StorageGuid, OPTIONAL\r
1017 IN CHAR16 *StorageName OPTIONAL\r
1018 )\r
1019{\r
1020 EFI_STATUS Status;\r
1021 BOOLEAN Match;\r
1022 EFI_GUID Guid;\r
1023 CHAR16 *Name;\r
1024 CHAR16 *StrPtr;\r
1025 UINTN BufferSize;\r
1026\r
1027 //\r
1028 // <ConfigHdr> ::=\r
1029 // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>\r
1030 // | 5 | 32 | 6 | NameStrLen*4 | 6 | DevicePathStrLen | 1 |\r
1031 //\r
1032 if (StrLen (ConfigString) <= (5 + 32 + 6)) {\r
1033 return FALSE;\r
1034 }\r
1035\r
1036 //\r
1037 // Compare GUID\r
1038 //\r
1039 if (StorageGuid != NULL) {\r
1040\r
1041 StrPtr = ConfigString + 5 + 32;\r
1042 if (*StrPtr != L'&') {\r
1043 return FALSE;\r
1044 }\r
1045 *StrPtr = L'\0';\r
1046\r
1047 BufferSize = sizeof (EFI_GUID);\r
1048 Status = HexStringToBufInReverseOrder (\r
1049 (UINT8 *) &Guid,\r
1050 &BufferSize,\r
1051 ConfigString + 5\r
1052 );\r
1053 *StrPtr = L'&';\r
1054\r
1055 if (EFI_ERROR (Status)) {\r
1056 return FALSE;\r
1057 }\r
1058\r
1059 if (!CompareGuid (&Guid, StorageGuid)) {\r
1060 return FALSE;\r
1061 }\r
1062 }\r
1063\r
1064 //\r
1065 // Compare Name\r
1066 //\r
1067 Match = TRUE;\r
1068 if (StorageName != NULL) {\r
1069 StrPtr = ConfigString + 5 + 32 + 6;\r
1070 while (*StrPtr != L'\0' && *StrPtr != L'&') {\r
1071 StrPtr++;\r
1072 }\r
1073 if (*StrPtr != L'&') {\r
1074 return FALSE;\r
1075 }\r
1076\r
1077 *StrPtr = L'\0';\r
1078 BufferSize = (((UINTN) StrPtr) - ((UINTN) &ConfigString[5 + 32 + 6])) / 4 + sizeof (CHAR16);\r
1079 Name = AllocatePool (BufferSize);\r
1080 ASSERT (Name != NULL);\r
1081 Status = ConfigStringToUnicode (\r
1082 Name,\r
1083 &BufferSize,\r
1084 ConfigString + 5 + 32 + 6\r
1085 );\r
1086 *StrPtr = L'&';\r
1087\r
1088 if (EFI_ERROR (Status) || (StrCmp (Name, StorageName) != 0)) {\r
1089 Match = FALSE;\r
1090 }\r
fca1cc71 1091 FreePool (Name);\r
08e4b3cf 1092 }\r
1093\r
1094 return Match;\r
1095}\r
1096\r
1097/**\r
1098 Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.\r
1099\r
1100 @param String The string to be searched in.\r
1101 @param Offset Offset in BlockName.\r
1102 @param Width Width in BlockName.\r
1103\r
1104 @retval TRUE Block name found.\r
1105 @retval FALSE Block name not found.\r
1106\r
1107**/\r
1108BOOLEAN\r
1109EFIAPI\r
1110FindBlockName (\r
1111 IN OUT CHAR16 *String,\r
1112 IN UINTN Offset,\r
1113 IN UINTN Width\r
1114 )\r
1115{\r
1116 EFI_STATUS Status;\r
1117 UINTN Data;\r
1118 UINTN BufferSize;\r
1119 UINTN ConvertedStrLen;\r
1120\r
1121 while ((String = StrStr (String, L"&OFFSET=")) != NULL) {\r
1122 //\r
1123 // Skip '&OFFSET='\r
1124 //\r
1125 String = String + 8;\r
1126\r
1127 Data = 0;\r
1128 BufferSize = sizeof (UINTN);\r
1129 Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);\r
1130 if (EFI_ERROR (Status)) {\r
1131 return FALSE;\r
1132 }\r
1133 String = String + ConvertedStrLen;\r
1134\r
1135 if (Data != Offset) {\r
1136 continue;\r
1137 }\r
1138\r
1139 if (StrnCmp (String, L"&WIDTH=", 7) != 0) {\r
1140 return FALSE;\r
1141 }\r
1142 String = String + 7;\r
1143\r
1144 Data = 0;\r
1145 BufferSize = sizeof (UINTN);\r
1146 Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);\r
1147 if (EFI_ERROR (Status)) {\r
1148 return FALSE;\r
1149 }\r
1150 if (Data == Width) {\r
1151 return TRUE;\r
1152 }\r
1153\r
1154 String = String + ConvertedStrLen;\r
1155 }\r
1156\r
1157 return FALSE;\r
1158}\r
1159\r
1160\r
1161/**\r
1162 This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.\r
1163\r
1164 @param VariableGuid An optional field to indicate the target variable\r
1165 GUID name to use.\r
1166 @param VariableName An optional field to indicate the target\r
1167 human-readable variable name.\r
1168 @param BufferSize On input: Length in bytes of buffer to hold\r
1169 retrived data. On output: If return\r
1170 EFI_BUFFER_TOO_SMALL, containg length of buffer\r
1171 desired.\r
1172 @param Buffer Buffer to hold retrived data.\r
1173\r
1174 @retval EFI_SUCCESS Operation completes successfully.\r
1175 @retval EFI_BUFFER_TOO_SMALL The intput buffer is too small.\r
1176 @retval EFI_OUT_OF_RESOURCES There is no enough available memory space.\r
1177\r
1178**/\r
1179EFI_STATUS\r
1180EFIAPI\r
1181GetBrowserData (\r
1182 IN CONST EFI_GUID *VariableGuid, OPTIONAL\r
1183 IN CONST CHAR16 *VariableName, OPTIONAL\r
1184 IN OUT UINTN *BufferSize,\r
1185 IN OUT UINT8 *Buffer\r
1186 )\r
1187{\r
1188 EFI_STATUS Status;\r
1189 CONST CHAR16 *ConfigHdr;\r
1190 CHAR16 *ConfigResp;\r
1191 CHAR16 *StringPtr;\r
1192 UINTN HeaderLen;\r
1193 UINTN BufferLen;\r
1194 CHAR16 *Progress;\r
1195\r
1196 //\r
1197 // Locate protocols for use\r
1198 //\r
1199 Status = LocateFormBrowser2Protocols ();\r
1200 if (EFI_ERROR (Status)) {\r
1201 return Status;\r
1202 }\r
1203\r
1204 //\r
1205 // Retrive formset storage data from Form Browser\r
1206 //\r
1207 ConfigHdr = mFakeConfigHdr;\r
1208 HeaderLen = StrLen (ConfigHdr);\r
1209 \r
1210 //\r
1211 // First try allocate 0x4000 buffer for the formet storage data.\r
1212 //\r
1213 BufferLen = 0x4000;\r
1214 ConfigResp = AllocateZeroPool (BufferLen + HeaderLen);\r
1215 if (ConfigResp == NULL) {\r
1216 BufferLen = 0;\r
1217 }\r
1218\r
1219 StringPtr = ConfigResp + HeaderLen;\r
1220 *StringPtr = L'&';\r
1221 StringPtr++;\r
1222\r
1223 Status = mFormBrowser2->BrowserCallback (\r
1224 mFormBrowser2,\r
1225 &BufferLen,\r
1226 StringPtr,\r
1227 TRUE,\r
1228 VariableGuid,\r
1229 VariableName\r
1230 );\r
1231 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1232 if (ConfigResp != NULL) {\r
1233 FreePool (ConfigResp);\r
1234 }\r
1235\r
1236 ConfigResp = AllocateZeroPool (BufferLen + HeaderLen);\r
1237 if (ConfigResp == NULL) {\r
1238 return EFI_OUT_OF_RESOURCES;\r
1239 }\r
1240\r
1241 StringPtr = ConfigResp + HeaderLen;\r
1242 *StringPtr = L'&';\r
1243 StringPtr++;\r
1244\r
1245 Status = mFormBrowser2->BrowserCallback (\r
1246 mFormBrowser2,\r
1247 &BufferLen,\r
1248 StringPtr,\r
1249 TRUE,\r
1250 VariableGuid,\r
1251 VariableName\r
1252 );\r
1253 }\r
1254 if (EFI_ERROR (Status)) {\r
1255 FreePool (ConfigResp);\r
1256 return Status;\r
1257 }\r
1258 CopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16));\r
1259\r
1260 //\r
1261 // Convert <ConfigResp> to buffer data\r
1262 //\r
1263 Status = mIfrSupportLibHiiConfigRouting->ConfigToBlock (\r
1264 mIfrSupportLibHiiConfigRouting,\r
1265 ConfigResp,\r
1266 Buffer,\r
1267 BufferSize,\r
1268 &Progress\r
1269 );\r
1270 FreePool (ConfigResp);\r
1271\r
1272 return Status;\r
1273}\r
1274\r
1275\r
1276/**\r
1277 This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.\r
1278\r
1279 @param VariableGuid An optional field to indicate the target variable\r
1280 GUID name to use.\r
1281 @param VariableName An optional field to indicate the target\r
1282 human-readable variable name.\r
1283 @param BufferSize Length in bytes of buffer to hold retrived data.\r
1284 @param Buffer Buffer to hold retrived data.\r
1285 @param RequestElement An optional field to specify which part of the\r
1286 buffer data will be send back to Browser. If NULL,\r
1287 the whole buffer of data will be committed to\r
1288 Browser. <RequestElement> ::=\r
1289 &OFFSET=<Number>&WIDTH=<Number>*\r
1290\r
1291 @retval EFI_SUCCESS Operation completes successfully.\r
1292 @retval EFI_OUT_OF_RESOURCES There is no enough available memory space.\r
1293 @retval Other Updating Browser uncommitted data failed.\r
1294\r
1295**/\r
1296EFI_STATUS\r
1297EFIAPI\r
1298SetBrowserData (\r
1299 IN CONST EFI_GUID *VariableGuid, OPTIONAL\r
1300 IN CONST CHAR16 *VariableName, OPTIONAL\r
1301 IN UINTN BufferSize,\r
1302 IN CONST UINT8 *Buffer,\r
1303 IN CONST CHAR16 *RequestElement OPTIONAL\r
1304 )\r
1305{\r
1306 EFI_STATUS Status;\r
1307 CONST CHAR16 *ConfigHdr;\r
1308 CHAR16 *ConfigResp;\r
1309 CHAR16 *StringPtr;\r
1310 UINTN HeaderLen;\r
1311 UINTN BufferLen;\r
1312 CHAR16 *Progress;\r
1313 CHAR16 BlockName[33];\r
1314 CHAR16 *ConfigRequest;\r
1315 CONST CHAR16 *Request;\r
1316\r
1317 //\r
1318 // Locate protocols for use\r
1319 //\r
1320 Status = LocateFormBrowser2Protocols ();\r
1321 if (EFI_ERROR (Status)) {\r
1322 return Status;\r
1323 }\r
1324\r
1325 //\r
1326 // Prepare <ConfigRequest>\r
1327 //\r
1328 ConfigHdr = mFakeConfigHdr;\r
1329 HeaderLen = StrLen (ConfigHdr);\r
1330\r
1331 if (RequestElement == NULL) {\r
1332 //\r
1333 // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>\r
1334 //\r
1335 BlockName[0] = L'\0';\r
1336 StrCpy (BlockName, L"&OFFSET=0&WIDTH=");\r
1337\r
1338 //\r
1339 // String lenghth of L"&OFFSET=0&WIDTH=" is 16\r
1340 //\r
1341 StringPtr = BlockName + 16;\r
1342 BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16));\r
1343 BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN));\r
1344\r
1345 Request = BlockName;\r
1346 } else {\r
1347 Request = RequestElement;\r
1348 }\r
1349\r
1350 BufferLen = HeaderLen * sizeof (CHAR16) + StrSize (Request);\r
1351 ConfigRequest = AllocateZeroPool (BufferLen);\r
1352 if (ConfigRequest == NULL) {\r
1353 return EFI_OUT_OF_RESOURCES;\r
1354 }\r
1355\r
1356 CopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16));\r
1357 StringPtr = ConfigRequest + HeaderLen;\r
1358 StrCpy (StringPtr, Request);\r
1359\r
1360 //\r
1361 // Convert buffer to <ConfigResp>\r
1362 //\r
1363 Status = mIfrSupportLibHiiConfigRouting->BlockToConfig (\r
1364 mIfrSupportLibHiiConfigRouting,\r
1365 ConfigRequest,\r
1366 Buffer,\r
1367 BufferSize,\r
1368 &ConfigResp,\r
1369 &Progress\r
1370 );\r
1371 if (EFI_ERROR (Status)) {\r
1372 FreePool (ConfigRequest);\r
1373 return Status;\r
1374 }\r
1375\r
1376 //\r
1377 // Skip <ConfigHdr> and '&'\r
1378 //\r
1379 StringPtr = ConfigResp + HeaderLen + 1;\r
1380\r
1381 //\r
1382 // Change uncommitted data in Browser\r
1383 //\r
1384 Status = mFormBrowser2->BrowserCallback (\r
1385 mFormBrowser2,\r
1386 &BufferSize,\r
1387 StringPtr,\r
1388 FALSE,\r
1389 VariableGuid,\r
1390 VariableName\r
1391 );\r
1392 FreePool (ConfigRequest);\r
1393 return Status;\r
1394}\r
ac7e320c
LG
1395\r
1396/**\r
1397 Test if a Unicode character is a hexadecimal digit. If true, the input\r
1398 Unicode character is converted to a byte. \r
1399\r
1400 This function tests if a Unicode character is a hexadecimal digit. If true, the input\r
1401 Unicode character is converted to a byte. For example, Unicode character\r
1402 L'A' will be converted to 0x0A. \r
1403\r
1404 If Digit is NULL, then ASSERT.\r
1405\r
1406 @param Digit The output hexadecimal digit.\r
1407\r
1408 @param Char The input Unicode character.\r
1409\r
1410 @retval TRUE Char is in the range of Hexadecimal number. Digit is updated\r
1411 to the byte value of the number.\r
1412 @retval FALSE Char is not in the range of Hexadecimal number. Digit is keep\r
1413 intact.\r
1414\r
1415**/\r
1416BOOLEAN\r
1417EFIAPI\r
1418IsHexDigit (\r
1419 OUT UINT8 *Digit,\r
1420 IN CHAR16 Char\r
1421 )\r
1422{\r
1423 ASSERT (Digit != NULL);\r
1424 \r
1425 if ((Char >= L'0') && (Char <= L'9')) {\r
1426 *Digit = (UINT8) (Char - L'0');\r
1427 return TRUE;\r
1428 }\r
1429\r
1430 if ((Char >= L'A') && (Char <= L'F')) {\r
1431 *Digit = (UINT8) (Char - L'A' + 0x0A);\r
1432 return TRUE;\r
1433 }\r
1434\r
1435 if ((Char >= L'a') && (Char <= L'f')) {\r
1436 *Digit = (UINT8) (Char - L'a' + 0x0A);\r
1437 return TRUE;\r
1438 }\r
1439\r
1440 return FALSE;\r
1441}\r
1442\r
1443/** \r
1444 Convert binary buffer to a Unicode String in a specified sequence. \r
1445\r
1446 This function converts bytes in the memory block pointed by Buffer to a Unicode String Str. \r
1447 Each byte will be represented by two Unicode characters. For example, byte 0xA1 will \r
1448 be converted into two Unicode character L'A' and L'1'. In the output String, the Unicode Character \r
1449 for the Most Significant Nibble will be put before the Unicode Character for the Least Significant\r
1450 Nibble. The output string for the buffer containing a single byte 0xA1 will be L"A1". \r
1451 For a buffer with multiple bytes, the Unicode character produced by the first byte will be put into the \r
1452 the last character in the output string. The one next to first byte will be put into the\r
1453 character before the last character. This rules applies to the rest of the bytes. The Unicode\r
1454 character by the last byte will be put into the first character in the output string. For example,\r
1455 the input buffer for a 64-bits unsigned integer 0x12345678abcdef1234 will be converted to\r
1456 a Unicode string equal to L"12345678abcdef1234".\r
1457\r
1458 @param String On input, String is pointed to the buffer allocated for the convertion.\r
1459 @param StringLen The Length of String buffer to hold the output String. The length must include the tailing '\0' character.\r
1460 The StringLen required to convert a N bytes Buffer will be a least equal to or greater \r
1461 than 2*N + 1.\r
1462 @param Buffer The pointer to a input buffer.\r
1463 @param BufferSizeInBytes Length in bytes of the input buffer.\r
1464\r
1465\r
1466 @retval EFI_SUCCESS The convertion is successful. All bytes in Buffer has been convert to the corresponding\r
1467 Unicode character and placed into the right place in String.\r
1468 @retval EFI_BUFFER_TOO_SMALL StringSizeInBytes is smaller than 2 * N + 1the number of bytes required to\r
1469 complete the convertion. \r
1470**/\r
1471RETURN_STATUS\r
1472EFIAPI\r
1473BufToHexString (\r
1474 IN OUT CHAR16 *String,\r
1475 IN OUT UINTN *StringLen,\r
1476 IN CONST UINT8 *Buffer,\r
1477 IN UINTN BufferSizeInBytes\r
1478 )\r
1479{\r
1480 UINTN Idx;\r
1481 UINT8 Byte;\r
1482 UINTN StrLen;\r
1483\r
1484 //\r
1485 // Make sure string is either passed or allocate enough.\r
1486 // It takes 2 Unicode characters (4 bytes) to represent 1 byte of the binary buffer.\r
1487 // Plus the Unicode termination character.\r
1488 //\r
1489 StrLen = BufferSizeInBytes * 2;\r
1490 if (StrLen > ((*StringLen) - 1)) {\r
1491 *StringLen = StrLen + 1;\r
1492 return RETURN_BUFFER_TOO_SMALL;\r
1493 }\r
1494\r
1495 *StringLen = StrLen + 1;\r
1496 //\r
1497 // Ends the string.\r
1498 //\r
1499 String[StrLen] = L'\0'; \r
1500\r
1501 for (Idx = 0; Idx < BufferSizeInBytes; Idx++) {\r
1502 Byte = Buffer[Idx];\r
1503 String[StrLen - 1 - Idx * 2] = mIfrSupportLibHexStr [Byte & 0xF];\r
1504 String[StrLen - 2 - Idx * 2] = mIfrSupportLibHexStr [Byte >> 4];\r
1505 }\r
1506\r
1507 return RETURN_SUCCESS;\r
1508}\r
1509\r
1510\r
1511/**\r
1512 Convert a Unicode string consisting of hexadecimal characters to a output byte buffer.\r
1513\r
1514 This function converts a Unicode string consisting of characters in the range of Hexadecimal\r
1515 character (L'0' to L'9', L'A' to L'F' and L'a' to L'f') to a output byte buffer. The function will stop\r
1516 at the first non-hexadecimal character or the NULL character. The convertion process can be\r
1517 simply viewed as the reverse operations defined by BufToHexString. Two Unicode characters will be \r
1518 converted into one byte. The first Unicode character represents the Most Significant Nibble and the\r
1519 second Unicode character represents the Least Significant Nibble in the output byte. \r
1520 The first pair of Unicode characters represents the last byte in the output buffer. The second pair of Unicode \r
1521 characters represent the the byte preceding the last byte. This rule applies to the rest pairs of bytes. \r
1522 The last pair represent the first byte in the output buffer. \r
1523\r
1524 For example, a Unciode String L"12345678" will be converted into a buffer wil the following bytes \r
1525 (first byte is the byte in the lowest memory address): "0x78, 0x56, 0x34, 0x12".\r
1526\r
1527 If String has N valid hexadecimal characters for conversion, the caller must make sure Buffer is at least \r
1528 N/2 (if N is even) or (N+1)/2 (if N if odd) bytes. \r
1529\r
1530 @param Buffer The output buffer allocated by the caller.\r
1531 @param BufferSizeInBytes On input, the size in bytes of Buffer. On output, it is updated to \r
1532 contain the size of the Buffer which is actually used for the converstion.\r
1533 For Unicode string with 2*N hexadecimal characters (not including the \r
1534 tailing NULL character), N bytes of Buffer will be used for the output.\r
1535 @param String The input hexadecimal string.\r
1536 @param ConvertedStrLen The number of hexadecimal characters used to produce content in output\r
1537 buffer Buffer.\r
1538\r
1539 @retval RETURN_BUFFER_TOO_SMALL The input BufferSizeInBytes is too small to hold the output. BufferSizeInBytes\r
1540 will be updated to the size required for the converstion.\r
1541 @retval RETURN_SUCCESS The convertion is successful or the first Unicode character from String\r
1542 is hexadecimal. If ConvertedStrLen is not NULL, it is updated\r
1543 to the number of hexadecimal character used for the converstion.\r
1544**/\r
1545RETURN_STATUS\r
1546EFIAPI\r
1547HexStringToBuf (\r
1548 OUT UINT8 *Buffer, \r
1549 IN OUT UINTN *BufferSizeInBytes,\r
1550 IN CONST CHAR16 *String,\r
1551 OUT UINTN *ConvertedStrLen OPTIONAL\r
1552 )\r
1553{\r
1554 UINTN HexCnt;\r
1555 UINTN Idx;\r
1556 UINTN BufferLength;\r
1557 UINT8 Digit;\r
1558 UINT8 Byte;\r
1559\r
1560 //\r
1561 // Find out how many hex characters the string has.\r
1562 //\r
1563 for (Idx = 0, HexCnt = 0; IsHexDigit (&Digit, String[Idx]); Idx++, HexCnt++);\r
1564\r
1565 if (HexCnt == 0) {\r
1566 *ConvertedStrLen = 0;\r
1567 return RETURN_SUCCESS;\r
1568 }\r
1569 //\r
1570 // Two Unicode characters make up 1 buffer byte. Round up.\r
1571 //\r
1572 BufferLength = (HexCnt + 1) / 2; \r
1573\r
1574 //\r
1575 // Test if buffer is passed enough.\r
1576 //\r
1577 if (BufferLength > (*BufferSizeInBytes)) {\r
1578 *BufferSizeInBytes = BufferLength;\r
1579 return RETURN_BUFFER_TOO_SMALL;\r
1580 }\r
1581\r
1582 *BufferSizeInBytes = BufferLength;\r
1583\r
1584 for (Idx = 0; Idx < HexCnt; Idx++) {\r
1585\r
1586 IsHexDigit (&Digit, String[HexCnt - 1 - Idx]);\r
1587\r
1588 //\r
1589 // For odd charaters, write the lower nibble for each buffer byte,\r
1590 // and for even characters, the upper nibble.\r
1591 //\r
1592 if ((Idx & 1) == 0) {\r
1593 Byte = Digit;\r
1594 } else {\r
1595 Byte = Buffer[Idx / 2];\r
1596 Byte &= 0x0F;\r
1597 Byte = (UINT8) (Byte | Digit << 4);\r
1598 }\r
1599\r
1600 Buffer[Idx / 2] = Byte;\r
1601 }\r
1602\r
1603 if (ConvertedStrLen != NULL) {\r
1604 *ConvertedStrLen = HexCnt;\r
1605 }\r
1606\r
1607 return RETURN_SUCCESS;\r
1608}\r