2934ab383acf67d6f959209e213df7237df00a94
[efi/edk2/.git] / edk2 / MdeModulePkg / Universal / HiiDatabaseDxe / ConfigRouting.c
1 /** @file\r
2 Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.\r
3 \r
4 Copyright (c) 2007 - 2010, Intel Corporation\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution.  The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 **/\r
14 \r
15 \r
16 #include "HiiDatabase.h"\r
17 extern HII_DATABASE_PRIVATE_DATA mPrivate;\r
18 \r
19 /**\r
20   Calculate the number of Unicode characters of the incoming Configuration string,\r
21   not including NULL terminator.\r
22 \r
23   This is a internal function.\r
24 \r
25   @param  String                 String in <MultiConfigRequest> or\r
26                                  <MultiConfigResp> format.\r
27 \r
28   @return The number of Unicode characters.\r
29 \r
30 **/\r
31 UINTN\r
32 CalculateConfigStringLen (\r
33   IN EFI_STRING                    String\r
34   )\r
35 {\r
36   EFI_STRING  TmpPtr;\r
37 \r
38   //\r
39   // "GUID=" should be the first element of incoming string.\r
40   //\r
41   ASSERT (String != NULL);\r
42   ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);\r
43 \r
44   //\r
45   // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".\r
46   // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.\r
47   // \r
48   TmpPtr = StrStr (String, L"&GUID=");\r
49   if (TmpPtr == NULL) {\r
50     return StrLen (String);\r
51   }\r
52 \r
53   return (TmpPtr - String);\r
54 }\r
55 \r
56 \r
57 /**\r
58   Convert the hex UNICODE %02x encoding of a UEFI device path to binary\r
59   from <PathHdr> of <ConfigHdr>.\r
60 \r
61   This is a internal function.\r
62 \r
63   @param  String                 UEFI configuration string\r
64   @param  DevicePathData         Binary of a UEFI device path.\r
65 \r
66   @retval EFI_NOT_FOUND          The device path is not invalid.\r
67   @retval EFI_INVALID_PARAMETER  Any incoming parameter is invalid.\r
68   @retval EFI_OUT_OF_RESOURCES   Lake of resources to store neccesary structures.\r
69   @retval EFI_SUCCESS            The device path is retrieved and translated to\r
70                                  binary format.\r
71 \r
72 **/\r
73 EFI_STATUS\r
74 GetDevicePath (\r
75   IN  EFI_STRING                   String,\r
76   OUT UINT8                        **DevicePathData\r
77   )\r
78 {\r
79   UINTN                    Length;\r
80   EFI_STRING               PathHdr;\r
81   UINT8                    *DevicePathBuffer;\r
82   CHAR16                   TemStr[2];\r
83   UINTN                    Index;\r
84   UINT8                    DigitUint8;\r
85   EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
86 \r
87 \r
88   if (String == NULL || DevicePathData == NULL) {\r
89     return EFI_INVALID_PARAMETER;\r
90   }\r
91 \r
92   //\r
93   // Find the 'PATH=' of <PathHdr> and skip it.\r
94   //\r
95   for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);\r
96   if (*String == 0) {\r
97     return EFI_INVALID_PARAMETER;\r
98   }\r
99   //\r
100   // Check whether path data does exist.\r
101   //\r
102   String += StrLen (L"PATH=");\r
103   if (*String == 0) {\r
104     return EFI_INVALID_PARAMETER;\r
105   }\r
106   PathHdr = String;\r
107 \r
108   //\r
109   // The content between 'PATH=' of <ConfigHdr> and '&' of next element\r
110   // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding\r
111   // of UEFI device path.\r
112   //\r
113   for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);\r
114   //\r
115   // Check DevicePath Length\r
116   //\r
117   if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {\r
118     return EFI_NOT_FOUND;\r
119   }\r
120   \r
121   //\r
122   // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order\r
123   // as the device path resides in RAM memory.\r
124   // Translate the data into binary.\r
125   //\r
126   DevicePathBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);\r
127   if (DevicePathBuffer == NULL) {\r
128     return EFI_OUT_OF_RESOURCES;\r
129   }\r
130   \r
131   //\r
132   // Convert DevicePath\r
133   //\r
134   ZeroMem (TemStr, sizeof (TemStr));\r
135   for (Index = 0; Index < Length; Index ++) {\r
136     TemStr[0] = PathHdr[Index];\r
137     DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
138     if ((Index & 1) == 0) {\r
139       DevicePathBuffer [Index/2] = DigitUint8;\r
140     } else {\r
141       DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);\r
142     }\r
143   }\r
144   \r
145   //\r
146   // Validate DevicePath\r
147   //\r
148   DevicePath  = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathBuffer;\r
149   while (!IsDevicePathEnd (DevicePath)) {\r
150     if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) {\r
151       //\r
152       // Invalid device path\r
153       //\r
154       FreePool (DevicePathBuffer);\r
155       return EFI_NOT_FOUND;\r
156     }\r
157     DevicePath = NextDevicePathNode (DevicePath);\r
158   }\r
159 \r
160   //\r
161   // return the device path\r
162   //\r
163   *DevicePathData = DevicePathBuffer;\r
164   return EFI_SUCCESS;\r
165 }\r
166 \r
167 /**\r
168   Converts the unicode character of the string from uppercase to lowercase.\r
169   This is a internal function.\r
170 \r
171   @param ConfigString  String to be converted\r
172 \r
173 **/\r
174 VOID\r
175 EFIAPI\r
176 HiiToLower (\r
177   IN EFI_STRING  ConfigString\r
178   )\r
179 {\r
180   EFI_STRING  String;\r
181   BOOLEAN     Lower;\r
182 \r
183   ASSERT (ConfigString != NULL);\r
184 \r
185   //\r
186   // Convert all hex digits in range [A-F] in the configuration header to [a-f]\r
187   //\r
188   for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {\r
189     if (*String == L'=') {\r
190       Lower = TRUE;\r
191     } else if (*String == L'&') {\r
192       Lower = FALSE;\r
193     } else if (Lower && *String >= L'A' && *String <= L'F') {\r
194       *String = (CHAR16) (*String - L'A' + L'a');\r
195     }\r
196   }\r
197 \r
198   return;\r
199 }\r
200 \r
201 /**\r
202   Generate a sub string then output it.\r
203 \r
204   This is a internal function.\r
205 \r
206   @param  String                 A constant string which is the prefix of the to be\r
207                                  generated string, e.g. GUID=\r
208 \r
209   @param  BufferLen              The length of the Buffer in bytes.\r
210 \r
211   @param  Buffer                 Points to a buffer which will be converted to be the \r
212                                  content of the generated string.\r
213 \r
214   @param  Flag                   If 1, the buffer contains data for the value of GUID or PATH stored in \r
215                                  UINT8 *; if 2, the buffer contains unicode string for the value of NAME;\r
216                                  if 3, the buffer contains other data.\r
217 \r
218   @param  SubStr                 Points to the output string. It's caller's\r
219                                  responsibility to free this buffer.\r
220 \r
221 \r
222 **/\r
223 VOID\r
224 GenerateSubStr (\r
225   IN CONST EFI_STRING              String,\r
226   IN  UINTN                        BufferLen,\r
227   IN  VOID                         *Buffer,\r
228   IN  UINT8                        Flag,\r
229   OUT EFI_STRING                   *SubStr\r
230   )\r
231 {\r
232   UINTN       Length;\r
233   EFI_STRING  Str;\r
234   EFI_STRING  StringHeader;\r
235   CHAR16      *TemString;\r
236   CHAR16      *TemName;\r
237   UINT8       *TemBuffer;\r
238   UINTN       Index;\r
239 \r
240   ASSERT (String != NULL && SubStr != NULL);\r
241 \r
242   if (Buffer == NULL) {\r
243     *SubStr = AllocateCopyPool (StrSize (String), String);\r
244     ASSERT (*SubStr != NULL);\r
245     return ;\r
246   }\r
247   \r
248   //\r
249   // Header + Data + '&' + '\0'\r
250   //\r
251   Length = StrLen (String) + BufferLen * 2 + 1 + 1;\r
252   Str    = AllocateZeroPool (Length * sizeof (CHAR16));\r
253   ASSERT (Str != NULL);\r
254 \r
255   StrCpy (Str, String);\r
256   Length = (BufferLen * 2 + 1) * sizeof (CHAR16);\r
257 \r
258   StringHeader = Str + StrLen (String);\r
259   TemString    = (CHAR16 *) StringHeader;\r
260 \r
261   switch (Flag) {\r
262   case 1:\r
263     //\r
264     // Convert Buffer to Hex String in reverse order\r
265     //\r
266     TemBuffer = ((UINT8 *) Buffer);\r
267     for (Index = 0; Index < BufferLen; Index ++, TemBuffer ++) {\r
268       TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
269     }\r
270     break;\r
271   case 2:\r
272     //\r
273     // Check buffer is enough\r
274     //\r
275     TemName = (CHAR16 *) Buffer;\r
276     ASSERT ((BufferLen * 2 + 1) >= (StrLen (TemName) * 4 + 1));\r
277     //\r
278     // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"\r
279     //\r
280     for (; *TemName != L'\0'; TemName++) {\r
281       TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);\r
282     }\r
283     break;\r
284   case 3:\r
285     //\r
286     // Convert Buffer to Hex String\r
287     //\r
288     TemBuffer = ((UINT8 *) Buffer) + BufferLen - 1;\r
289     for (Index = 0; Index < BufferLen; Index ++, TemBuffer --) {\r
290       TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
291     }\r
292     break;\r
293   default:\r
294     break;\r
295   }\r
296 \r
297   //\r
298   // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.\r
299   //\r
300   StrCat (Str, L"&");  \r
301   HiiToLower (Str);\r
302 \r
303   *SubStr = Str;\r
304 }\r
305 \r
306 \r
307 /**\r
308   Retrieve the <ConfigBody> from String then output it.\r
309 \r
310   This is a internal function.\r
311 \r
312   @param  String                 A sub string of a configuration string in\r
313                                  <MultiConfigAltResp> format.\r
314   @param  ConfigBody             Points to the output string. It's caller's\r
315                                  responsibility to free this buffer.\r
316 \r
317   @retval EFI_INVALID_PARAMETER  There is no form package in current hii database.\r
318   @retval EFI_OUT_OF_RESOURCES   Not enough memory to finish this operation.\r
319   @retval EFI_SUCCESS            All existing storage is exported.\r
320 \r
321 **/\r
322 EFI_STATUS\r
323 OutputConfigBody (\r
324   IN  EFI_STRING                   String,\r
325   OUT EFI_STRING                   *ConfigBody\r
326   )\r
327 {\r
328   EFI_STRING  TmpPtr;\r
329   EFI_STRING  Result;\r
330   UINTN       Length;\r
331 \r
332   if (String == NULL || ConfigBody == NULL) {\r
333     return EFI_INVALID_PARAMETER;\r
334   }\r
335   \r
336   //\r
337   // The setting information should start OFFSET, not ALTCFG.\r
338   //\r
339   if (StrnCmp (String, L"&ALTCFG=", StrLen (L"&ALTCFG=")) == 0) {\r
340     return EFI_INVALID_PARAMETER;\r
341   }\r
342 \r
343   TmpPtr = StrStr (String, L"GUID=");\r
344   if (TmpPtr == NULL) {\r
345     //\r
346     // It is the last <ConfigResp> of the incoming configuration string.\r
347     //\r
348     Result = AllocateCopyPool (StrSize (String), String);\r
349     if (Result == NULL) {\r
350       return EFI_OUT_OF_RESOURCES;\r
351     } else {\r
352       *ConfigBody = Result;\r
353       return EFI_SUCCESS;\r
354     }\r
355   }\r
356 \r
357   Length = TmpPtr - String;\r
358   Result = AllocateCopyPool (Length * sizeof (CHAR16), String);\r
359   if (Result == NULL) {\r
360     return EFI_OUT_OF_RESOURCES;\r
361   }\r
362 \r
363   *(Result + Length - 1) = 0;\r
364   *ConfigBody = Result;\r
365   return EFI_SUCCESS;\r
366 }\r
367 \r
368 /**\r
369   Append a string to a multi-string format.\r
370 \r
371   This is a internal function.\r
372 \r
373   @param  MultiString            String in <MultiConfigRequest>,\r
374                                  <MultiConfigAltResp>, or <MultiConfigResp>. On\r
375                                  input, the buffer length of  this string is\r
376                                  MAX_STRING_LENGTH. On output, the  buffer length\r
377                                  might be updated.\r
378   @param  AppendString           NULL-terminated Unicode string.\r
379 \r
380   @retval EFI_INVALID_PARAMETER  Any incoming parameter is invalid.\r
381   @retval EFI_SUCCESS            AppendString is append to the end of MultiString\r
382 \r
383 **/\r
384 EFI_STATUS\r
385 AppendToMultiString (\r
386   IN OUT EFI_STRING                *MultiString,\r
387   IN EFI_STRING                    AppendString\r
388   )\r
389 {\r
390   UINTN AppendStringSize;\r
391   UINTN MultiStringSize;\r
392 \r
393   if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {\r
394     return EFI_INVALID_PARAMETER;\r
395   }\r
396 \r
397   AppendStringSize = StrSize (AppendString);\r
398   MultiStringSize  = StrSize (*MultiString);\r
399 \r
400   //\r
401   // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.\r
402   //\r
403   if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||\r
404       MultiStringSize > MAX_STRING_LENGTH) {\r
405     *MultiString = (EFI_STRING) ReallocatePool (\r
406                                   MultiStringSize,\r
407                                   MultiStringSize + AppendStringSize,\r
408                                   (VOID *) (*MultiString)\r
409                                   );\r
410     ASSERT (*MultiString != NULL);\r
411   }\r
412   //\r
413   // Append the incoming string\r
414   //\r
415   StrCat (*MultiString, AppendString);\r
416 \r
417   return EFI_SUCCESS;\r
418 }\r
419 \r
420 \r
421 /**\r
422   Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET\r
423   or WIDTH or VALUE.\r
424   <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>\r
425 \r
426   This is a internal function.\r
427 \r
428   @param  StringPtr              String in <BlockConfig> format and points to the\r
429                                  first character of <Number>.\r
430   @param  Number                 The output value. Caller takes the responsibility\r
431                                  to free memory.\r
432   @param  Len                    Length of the <Number>, in characters.\r
433 \r
434   @retval EFI_OUT_OF_RESOURCES   Insufficient resources to store neccessary\r
435                                  structures.\r
436   @retval EFI_SUCCESS            Value of <Number> is outputted in Number\r
437                                  successfully.\r
438 \r
439 **/\r
440 EFI_STATUS\r
441 GetValueOfNumber (\r
442   IN EFI_STRING                    StringPtr,\r
443   OUT UINT8                        **Number,\r
444   OUT UINTN                        *Len\r
445   )\r
446 {\r
447   EFI_STRING               TmpPtr;\r
448   UINTN                    Length;\r
449   EFI_STRING               Str;\r
450   UINT8                    *Buf;\r
451   EFI_STATUS               Status;\r
452   UINT8                    DigitUint8;\r
453   UINTN                    Index;\r
454   CHAR16                   TemStr[2];\r
455 \r
456   ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);\r
457   ASSERT (*StringPtr != L'\0');\r
458 \r
459   Buf = NULL;\r
460 \r
461   TmpPtr = StringPtr;\r
462   while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
463     StringPtr++;\r
464   }\r
465   *Len   = StringPtr - TmpPtr;\r
466   Length = *Len + 1;\r
467 \r
468   Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));\r
469   if (Str == NULL) {\r
470     Status = EFI_OUT_OF_RESOURCES;\r
471     goto Exit;\r
472   }\r
473   CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));\r
474   *(Str + *Len) = L'\0';\r
475 \r
476   Length = (Length + 1) / 2;\r
477   Buf = (UINT8 *) AllocateZeroPool (Length);\r
478   if (Buf == NULL) {\r
479     Status = EFI_OUT_OF_RESOURCES;\r
480     goto Exit;\r
481   }\r
482   \r
483   Length = *Len;\r
484   ZeroMem (TemStr, sizeof (TemStr));\r
485   for (Index = 0; Index < Length; Index ++) {\r
486     TemStr[0] = Str[Length - Index - 1];\r
487     DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
488     if ((Index & 1) == 0) {\r
489       Buf [Index/2] = DigitUint8;\r
490     } else {\r
491       Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);\r
492     }\r
493   }\r
494 \r
495   *Number = Buf;\r
496   Status  = EFI_SUCCESS;\r
497 \r
498 Exit:\r
499   if (Str != NULL) {\r
500     FreePool (Str);\r
501   }\r
502 \r
503   return Status;\r
504 }\r
505 \r
506 /**\r
507   This function merges DefaultAltCfgResp string into AltCfgResp string for\r
508   the missing AltCfgId in AltCfgResq.\r
509 \r
510   @param  AltCfgResp             Pointer to a null-terminated Unicode string in\r
511                                  <ConfigAltResp> format. The default value string \r
512                                  will be merged into it. \r
513   @param  DefaultAltCfgResp      Pointer to a null-terminated Unicode string in\r
514                                  <MultiConfigAltResp> format. The default value \r
515                                  string may contain more than one ConfigAltResp\r
516                                  string for the different varstore buffer.\r
517 \r
518   @retval EFI_SUCCESS            The merged string returns.\r
519   @retval EFI_INVALID_PARAMETER  *AltCfgResp is to NULL.\r
520 **/\r
521 EFI_STATUS\r
522 EFIAPI\r
523 MergeDefaultString (\r
524   IN OUT EFI_STRING  *AltCfgResp,\r
525   IN     EFI_STRING  DefaultAltCfgResp\r
526   )\r
527 {\r
528   EFI_STRING   StringPtrDefault;\r
529   EFI_STRING   StringPtrEnd;\r
530   CHAR16       TempChar;\r
531   EFI_STRING   StringPtr;\r
532   EFI_STRING   AltConfigHdr;\r
533   UINTN        HeaderLength;\r
534   UINTN        SizeAltCfgResp;\r
535   \r
536   if (*AltCfgResp == NULL) {\r
537     return EFI_INVALID_PARAMETER;\r
538   }\r
539   \r
540   //\r
541   // Get the requestr ConfigHdr\r
542   //\r
543   SizeAltCfgResp  = 0;\r
544   StringPtr       = *AltCfgResp;\r
545   \r
546   //\r
547   // Find <ConfigHdr> GUID=...&NAME=...&PATH=...\r
548   //\r
549   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
550     return EFI_INVALID_PARAMETER;\r
551   }\r
552   while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {\r
553     StringPtr++;\r
554   }\r
555   while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {\r
556     StringPtr++;\r
557   }\r
558   if (*StringPtr == L'\0') {\r
559     return EFI_INVALID_PARAMETER;\r
560   }\r
561   StringPtr += StrLen (L"&PATH=");\r
562   while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
563     StringPtr ++;\r
564   }\r
565   HeaderLength = StringPtr - *AltCfgResp;\r
566 \r
567   //\r
568   // Construct AltConfigHdr string  "&<ConfigHdr>&ALTCFG=XXXX\0"\r
569   //                                  |1| StrLen (ConfigHdr) | 8 | 4 | 1 |\r
570   //\r
571   AltConfigHdr = AllocateZeroPool ((1 + HeaderLength + 8 + 4 + 1) * sizeof (CHAR16));\r
572   if (AltConfigHdr == NULL) {\r
573     return EFI_OUT_OF_RESOURCES;\r
574   }\r
575   StrCpy (AltConfigHdr, L"&");\r
576   StrnCat (AltConfigHdr, *AltCfgResp, HeaderLength);\r
577   StrCat (AltConfigHdr, L"&ALTCFG=");\r
578   HeaderLength = StrLen (AltConfigHdr);\r
579   \r
580   StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr);\r
581   while (StringPtrDefault != NULL) {\r
582     //\r
583     // Get AltCfg Name\r
584     //\r
585     StrnCat (AltConfigHdr, StringPtrDefault + HeaderLength, 4);\r
586     StringPtr = StrStr (*AltCfgResp, AltConfigHdr); \r
587     \r
588     //\r
589     // Append the found default value string to the input AltCfgResp\r
590     // \r
591     if (StringPtr == NULL) {\r
592       StringPtrEnd   = StrStr (StringPtrDefault + 1, L"&GUID");\r
593       SizeAltCfgResp = StrSize (*AltCfgResp);\r
594       if (StringPtrEnd == NULL) {\r
595         //\r
596         // No more default string is found.\r
597         //\r
598         *AltCfgResp    = (EFI_STRING) ReallocatePool (\r
599                                      SizeAltCfgResp,\r
600                                      SizeAltCfgResp + StrSize (StringPtrDefault),\r
601                                      (VOID *) (*AltCfgResp)\r
602                                      );\r
603         if (*AltCfgResp == NULL) {\r
604           FreePool (AltConfigHdr);\r
605           return EFI_OUT_OF_RESOURCES;\r
606         }\r
607         StrCat (*AltCfgResp, StringPtrDefault);\r
608         break;\r
609       } else {\r
610         TempChar = *StringPtrEnd;\r
611         *StringPtrEnd = L'\0';\r
612         *AltCfgResp = (EFI_STRING) ReallocatePool (\r
613                                      SizeAltCfgResp,\r
614                                      SizeAltCfgResp + StrSize (StringPtrDefault),\r
615                                      (VOID *) (*AltCfgResp)\r
616                                      );\r
617         if (*AltCfgResp == NULL) {\r
618           FreePool (AltConfigHdr);\r
619           return EFI_OUT_OF_RESOURCES;\r
620         }\r
621         StrCat (*AltCfgResp, StringPtrDefault);\r
622         *StringPtrEnd = TempChar;\r
623       }\r
624     }\r
625     \r
626     //\r
627     // Find next AltCfg String\r
628     //\r
629     *(AltConfigHdr + HeaderLength) = L'\0';\r
630     StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr);    \r
631   }\r
632   \r
633   FreePool (AltConfigHdr);\r
634   return EFI_SUCCESS;  \r
635 }\r
636 \r
637 /**\r
638   This function finds the matched DefaultName for the input DefaultId\r
639 \r
640   @param  DefaultIdArray    Array stores the map table between DefaultId and DefaultName.\r
641   @param  VarDefaultId      Default Id\r
642   @param  VarDefaultName    Default Name string ID for the input default ID.\r
643   \r
644   @retval EFI_SUCCESS       The mapped default name string ID is found.\r
645   @retval EFI_NOT_FOUND     The mapped default name string ID is not found.\r
646 **/\r
647 EFI_STATUS\r
648 FindDefaultName (\r
649   IN  IFR_DEFAULT_DATA *DefaultIdArray, \r
650   IN  UINT16           VarDefaultId, \r
651   OUT EFI_STRING_ID    *VarDefaultName\r
652   )\r
653 {\r
654   LIST_ENTRY        *Link;\r
655   IFR_DEFAULT_DATA  *DefaultData;\r
656 \r
657   for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {\r
658     DefaultData = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);\r
659     if (DefaultData->DefaultId == VarDefaultId) {\r
660       *VarDefaultName = DefaultData->DefaultName;\r
661       return EFI_SUCCESS;\r
662     }\r
663   }\r
664   \r
665   return EFI_NOT_FOUND;\r
666 }\r
667 \r
668 /**\r
669   This function inserts new DefaultValueData into the BlockData DefaultValue array.\r
670 \r
671   @param  BlockData         The BlockData is updated to add new default value.\r
672   @param  DefaultValueData  The DefaultValue is added.\r
673 \r
674 **/\r
675 VOID\r
676 InsertDefaultValue (\r
677   IN IFR_BLOCK_DATA         *BlockData,\r
678   IN IFR_DEFAULT_DATA       *DefaultValueData\r
679   )\r
680 {\r
681   LIST_ENTRY             *Link;\r
682   IFR_DEFAULT_DATA       *DefaultValueArray;\r
683 \r
684   for (Link = BlockData->DefaultValueEntry.ForwardLink; Link != &BlockData->DefaultValueEntry; Link = Link->ForwardLink) {\r
685     DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);\r
686     if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) {\r
687       if (DefaultValueData->OpCode == EFI_IFR_DEFAULT_OP) {\r
688         //\r
689         // Update the default value array in BlockData.\r
690         //\r
691         DefaultValueArray->Value = DefaultValueData->Value;\r
692       } else if (DefaultValueArray->OpCode != EFI_IFR_DEFAULT_OP) {\r
693         //\r
694         // Update the default value array in BlockData.\r
695         //\r
696         DefaultValueArray->Value = DefaultValueData->Value;\r
697       }\r
698       FreePool (DefaultValueData);\r
699       return;\r
700     } else if (DefaultValueArray->DefaultId > DefaultValueData->DefaultId) {\r
701       //\r
702       // Insert new default value data in the front of this default value array.\r
703       //\r
704       InsertTailList (Link, &DefaultValueData->Entry);\r
705       return;\r
706     }\r
707   }\r
708 \r
709   //\r
710   // Insert new default value data in tail.\r
711   //\r
712   InsertTailList (Link, &DefaultValueData->Entry);\r
713   return;\r
714 }\r
715 \r
716 /**\r
717   This function inserts new BlockData into the block link\r
718 \r
719   @param  BlockLink   The list entry points to block array.\r
720   @param  BlockData   The point to BlockData is added.\r
721   \r
722 **/\r
723 VOID\r
724 InsertBlockData (\r
725   IN LIST_ENTRY        *BlockLink,\r
726   IN IFR_BLOCK_DATA    **BlockData\r
727   )\r
728 {\r
729   LIST_ENTRY      *Link;\r
730   IFR_BLOCK_DATA  *BlockArray;\r
731   IFR_BLOCK_DATA  *BlockSingleData;\r
732 \r
733   BlockSingleData = *BlockData;\r
734   \r
735   //\r
736   // Insert block data in its Offset and Width order.\r
737   //\r
738   for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {\r
739     BlockArray = BASE_CR (Link, IFR_BLOCK_DATA, Entry);\r
740     if (BlockArray->Offset == BlockSingleData->Offset) {\r
741       if (BlockArray->Width > BlockSingleData->Width) {\r
742         //\r
743         // Insert this block data in the front of block array\r
744         //\r
745         InsertTailList (Link, &BlockSingleData->Entry);\r
746         return;\r
747       }\r
748 \r
749       if (BlockArray->Width == BlockSingleData->Width) {\r
750         //\r
751         // The same block array has been added.\r
752         //\r
753         FreePool (BlockSingleData);\r
754         *BlockData = BlockArray;\r
755         return;\r
756       }\r
757     } else if (BlockArray->Offset > BlockSingleData->Offset) {\r
758       //\r
759       // Insert new block data in the front of block array \r
760       //\r
761       InsertTailList (Link, &BlockSingleData->Entry);\r
762       return;\r
763     }\r
764   }\r
765   \r
766   //\r
767   // Add new block data into the tail.\r
768   //\r
769   InsertTailList (Link, &BlockSingleData->Entry);\r
770   return;  \r
771 }\r
772 \r
773 /**\r
774   This function checks VarOffset and VarWidth is in the block range.\r
775 \r
776   @param  RequestBlockArray  The block array is to be checked. \r
777   @param  VarOffset          Offset of var to the structure\r
778   @param  VarWidth           Width of var.\r
779   \r
780   @retval TRUE   This Var is in the block range.\r
781   @retval FALSE  This Var is not in the block range.\r
782 **/\r
783 BOOLEAN\r
784 BlockArrayCheck (\r
785   IN IFR_BLOCK_DATA  *RequestBlockArray,\r
786   IN UINT16          VarOffset,\r
787   IN UINT16          VarWidth\r
788   )\r
789 {\r
790   LIST_ENTRY          *Link;\r
791   IFR_BLOCK_DATA      *BlockData;\r
792   \r
793   //\r
794   // No Request Block array, all vars are got.\r
795   //\r
796   if (RequestBlockArray == NULL) {\r
797     return TRUE;\r
798   }\r
799   \r
800   //\r
801   // Check the input var is in the request block range.\r
802   //\r
803   for (Link = RequestBlockArray->Entry.ForwardLink; Link != &RequestBlockArray->Entry; Link = Link->ForwardLink) {\r
804     BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);\r
805     if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {\r
806       return TRUE;\r
807     }\r
808   }\r
809 \r
810   return FALSE;\r
811 }\r
812 \r
813 /**\r
814   This function parses Form Package to get the block array and the default\r
815   value array according to the request ConfigHdr.\r
816 \r
817   @param  Package               Pointer to the form package data.\r
818   @param  PackageLength         Length of the pacakge.\r
819   @param  ConfigHdr             Request string ConfigHdr. If it is NULL,\r
820                                 the first found varstore will be as ConfigHdr.\r
821   @param  RequestBlockArray     The block array is retrieved from the request string.\r
822   @param  VarStorageData        VarStorage structure contains the got block and default value.\r
823   @param  PIfrDefaultIdArray    Point to the got default id and default name array.\r
824 \r
825   @retval EFI_SUCCESS           The block array and the default value array are got.\r
826   @retval EFI_INVALID_PARAMETER The varstore defintion in the differnt form pacakges\r
827                                 are conflicted. \r
828   @retval EFI_OUT_OF_RESOURCES  No enough memory.\r
829 **/\r
830 EFI_STATUS\r
831 EFIAPI\r
832 ParseIfrData (\r
833   IN     UINT8               *Package,\r
834   IN     UINT32              PackageLength,\r
835   IN     EFI_STRING          ConfigHdr,\r
836   IN     IFR_BLOCK_DATA      *RequestBlockArray,\r
837   IN OUT IFR_VARSTORAGE_DATA *VarStorageData,\r
838   OUT    IFR_DEFAULT_DATA    *DefaultIdArray\r
839   )\r
840 {\r
841   EFI_STATUS               Status;\r
842   UINTN                    IfrOffset;\r
843   EFI_IFR_VARSTORE         *IfrVarStore;\r
844   EFI_IFR_OP_HEADER        *IfrOpHdr;\r
845   EFI_IFR_ONE_OF           *IfrOneOf;\r
846   EFI_IFR_ONE_OF_OPTION    *IfrOneOfOption;\r
847   EFI_IFR_DEFAULT          *IfrDefault;\r
848   EFI_IFR_ORDERED_LIST     *IfrOrderedList;\r
849   EFI_IFR_CHECKBOX         *IfrCheckBox;\r
850   EFI_IFR_PASSWORD         *IfrPassword;\r
851   EFI_IFR_STRING           *IfrString;\r
852   IFR_DEFAULT_DATA         *DefaultData;\r
853   IFR_BLOCK_DATA           *BlockData;\r
854   CHAR16                   *VarStoreName;\r
855   UINT16                   VarOffset;\r
856   UINT16                   VarWidth;\r
857   EFI_STRING_ID            VarDefaultName;\r
858   UINT16                   VarDefaultId;\r
859   EFI_STRING               GuidStr;\r
860   EFI_STRING               NameStr;\r
861   EFI_STRING               TempStr;\r
862   UINTN                    LengthString;\r
863 \r
864   LengthString     = 0;\r
865   Status           = EFI_SUCCESS;\r
866   GuidStr          = NULL;\r
867   NameStr          = NULL;\r
868   TempStr          = NULL;\r
869   BlockData        = NULL;\r
870   DefaultData      = NULL;\r
871   VarDefaultName   = 0;\r
872 \r
873   //\r
874   // Go through the form package to parse OpCode one by one.\r
875   //\r
876   IfrOffset   = sizeof (EFI_HII_PACKAGE_HEADER);\r
877   while (IfrOffset < PackageLength) {\r
878     IfrOpHdr  = (EFI_IFR_OP_HEADER *) (Package + IfrOffset);\r
879 \r
880     switch (IfrOpHdr->OpCode) {\r
881     case EFI_IFR_VARSTORE_OP:\r
882       //\r
883       // VarStore is found. Don't need to search any more.\r
884       //\r
885       if (VarStorageData->Size != 0) {\r
886         break;\r
887       }\r
888 \r
889       //\r
890       // Get the requied varstore information\r
891       // Add varstore by Guid and Name in ConfigHdr\r
892       // Make sure Offset is in varstore size and varstoreid\r
893       //\r
894       IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;\r
895       VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrVarStore->Name) * sizeof (CHAR16));\r
896       if (VarStoreName == NULL) {\r
897         Status = EFI_OUT_OF_RESOURCES;\r
898         goto Done;\r
899       }\r
900       AsciiStrToUnicodeStr ((CHAR8 *) IfrVarStore->Name, VarStoreName);\r
901 \r
902       GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &IfrVarStore->Guid, 1, &GuidStr);\r
903       GenerateSubStr (L"NAME=", StrLen (VarStoreName) * sizeof (CHAR16), (VOID *) VarStoreName, 2, &NameStr);\r
904       LengthString = StrLen (GuidStr);\r
905       LengthString = LengthString + StrLen (NameStr) + 1;\r
906       TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));\r
907     if (TempStr == NULL) {\r
908         FreePool (GuidStr);\r
909         FreePool (NameStr);\r
910         FreePool (VarStoreName);\r
911         Status = EFI_OUT_OF_RESOURCES;\r
912         goto Done;\r
913       }\r
914       StrCpy (TempStr, GuidStr);\r
915       StrCat (TempStr, NameStr);\r
916       if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) {\r
917         //\r
918         // Find the matched VarStore\r
919         //\r
920         CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrVarStore->Guid);\r
921         VarStorageData->VarStoreId = IfrVarStore->VarStoreId;\r
922         VarStorageData->Size       = IfrVarStore->Size;\r
923         VarStorageData->Name       = VarStoreName;\r
924       } else {\r
925         //\r
926         // No found, free the allocated memory \r
927         //\r
928         FreePool (VarStoreName);\r
929       }\r
930       //\r
931       // Free alllocated temp string.\r
932       //\r
933       FreePool (GuidStr);\r
934       FreePool (NameStr);\r
935       FreePool (TempStr);\r
936       break;\r
937 \r
938     case EFI_IFR_DEFAULTSTORE_OP:\r
939       //\r
940       // Add new the map between default id and default name.\r
941       //\r
942       DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));\r
943       if (DefaultData == NULL) {\r
944         Status = EFI_OUT_OF_RESOURCES;\r
945         goto Done;\r
946       }\r
947       DefaultData->DefaultId   = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId;\r
948       DefaultData->DefaultName = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultName;\r
949       InsertTailList (&DefaultIdArray->Entry, &DefaultData->Entry);\r
950       DefaultData = NULL;\r
951       break;\r
952 \r
953     case EFI_IFR_FORM_OP:\r
954     case EFI_IFR_FORM_MAP_OP:\r
955       //\r
956       // No matched varstore is found and directly return.\r
957       //\r
958       if (VarStorageData->Size == 0) {\r
959         Status = EFI_SUCCESS;\r
960         goto Done;\r
961       }\r
962       break;\r
963 \r
964     case EFI_IFR_ONE_OF_OP:\r
965     case EFI_IFR_NUMERIC_OP:\r
966       //\r
967       // Numeric and OneOf has the same opcode structure.\r
968       //\r
969 \r
970       //\r
971       // Numeric and OneOf question is not in IFR Form. This IFR form is not valid. \r
972       //\r
973       if (VarStorageData->Size == 0) {\r
974         Status = EFI_INVALID_PARAMETER;\r
975         goto Done;\r
976       }\r
977       //\r
978       // Check whether this question is for the requested varstore.\r
979       //\r
980       IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;\r
981       if (IfrOneOf->Question.VarStoreId != VarStorageData->VarStoreId) {\r
982         break;\r
983       }\r
984       \r
985       //\r
986       // Get Offset/Width by Question header and OneOf Flags\r
987       //\r
988       VarOffset = IfrOneOf->Question.VarStoreInfo.VarOffset;\r
989       VarWidth  = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));\r
990       //\r
991       // Check whether this question is in requested block array.\r
992       //\r
993       if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {\r
994         //\r
995         // This question is not in the requested string. Skip it.\r
996         //\r
997         break;\r
998       }\r
999 \r
1000       //\r
1001       // Check this var question is in the var storage \r
1002       //\r
1003       if ((VarOffset + VarWidth) > VarStorageData->Size) {\r
1004         Status = EFI_INVALID_PARAMETER;\r
1005         goto Done;\r
1006       }\r
1007       \r
1008       //\r
1009       // Set Block Data\r
1010       //\r
1011       BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));\r
1012       if (BlockData == NULL) {\r
1013         Status = EFI_OUT_OF_RESOURCES;\r
1014         goto Done;\r
1015       }\r
1016       BlockData->Offset     = VarOffset;\r
1017       BlockData->Width      = VarWidth;\r
1018       BlockData->QuestionId = IfrOneOf->Question.QuestionId;\r
1019       BlockData->OpCode     = IfrOpHdr->OpCode;\r
1020       BlockData->Scope      = IfrOpHdr->Scope;\r
1021       InitializeListHead (&BlockData->DefaultValueEntry);\r
1022       //\r
1023       // Add Block Data into VarStorageData BlockEntry\r
1024       //\r
1025       InsertBlockData (&VarStorageData->BlockEntry, &BlockData);\r
1026       break;\r
1027 \r
1028     case EFI_IFR_ORDERED_LIST_OP:\r
1029       //\r
1030       // offset by question header\r
1031       // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type\r
1032       // no default value and default id, how to define its default value?\r
1033       //\r
1034 \r
1035       //\r
1036       // OrderedList question is not in IFR Form. This IFR form is not valid. \r
1037       //\r
1038       if (VarStorageData->Size == 0) {\r
1039         Status = EFI_INVALID_PARAMETER;\r
1040         goto Done;\r
1041       }\r
1042       //\r
1043       // Check whether this question is for the requested varstore.\r
1044       //\r
1045       IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpHdr;\r
1046       if (IfrOrderedList->Question.VarStoreId != VarStorageData->VarStoreId) {\r
1047         BlockData = NULL;\r
1048         break;\r
1049       }\r
1050 \r
1051       //\r
1052       // Get Offset/Width by Question header and OneOf Flags\r
1053       //\r
1054       VarOffset = IfrOrderedList->Question.VarStoreInfo.VarOffset;\r
1055       VarWidth  = IfrOrderedList->MaxContainers;\r
1056       \r
1057       //\r
1058       // Set Block Data\r
1059       //\r
1060       BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));\r
1061       if (BlockData == NULL) {\r
1062         Status = EFI_OUT_OF_RESOURCES;\r
1063         goto Done;\r
1064       }\r
1065       BlockData->Offset     = VarOffset;\r
1066       BlockData->Width      = VarWidth;\r
1067       BlockData->QuestionId = IfrOrderedList->Question.QuestionId;\r
1068       BlockData->OpCode     = IfrOpHdr->OpCode;\r
1069       BlockData->Scope      = IfrOpHdr->Scope;\r
1070       InitializeListHead (&BlockData->DefaultValueEntry);\r
1071       break;\r
1072 \r
1073     case EFI_IFR_CHECKBOX_OP:\r
1074       //\r
1075       // EFI_IFR_DEFAULT_OP\r
1076       // offset by question header\r
1077       // width is 1 sizeof (BOOLEAN)\r
1078       // default id by CheckBox Flags if CheckBox flags (Default or Mau) is set, the default value is 1 to be set.\r
1079       // value by DefaultOption\r
1080       // default id by DeaultOption DefaultId can override CheckBox Flags and Default value.\r
1081       // \r
1082 \r
1083       //\r
1084       // CheckBox question is not in IFR Form. This IFR form is not valid. \r
1085       //\r
1086       if (VarStorageData->Size == 0) {\r
1087         Status = EFI_INVALID_PARAMETER;\r
1088         goto Done;\r
1089       }\r
1090       //\r
1091       // Check whether this question is for the requested varstore.\r
1092       //\r
1093       IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;\r
1094       if (IfrCheckBox->Question.VarStoreId != VarStorageData->VarStoreId) {\r
1095         break;\r
1096       }\r
1097       \r
1098       //\r
1099       // Get Offset/Width by Question header and OneOf Flags\r
1100       //\r
1101       VarOffset = IfrCheckBox->Question.VarStoreInfo.VarOffset;\r
1102       VarWidth  = sizeof (BOOLEAN);\r
1103 \r
1104       //\r
1105       // Check whether this question is in requested block array.\r
1106       //\r
1107       if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {\r
1108         //\r
1109         // This question is not in the requested string. Skip it.\r
1110         //\r
1111         break;\r
1112       }\r
1113 \r
1114       //\r
1115       // Check this var question is in the var storage \r
1116       //\r
1117       if ((VarOffset + VarWidth) > VarStorageData->Size) {\r
1118         Status = EFI_INVALID_PARAMETER;\r
1119         goto Done;\r
1120       }\r
1121       \r
1122       //\r
1123       // Set Block Data\r
1124       //\r
1125       BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));\r
1126       if (BlockData == NULL) {\r
1127         Status = EFI_OUT_OF_RESOURCES;\r
1128         goto Done;\r
1129       }\r
1130       BlockData->Offset     = VarOffset;\r
1131       BlockData->Width      = VarWidth;\r
1132       BlockData->QuestionId = IfrCheckBox->Question.QuestionId;\r
1133       BlockData->OpCode     = IfrOpHdr->OpCode;\r
1134       BlockData->Scope      = IfrOpHdr->Scope;\r
1135       InitializeListHead (&BlockData->DefaultValueEntry);\r
1136       //\r
1137       // Add Block Data into VarStorageData BlockEntry\r
1138       //\r
1139       InsertBlockData (&VarStorageData->BlockEntry, &BlockData);\r
1140       \r
1141       //\r
1142       // Add default value by CheckBox Flags \r
1143       //\r
1144       if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) {\r
1145         //\r
1146         // Set standard ID to Manufacture ID and Get DefaultName String ID\r
1147         //\r
1148         VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;\r
1149         Status       = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);\r
1150         if (EFI_ERROR (Status)) {\r
1151           goto Done;\r
1152         }\r
1153         //\r
1154         // Prepare new DefaultValue\r
1155         //\r
1156         DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));\r
1157         if (DefaultData == NULL) {\r
1158           Status = EFI_OUT_OF_RESOURCES;\r
1159           goto Done;\r
1160         }\r
1161         DefaultData->OpCode      = IfrOpHdr->OpCode;\r
1162         DefaultData->DefaultId   = VarDefaultId;\r
1163         DefaultData->DefaultName = VarDefaultName;\r
1164         DefaultData->Value       = 1;\r
1165         //\r
1166         // Add DefaultValue into current BlockData\r
1167         //\r
1168         InsertDefaultValue (BlockData, DefaultData);\r
1169       }\r
1170 \r
1171       if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) {\r
1172         //\r
1173         // Set standard ID to Manufacture ID and Get DefaultName String ID\r
1174         //\r
1175         VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;\r
1176         Status       = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);\r
1177         if (EFI_ERROR (Status)) {\r
1178           goto Done;\r
1179         }\r
1180         //\r
1181         // Prepare new DefaultValue\r
1182         //\r
1183         DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));\r
1184         if (DefaultData == NULL) {\r
1185           Status = EFI_OUT_OF_RESOURCES;\r
1186           goto Done;\r
1187         }\r
1188         DefaultData->OpCode      = IfrOpHdr->OpCode;\r
1189         DefaultData->DefaultId   = VarDefaultId;\r
1190         DefaultData->DefaultName = VarDefaultName;\r
1191         DefaultData->Value       = 1;\r
1192         //\r
1193         // Add DefaultValue into current BlockData\r
1194         //\r
1195         InsertDefaultValue (BlockData, DefaultData);\r
1196       }\r
1197       break;\r
1198 \r
1199     case EFI_IFR_STRING_OP:\r
1200       //\r
1201       // offset by question header\r
1202       // width MaxSize * sizeof (CHAR16)\r
1203       // no default value, only block array\r
1204       //\r
1205 \r
1206       //\r
1207       // String question is not in IFR Form. This IFR form is not valid. \r
1208       //\r
1209       if (VarStorageData->Size == 0) {\r
1210         Status = EFI_INVALID_PARAMETER;\r
1211         goto Done;\r
1212       }\r
1213       //\r
1214       // Check whether this question is for the requested varstore.\r
1215       //\r
1216       IfrString = (EFI_IFR_STRING *) IfrOpHdr;\r
1217       if (IfrString->Question.VarStoreId != VarStorageData->VarStoreId) {\r
1218         break;\r
1219       }\r
1220       \r
1221       //\r
1222       // Get Offset/Width by Question header and OneOf Flags\r
1223       //\r
1224       VarOffset = IfrString->Question.VarStoreInfo.VarOffset;\r
1225       VarWidth  = (UINT16) (IfrString->MaxSize * sizeof (UINT16));\r
1226 \r
1227       //\r
1228       // Check whether this question is in requested block array.\r
1229       //\r
1230       if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {\r
1231         //\r
1232         // This question is not in the requested string. Skip it.\r
1233         //\r
1234         break;\r
1235       }\r
1236 \r
1237       //\r
1238       // Check this var question is in the var storage \r
1239       //\r
1240       if ((VarOffset + VarWidth) > VarStorageData->Size) {\r
1241         Status = EFI_INVALID_PARAMETER;\r
1242         goto Done;\r
1243       }\r
1244       \r
1245       //\r
1246       // Set Block Data\r
1247       //\r
1248       BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));\r
1249       if (BlockData == NULL) {\r
1250         Status = EFI_OUT_OF_RESOURCES;\r
1251         goto Done;\r
1252       }\r
1253       BlockData->Offset     = VarOffset;\r
1254       BlockData->Width      = VarWidth;\r
1255       BlockData->QuestionId = IfrString->Question.QuestionId;\r
1256       BlockData->OpCode     = IfrOpHdr->OpCode;\r
1257       InitializeListHead (&BlockData->DefaultValueEntry);\r
1258       \r
1259       //\r
1260       // Add Block Data into VarStorageData BlockEntry\r
1261       //\r
1262       InsertBlockData (&VarStorageData->BlockEntry, &BlockData);\r
1263       \r
1264       //\r
1265       // No default value for string.\r
1266       //\r
1267       BlockData = NULL;\r
1268       break;\r
1269 \r
1270     case EFI_IFR_PASSWORD_OP:\r
1271       //\r
1272       // offset by question header\r
1273       // width MaxSize * sizeof (CHAR16)\r
1274       // no default value, only block array\r
1275       //\r
1276 \r
1277       //\r
1278       // Password question is not in IFR Form. This IFR form is not valid. \r
1279       //\r
1280       if (VarStorageData->Size == 0) {\r
1281         Status = EFI_INVALID_PARAMETER;\r
1282         goto Done;\r
1283       }\r
1284       //\r
1285       // Check whether this question is for the requested varstore.\r
1286       //\r
1287       IfrPassword = (EFI_IFR_PASSWORD *) IfrOpHdr;\r
1288       if (IfrPassword->Question.VarStoreId != VarStorageData->VarStoreId) {\r
1289         break;\r
1290       }\r
1291       \r
1292       //\r
1293       // Get Offset/Width by Question header and OneOf Flags\r
1294       //\r
1295       VarOffset = IfrPassword->Question.VarStoreInfo.VarOffset;\r
1296       VarWidth  = (UINT16) (IfrPassword->MaxSize * sizeof (UINT16));\r
1297 \r
1298       //\r
1299       // Check whether this question is in requested block array.\r
1300       //\r
1301       if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {\r
1302         //\r
1303         // This question is not in the requested string. Skip it.\r
1304         //\r
1305         break;\r
1306       }\r
1307 \r
1308       //\r
1309       // Check this var question is in the var storage \r
1310       //\r
1311       if ((VarOffset + VarWidth) > VarStorageData->Size) {\r
1312         Status = EFI_INVALID_PARAMETER;\r
1313         goto Done;\r
1314       }\r
1315       \r
1316       //\r
1317       // Set Block Data\r
1318       //\r
1319       BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));\r
1320       if (BlockData == NULL) {\r
1321         Status = EFI_OUT_OF_RESOURCES;\r
1322         goto Done;\r
1323       }\r
1324       BlockData->Offset     = VarOffset;\r
1325       BlockData->Width      = VarWidth;\r
1326       BlockData->QuestionId = IfrPassword->Question.QuestionId;\r
1327       BlockData->OpCode     = IfrOpHdr->OpCode;\r
1328       InitializeListHead (&BlockData->DefaultValueEntry);\r
1329       \r
1330       //\r
1331       // Add Block Data into VarStorageData BlockEntry\r
1332       //\r
1333       InsertBlockData (&VarStorageData->BlockEntry, &BlockData);\r
1334       \r
1335       //\r
1336       // No default value for string.\r
1337       //\r
1338       BlockData = NULL;\r
1339       break;\r
1340 \r
1341     case EFI_IFR_ONE_OF_OPTION_OP:\r
1342       //\r
1343       // No matched block data is ignored.\r
1344       //\r
1345       if (BlockData == NULL || BlockData->Scope == 0) {\r
1346         break;\r
1347       }\r
1348       \r
1349       IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;\r
1350       if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {\r
1351         //\r
1352         // Get ordered list option data type.\r
1353         //\r
1354         if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN) {\r
1355           VarWidth = 1;\r
1356         } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) {\r
1357           VarWidth = 2;\r
1358         } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) {\r
1359           VarWidth = 4;\r
1360         } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) {\r
1361           VarWidth = 8;\r
1362         } else {\r
1363           //\r
1364           // Invalid ordered list option data type.\r
1365           //\r
1366           Status = EFI_INVALID_PARAMETER;\r
1367           FreePool (BlockData);\r
1368           goto Done;\r
1369         }\r
1370 \r
1371         //\r
1372         // Calculate Ordered list QuestionId width.\r
1373         //\r
1374         BlockData->Width = (UINT16) (BlockData->Width * VarWidth);\r
1375         //\r
1376         // Check whether this question is in requested block array.\r
1377         //\r
1378         if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width)) {\r
1379           //\r
1380           // This question is not in the requested string. Skip it.\r
1381           //\r
1382           FreePool (BlockData);\r
1383           BlockData = NULL;\r
1384           break;\r
1385         }\r
1386         //\r
1387         // Check this var question is in the var storage \r
1388         //\r
1389         if ((BlockData->Offset + BlockData->Width) > VarStorageData->Size) {\r
1390           Status = EFI_INVALID_PARAMETER;\r
1391           FreePool (BlockData);\r
1392           goto Done;\r
1393         }\r
1394         //\r
1395         // Add Block Data into VarStorageData BlockEntry\r
1396         //\r
1397         InsertBlockData (&VarStorageData->BlockEntry, &BlockData);\r
1398         //\r
1399         // No default data for OrderedList.\r
1400         //\r
1401         BlockData = NULL;\r
1402         break;\r
1403       }\r
1404 \r
1405       if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) {\r
1406         //\r
1407         // Set standard ID to Manufacture ID and Get DefaultName String ID\r
1408         //\r
1409         VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;\r
1410         Status       = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);\r
1411         if (EFI_ERROR (Status)) {\r
1412           goto Done;\r
1413         }\r
1414         //\r
1415         // Prepare new DefaultValue\r
1416         //\r
1417         DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));\r
1418         if (DefaultData == NULL) {\r
1419           Status = EFI_OUT_OF_RESOURCES;\r
1420           goto Done;\r
1421         }\r
1422         DefaultData->OpCode      = IfrOpHdr->OpCode;\r
1423         DefaultData->DefaultId   = VarDefaultId;\r
1424         DefaultData->DefaultName = VarDefaultName;\r
1425         DefaultData->Value       = IfrOneOfOption->Value.u64;\r
1426         //\r
1427         // Add DefaultValue into current BlockData\r
1428         //\r
1429         InsertDefaultValue (BlockData, DefaultData);\r
1430       }\r
1431 \r
1432       if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) {\r
1433         //\r
1434         // Set default ID to Manufacture ID and Get DefaultName String ID\r
1435         //\r
1436         VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;\r
1437         Status       = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);\r
1438         if (EFI_ERROR (Status)) {\r
1439           goto Done;\r
1440         }\r
1441         //\r
1442         // Prepare new DefaultValue\r
1443         //\r
1444         DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));\r
1445         if (DefaultData == NULL) {\r
1446           Status = EFI_OUT_OF_RESOURCES;\r
1447           goto Done;\r
1448         }\r
1449         DefaultData->OpCode      = IfrOpHdr->OpCode;\r
1450         DefaultData->DefaultId   = VarDefaultId;\r
1451         DefaultData->DefaultName = VarDefaultName;\r
1452         DefaultData->Value       = IfrOneOfOption->Value.u64;\r
1453         //\r
1454         // Add DefaultValue into current BlockData\r
1455         //\r
1456         InsertDefaultValue (BlockData, DefaultData);\r
1457       }\r
1458       break;\r
1459 \r
1460     case EFI_IFR_DEFAULT_OP:\r
1461       //\r
1462       // Update Current BlockData to the default value.\r
1463       //\r
1464       if (BlockData == NULL || BlockData->Scope == 0) {\r
1465         //\r
1466         // No matched block data is ignored.        \r
1467         //\r
1468         break;\r
1469       }\r
1470 \r
1471       if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {\r
1472         //\r
1473         // OrderedList Opcode is no default value.\r
1474         //\r
1475         break;\r
1476       }\r
1477       //\r
1478       // Get the DefaultId and DefaultName String ID\r
1479       //\r
1480       IfrDefault     = (EFI_IFR_DEFAULT *) IfrOpHdr;\r
1481       VarDefaultId   = IfrDefault->DefaultId;\r
1482       Status       = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);\r
1483       if (EFI_ERROR (Status)) {\r
1484         goto Done;\r
1485       }\r
1486       //\r
1487       // Prepare new DefaultValue\r
1488       //\r
1489       DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));\r
1490       if (DefaultData == NULL) {\r
1491         Status = EFI_OUT_OF_RESOURCES;\r
1492         goto Done;\r
1493       }\r
1494       DefaultData->OpCode      = IfrOpHdr->OpCode;\r
1495       DefaultData->DefaultId   = VarDefaultId;\r
1496       DefaultData->DefaultName = VarDefaultName;\r
1497       DefaultData->Value       = IfrDefault->Value.u64;\r
1498       //\r
1499       // Add DefaultValue into current BlockData\r
1500       //\r
1501       InsertDefaultValue (BlockData, DefaultData);\r
1502       break;\r
1503     case EFI_IFR_END_OP:\r
1504       //\r
1505       // End Opcode is for Var question.\r
1506       //\r
1507       if (BlockData != NULL && BlockData->Scope > 0) {\r
1508         BlockData->Scope--;\r
1509       }\r
1510       break;\r
1511     default:\r
1512       if (BlockData != NULL && BlockData->Scope > 0) {\r
1513         BlockData->Scope = (UINT8) (BlockData->Scope + IfrOpHdr->Scope);\r
1514       }\r
1515       break;\r
1516     }\r
1517 \r
1518     IfrOffset += IfrOpHdr->Length;\r
1519   }\r
1520 \r
1521 Done:\r
1522   return Status;  \r
1523 }\r
1524 \r
1525 /**\r
1526   This function gets the full request string and full default value string by \r
1527   parsing IFR data in HII form packages. \r
1528   \r
1529   When Request points to NULL string, the request string and default value string \r
1530   for each varstore in form package will return. \r
1531 \r
1532   @param  DataBaseRecord         The DataBaseRecord instance contains the found Hii handle and package.\r
1533   @param  DevicePath             Device Path which Hii Config Access Protocol is registered.\r
1534   @param  Request                Pointer to a null-terminated Unicode string in\r
1535                                  <ConfigRequest> format. When it doesn't contain\r
1536                                  any RequestElement, it will be updated to return \r
1537                                  the full RequestElement retrieved from IFR data.\r
1538                                  If it points to NULL, the request string for the first\r
1539                                  varstore in form package will be merged into a\r
1540                                  <MultiConfigRequest> format string and return. \r
1541   @param  AltCfgResp             Pointer to a null-terminated Unicode string in\r
1542                                  <ConfigAltResp> format. When the pointer is to NULL,\r
1543                                  the full default value string retrieved from IFR data\r
1544                                  will return. When the pinter is to a string, the\r
1545                                  full default value string retrieved from IFR data\r
1546                                  will be merged into the input string and return.\r
1547                                  When Request points to NULL, the default value string \r
1548                                  for each varstore in form package will be merged into \r
1549                                  a <MultiConfigAltResp> format string and return.\r
1550   @param  PointerProgress        Optional parameter, it can be be NULL. \r
1551                                  When it is not NULL, if Request is NULL, it returns NULL. \r
1552                                  On return, points to a character in the Request\r
1553                                  string. Points to the string's null terminator if\r
1554                                  request was successful. Points to the most recent\r
1555                                  & before the first failing name / value pair (or\r
1556                                  the beginning of the string if the failure is in\r
1557                                  the first name / value pair) if the request was\r
1558                                  not successful.\r
1559   @retval EFI_SUCCESS            The Results string is set to the full request string.\r
1560                                  And AltCfgResp contains all default value string.\r
1561   @retval EFI_OUT_OF_RESOURCES   Not enough memory for the return string.\r
1562   @retval EFI_NOT_FOUND          The varstore (Guid and Name) in Request string \r
1563                                  can't be found in Form package.\r
1564   @retval EFI_NOT_FOUND          HiiPackage can't be got on the input HiiHandle.\r
1565   @retval EFI_INVALID_PARAMETER  Request points to NULL.\r
1566 \r
1567 **/\r
1568 EFI_STATUS\r
1569 EFIAPI\r
1570 GetFullStringFromHiiFormPackages (\r
1571   IN     HII_DATABASE_RECORD        *DataBaseRecord,\r
1572   IN     EFI_DEVICE_PATH_PROTOCOL   *DevicePath,\r
1573   IN OUT EFI_STRING                 *Request,\r
1574   IN OUT EFI_STRING                 *AltCfgResp,\r
1575   OUT    EFI_STRING                 *PointerProgress OPTIONAL\r
1576   )\r
1577 {\r
1578   EFI_STATUS                   Status;\r
1579   UINT8                        *HiiFormPackage;\r
1580   UINTN                        PackageSize;\r
1581   UINTN                        ResultSize;\r
1582   IFR_BLOCK_DATA               *RequestBlockArray;\r
1583   IFR_BLOCK_DATA               *BlockData;\r
1584   IFR_BLOCK_DATA               *NextBlockData;\r
1585   IFR_DEFAULT_DATA             *DefaultValueData;\r
1586   IFR_DEFAULT_DATA             *DefaultId;\r
1587   IFR_DEFAULT_DATA             *DefaultIdArray;\r
1588   IFR_VARSTORAGE_DATA          *VarStorageData;\r
1589   EFI_STRING                   DefaultAltCfgResp;\r
1590   EFI_STRING                   FullConfigRequest;\r
1591   EFI_STRING                   ConfigHdr;\r
1592   EFI_STRING                   GuidStr;\r
1593   EFI_STRING                   NameStr;\r
1594   EFI_STRING                   PathStr;\r
1595   EFI_STRING                   StringPtr;\r
1596   EFI_STRING                   Progress;\r
1597   UINTN                        Length;\r
1598   UINT8                        *TmpBuffer;\r
1599   UINT16                       Offset;\r
1600   UINT16                       Width;\r
1601   LIST_ENTRY                   *Link;\r
1602   LIST_ENTRY                   *LinkData;\r
1603   LIST_ENTRY                   *LinkDefault;\r
1604   BOOLEAN                      DataExist;\r
1605 \r
1606   if (DataBaseRecord == NULL || DevicePath == NULL || Request == NULL || AltCfgResp == NULL) {\r
1607     return EFI_INVALID_PARAMETER;\r
1608   }\r
1609 \r
1610   //\r
1611   // Initialize the local variables.\r
1612   //\r
1613   RequestBlockArray = NULL;\r
1614   DefaultIdArray    = NULL;\r
1615   VarStorageData    = NULL;\r
1616   DefaultAltCfgResp = NULL;\r
1617   FullConfigRequest = NULL;\r
1618   ConfigHdr         = NULL;\r
1619   GuidStr           = NULL;\r
1620   NameStr           = NULL;\r
1621   PathStr           = NULL;\r
1622   HiiFormPackage    = NULL;\r
1623   ResultSize        = 0;\r
1624   PackageSize       = 0;\r
1625   DataExist         = FALSE;\r
1626   Progress          = *Request;\r
1627  \r
1628   //\r
1629   // 0. Get Hii Form Package by HiiHandle\r
1630   //\r
1631   Status = ExportFormPackages (\r
1632              &mPrivate, \r
1633              DataBaseRecord->Handle, \r
1634              DataBaseRecord->PackageList, \r
1635              0, \r
1636              PackageSize, \r
1637              HiiFormPackage,\r
1638              &ResultSize\r
1639            );\r
1640   if (EFI_ERROR (Status)) {\r
1641     return Status;\r
1642   }\r
1643  \r
1644   HiiFormPackage = AllocatePool (ResultSize);\r
1645   if (HiiFormPackage == NULL) {\r
1646     Status = EFI_OUT_OF_RESOURCES;\r
1647     goto Done;\r
1648   }\r
1649 \r
1650   //\r
1651   // Get HiiFormPackage by HiiHandle\r
1652   //\r
1653   PackageSize   = ResultSize;\r
1654   ResultSize    = 0;\r
1655   Status = ExportFormPackages (\r
1656              &mPrivate, \r
1657              DataBaseRecord->Handle, \r
1658              DataBaseRecord->PackageList, \r
1659              0,\r
1660              PackageSize, \r
1661              HiiFormPackage,\r
1662              &ResultSize\r
1663            );\r
1664   if (EFI_ERROR (Status)) {\r
1665     goto Done;\r
1666   }\r
1667 \r
1668   //\r
1669   // 1. Get the request block array by Request String when Request string containts the block array.\r
1670   //\r
1671   StringPtr = NULL;\r
1672   if (*Request != NULL) {\r
1673     StringPtr = *Request;\r
1674     //\r
1675     // Jump <ConfigHdr>\r
1676     //\r
1677     if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
1678       Status   = EFI_INVALID_PARAMETER;\r
1679       goto Done;\r
1680     }\r
1681     StringPtr += StrLen (L"GUID=");\r
1682     while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {\r
1683       StringPtr++;\r
1684     }\r
1685     if (*StringPtr == L'\0') {\r
1686       Status = EFI_INVALID_PARAMETER;\r
1687       goto Done;\r
1688     }\r
1689     StringPtr += StrLen (L"&NAME=");\r
1690     while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {\r
1691       StringPtr++;\r
1692     }\r
1693     if (*StringPtr == L'\0') {\r
1694       Status = EFI_INVALID_PARAMETER;\r
1695       goto Done;\r
1696     }\r
1697     StringPtr += StrLen (L"&PATH=");\r
1698     while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
1699       StringPtr ++;\r
1700     }\r
1701     //\r
1702     // Check the following string &OFFSET=\r
1703     //\r
1704     if (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {\r
1705       Progress = StringPtr;\r
1706       Status   = EFI_INVALID_PARAMETER;\r
1707       goto Done;\r
1708     } else if (*StringPtr == L'\0') {\r
1709       //\r
1710       // No request block is found.\r
1711       //\r
1712       StringPtr = NULL;\r
1713     }\r
1714   }\r
1715   if (StringPtr != NULL) {\r
1716     //\r
1717     // Init RequestBlockArray\r
1718     //\r
1719     RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));\r
1720     if (RequestBlockArray == NULL) {\r
1721       Status = EFI_OUT_OF_RESOURCES;\r
1722       goto Done;\r
1723     }\r
1724     InitializeListHead (&RequestBlockArray->Entry);\r
1725 \r
1726     //\r
1727     // Get the request Block array from the request string\r
1728     // Offset and Width\r
1729     //\r
1730 \r
1731     //\r
1732     // Parse each <RequestElement> if exists\r
1733     // Only <BlockName> format is supported by this help function.\r
1734     // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>\r
1735     //\r
1736     while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {\r
1737       //\r
1738       // Skip the OFFSET string\r
1739       //\r
1740       Progress   = StringPtr;\r
1741       StringPtr += StrLen (L"&OFFSET=");\r
1742       //\r
1743       // Get Offset\r
1744       //\r
1745       Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1746       if (EFI_ERROR (Status)) {\r
1747         goto Done;\r
1748       }\r
1749       Offset = 0;\r
1750       CopyMem (\r
1751         &Offset,\r
1752         TmpBuffer,\r
1753         (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)\r
1754         );\r
1755       FreePool (TmpBuffer);\r
1756   \r
1757       StringPtr += Length;\r
1758       if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {\r
1759         Status = EFI_INVALID_PARAMETER;\r
1760         goto Done;\r
1761       }\r
1762       StringPtr += StrLen (L"&WIDTH=");\r
1763   \r
1764       //\r
1765       // Get Width\r
1766       //\r
1767       Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1768       if (EFI_ERROR (Status)) {\r
1769         goto Done;\r
1770       }\r
1771       Width = 0;\r
1772       CopyMem (\r
1773         &Width,\r
1774         TmpBuffer,\r
1775         (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)\r
1776         );\r
1777       FreePool (TmpBuffer);\r
1778 \r
1779       StringPtr += Length;\r
1780       if (*StringPtr != 0 && *StringPtr != L'&') {\r
1781         Status = EFI_INVALID_PARAMETER;\r
1782         goto Done;\r
1783       }\r
1784       \r
1785       //\r
1786       // Set Block Data\r
1787       //\r
1788       BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));\r
1789       if (BlockData == NULL) {\r
1790         Status = EFI_OUT_OF_RESOURCES;\r
1791         goto Done;\r
1792       }\r
1793       BlockData->Offset = Offset;\r
1794       BlockData->Width  = Width;\r
1795       InsertBlockData (&RequestBlockArray->Entry, &BlockData);\r
1796       \r
1797       //\r
1798       // Skip &VALUE string if &VALUE does exists.\r
1799       //\r
1800       if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) == 0) {\r
1801         StringPtr += StrLen (L"&VALUE=");\r
1802 \r
1803         //\r
1804         // Get Value\r
1805         //\r
1806         Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1807         if (EFI_ERROR (Status)) {\r
1808           Status = EFI_INVALID_PARAMETER;\r
1809           goto Done;\r
1810         }\r
1811 \r
1812         StringPtr += Length;\r
1813         if (*StringPtr != 0 && *StringPtr != L'&') {\r
1814           Status = EFI_INVALID_PARAMETER;\r
1815           goto Done;\r
1816         }\r
1817       }\r
1818       //\r
1819       // If '\0', parsing is finished. \r
1820       //\r
1821       if (*StringPtr == 0) {\r
1822         break;\r
1823       }\r
1824     }\r
1825     \r
1826     //\r
1827     // Merge the requested block data.\r
1828     //\r
1829     Link = RequestBlockArray->Entry.ForwardLink;\r
1830     while ((Link != &RequestBlockArray->Entry) && (Link->ForwardLink != &RequestBlockArray->Entry)) {\r
1831       BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);\r
1832       NextBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);\r
1833       if ((NextBlockData->Offset >= BlockData->Offset) && (NextBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {\r
1834         if ((NextBlockData->Offset + NextBlockData->Width) > (BlockData->Offset + BlockData->Width)) {\r
1835           BlockData->Width = (UINT16) (NextBlockData->Offset + NextBlockData->Width - BlockData->Offset);\r
1836         }\r
1837         RemoveEntryList (Link->ForwardLink);\r
1838         FreePool (NextBlockData);\r
1839         continue;\r
1840       }\r
1841       Link = Link->ForwardLink;      \r
1842     }\r
1843   }\r
1844   \r
1845   //\r
1846   // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray.\r
1847   //\r
1848 \r
1849   //\r
1850   // Initialize DefaultIdArray to store the map between DeaultId and DefaultName\r
1851   //\r
1852   DefaultIdArray   = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));\r
1853   if (DefaultIdArray == NULL) {\r
1854     Status = EFI_OUT_OF_RESOURCES;\r
1855     goto Done;\r
1856   }\r
1857   InitializeListHead (&DefaultIdArray->Entry);\r
1858 \r
1859   //\r
1860   // Initialize VarStorageData to store the var store Block and Default value information.\r
1861   //\r
1862   VarStorageData = (IFR_VARSTORAGE_DATA *) AllocateZeroPool (sizeof (IFR_VARSTORAGE_DATA));\r
1863   if (VarStorageData == NULL) {\r
1864     Status = EFI_OUT_OF_RESOURCES;\r
1865     goto Done;\r
1866   }\r
1867   InitializeListHead (&VarStorageData->Entry);\r
1868   InitializeListHead (&VarStorageData->BlockEntry);\r
1869 \r
1870   //\r
1871   // Parse the opcode in form pacakge to get the default setting.\r
1872   //\r
1873   Status = ParseIfrData (HiiFormPackage, (UINT32) PackageSize, *Request, RequestBlockArray, VarStorageData, DefaultIdArray);\r
1874   if (EFI_ERROR (Status)) {\r
1875     goto Done;\r
1876   }\r
1877   \r
1878   //\r
1879   // No requested varstore in IFR data and directly return\r
1880   //\r
1881   if (VarStorageData->Size == 0) {\r
1882     Status = EFI_SUCCESS;\r
1883     goto Done;\r
1884   }\r
1885 \r
1886   //\r
1887   // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case.\r
1888   //\r
1889 \r
1890   //\r
1891   // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle\r
1892   //\r
1893   GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &VarStorageData->Guid, 1, &GuidStr);\r
1894   GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *) VarStorageData->Name, 2, &NameStr);\r
1895   GenerateSubStr (\r
1896     L"PATH=",\r
1897     GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),\r
1898     (VOID *) DevicePath,\r
1899     1,\r
1900     &PathStr\r
1901     );\r
1902   Length = StrLen (GuidStr);\r
1903   Length = Length + StrLen (NameStr);\r
1904   Length = Length + StrLen (PathStr) + 1;\r
1905   ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16));\r
1906   if (ConfigHdr == NULL) {\r
1907     Status = EFI_OUT_OF_RESOURCES;\r
1908     goto Done;    \r
1909   }\r
1910   StrCpy (ConfigHdr, GuidStr);\r
1911   StrCat (ConfigHdr, NameStr);\r
1912   StrCat (ConfigHdr, PathStr);\r
1913 \r
1914   //\r
1915   // Remove the last character L'&'\r
1916   //\r
1917   *(ConfigHdr + StrLen (ConfigHdr) - 1) = L'\0';\r
1918 \r
1919   if (RequestBlockArray == NULL) {\r
1920     //\r
1921     // Append VarStorageData BlockEntry into *Request string\r
1922     // Now support only one varstore in a form package.\r
1923     //\r
1924 \r
1925     //\r
1926     // Go through all VarStorageData Entry and get BlockEntry for each one for the multiple varstore in a single form package\r
1927     // Then construct them all to return MultiRequest string : ConfigHdr BlockConfig\r
1928     //\r
1929 \r
1930     //\r
1931     // Compute the length of the entire request starting with <ConfigHdr> and a \r
1932     // Null-terminator\r
1933     //\r
1934     DataExist = FALSE;\r
1935     Length    = StrLen (ConfigHdr) + 1;\r
1936 \r
1937     for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {\r
1938       //\r
1939       // Add <BlockName> length for each Offset/Width pair\r
1940       //\r
1941       // <BlockName> ::= &OFFSET=1234&WIDTH=1234\r
1942       //                 |  8   | 4 |   7  | 4 |\r
1943       //\r
1944       DataExist = TRUE;\r
1945       Length = Length + (8 + 4 + 7 + 4);\r
1946     }\r
1947     \r
1948     //\r
1949     // No any request block data is found. The request string can't be constructed.\r
1950     //\r
1951     if (!DataExist) {\r
1952       Status = EFI_SUCCESS;\r
1953       goto Done;\r
1954     }\r
1955 \r
1956     //\r
1957     // Allocate buffer for the entire <ConfigRequest>\r
1958     //\r
1959     FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16));\r
1960     if (FullConfigRequest == NULL) {\r
1961       Status = EFI_OUT_OF_RESOURCES;\r
1962       goto Done;\r
1963     }\r
1964     StringPtr = FullConfigRequest;\r
1965   \r
1966     //\r
1967     // Start with <ConfigHdr>\r
1968     //\r
1969     StrCpy (StringPtr, ConfigHdr);\r
1970     StringPtr += StrLen (StringPtr);\r
1971 \r
1972     //\r
1973     // Loop through all the Offset/Width pairs and append them to ConfigRequest\r
1974     //\r
1975     for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {\r
1976       BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);\r
1977       //\r
1978       // Append &OFFSET=XXXX&WIDTH=YYYY\0\r
1979       //\r
1980       UnicodeSPrint (\r
1981         StringPtr, \r
1982         (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16), \r
1983         L"&OFFSET=%04X&WIDTH=%04X", \r
1984         BlockData->Offset, \r
1985         BlockData->Width\r
1986       );\r
1987       StringPtr += StrLen (StringPtr);\r
1988     }\r
1989     //\r
1990     // Set to the got full request string.\r
1991     //\r
1992     HiiToLower (FullConfigRequest);\r
1993     if (*Request != NULL) {\r
1994       FreePool (*Request);\r
1995     }\r
1996     *Request = FullConfigRequest;\r
1997   }\r
1998   \r
1999   //\r
2000   // 4. Construct Default Value string in AltResp according to request element.\r
2001   // Go through all VarStorageData Entry and get the DefaultId array for each one\r
2002   // Then construct them all to : ConfigHdr AltConfigHdr ConfigBody AltConfigHdr ConfigBody\r
2003   //\r
2004   DataExist = FALSE;\r
2005   //\r
2006   // Add length for <ConfigHdr> + '\0'\r
2007   //\r
2008   Length = StrLen (ConfigHdr) + 1;\r
2009   \r
2010   for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {\r
2011     DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);\r
2012     //\r
2013     // Add length for "&<ConfigHdr>&ALTCFG=XXXX"\r
2014     //                |1| StrLen (ConfigHdr) | 8 | 4 |\r
2015     //\r
2016     Length += (1 + StrLen (ConfigHdr) + 8 + 4);\r
2017     \r
2018     for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {\r
2019       BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);\r
2020       for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; LinkDefault = LinkDefault->ForwardLink) {\r
2021         DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);\r
2022         if (DefaultValueData->DefaultId == DefaultId->DefaultId) {\r
2023           //\r
2024           // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz"\r
2025           //                |    8  | 4 |   7  | 4 |   7  | Width * 2 |\r
2026           //\r
2027           Length += (8 + 4 + 7 + 4 + 7 + BlockData->Width * 2);\r
2028           DataExist = TRUE;\r
2029         }\r
2030       }\r
2031     }\r
2032   }\r
2033   \r
2034   //\r
2035   // No default value is found. The default string doesn't exist.\r
2036   //\r
2037   if (!DataExist) {\r
2038     Status = EFI_SUCCESS;\r
2039     goto Done;\r
2040   }\r
2041 \r
2042   //\r
2043   // Allocate buffer for the entire <DefaultAltCfgResp>\r
2044   //\r
2045   DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));\r
2046   if (DefaultAltCfgResp == NULL) {\r
2047     Status = EFI_OUT_OF_RESOURCES;\r
2048     goto Done;\r
2049   }\r
2050   StringPtr = DefaultAltCfgResp;\r
2051 \r
2052   //\r
2053   // Start with <ConfigHdr>\r
2054   //\r
2055   StrCpy (StringPtr, ConfigHdr);\r
2056   StringPtr += StrLen (StringPtr);\r
2057 \r
2058   for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {\r
2059     DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);\r
2060     //\r
2061     // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX\0"\r
2062     //                                |1| StrLen (ConfigHdr) | 8 | 4 |\r
2063     //\r
2064     UnicodeSPrint (\r
2065       StringPtr, \r
2066       (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16), \r
2067       L"&%s&ALTCFG=%04X", \r
2068       ConfigHdr, \r
2069       DefaultId->DefaultName\r
2070       );\r
2071     StringPtr += StrLen (StringPtr);\r
2072     \r
2073     for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {\r
2074       BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);\r
2075       for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; LinkDefault = LinkDefault->ForwardLink) {\r
2076         DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);\r
2077         if (DefaultValueData->DefaultId == DefaultId->DefaultId) {\r
2078           //\r
2079           // Add <BlockConfig>\r
2080           // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>\r
2081           //\r
2082           UnicodeSPrint (\r
2083             StringPtr, \r
2084             (8 + 4 + 7 + 4 + 7 + 1) * sizeof (CHAR16),\r
2085             L"&OFFSET=%04X&WIDTH=%04X&VALUE=", \r
2086             BlockData->Offset, \r
2087             BlockData->Width\r
2088             );\r
2089           StringPtr += StrLen (StringPtr);\r
2090 \r
2091           //\r
2092           // Convert Value to a hex string in "%x" format\r
2093           // NOTE: This is in the opposite byte that GUID and PATH use\r
2094           //\r
2095           Width     = BlockData->Width;\r
2096           TmpBuffer = (UINT8 *) &(DefaultValueData->Value);\r
2097           for (; Width > 0; Width--) {\r
2098             StringPtr += UnicodeValueToString (StringPtr, PREFIX_ZERO | RADIX_HEX, TmpBuffer[Width - 1], 2);\r
2099           }\r
2100         }\r
2101       }\r
2102     }\r
2103   }\r
2104   HiiToLower (DefaultAltCfgResp);\r
2105 \r
2106   //\r
2107   // 5. Merge string into the input AltCfgResp if the iput *AltCfgResp is not NULL.\r
2108   //\r
2109   if (*AltCfgResp != NULL && DefaultAltCfgResp != NULL) {\r
2110     Status = MergeDefaultString (AltCfgResp, DefaultAltCfgResp);\r
2111     FreePool (DefaultAltCfgResp);\r
2112   } else if (*AltCfgResp == NULL) {\r
2113     *AltCfgResp = DefaultAltCfgResp;\r
2114   }\r
2115 \r
2116 Done:\r
2117   if (RequestBlockArray != NULL) {\r
2118     //\r
2119     // Free Link Array RequestBlockArray\r
2120     //\r
2121     while (!IsListEmpty (&RequestBlockArray->Entry)) {\r
2122       BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);\r
2123       RemoveEntryList (&BlockData->Entry);\r
2124       FreePool (BlockData);\r
2125     }\r
2126 \r
2127     FreePool (RequestBlockArray);\r
2128   }\r
2129   \r
2130   if (VarStorageData != NULL) {\r
2131     //\r
2132     // Free link array VarStorageData\r
2133     //\r
2134     while (!IsListEmpty (&VarStorageData->BlockEntry)) {\r
2135       BlockData = BASE_CR (VarStorageData->BlockEntry.ForwardLink, IFR_BLOCK_DATA, Entry);\r
2136       RemoveEntryList (&BlockData->Entry);\r
2137       //\r
2138       // Free default value link array\r
2139       //\r
2140       while (!IsListEmpty (&BlockData->DefaultValueEntry)) {\r
2141         DefaultValueData = BASE_CR (BlockData->DefaultValueEntry.ForwardLink, IFR_DEFAULT_DATA, Entry);\r
2142         RemoveEntryList (&DefaultValueData->Entry);\r
2143         FreePool (DefaultValueData);\r
2144       }\r
2145       FreePool (BlockData);\r
2146     }\r
2147     FreePool (VarStorageData);\r
2148   }\r
2149 \r
2150   if (DefaultIdArray != NULL) {\r
2151     //\r
2152     // Free DefaultId Array\r
2153     //\r
2154     while (!IsListEmpty (&DefaultIdArray->Entry)) {\r
2155       DefaultId = BASE_CR (DefaultIdArray->Entry.ForwardLink, IFR_DEFAULT_DATA, Entry);\r
2156       RemoveEntryList (&DefaultId->Entry);\r
2157       FreePool (DefaultId);\r
2158     }\r
2159     FreePool (DefaultIdArray);\r
2160   }\r
2161   \r
2162   //\r
2163   // Free the allocated string \r
2164   //\r
2165   if (GuidStr != NULL) {\r
2166     FreePool (GuidStr);\r
2167   }\r
2168   if (NameStr != NULL) {\r
2169     FreePool (NameStr);\r
2170   }\r
2171   if (PathStr != NULL) {\r
2172     FreePool (PathStr);\r
2173   }\r
2174   if (ConfigHdr != NULL) {\r
2175     FreePool (ConfigHdr);\r
2176   }\r
2177 \r
2178   //\r
2179   // Free Pacakge data\r
2180   //\r
2181   if (HiiFormPackage != NULL) {\r
2182     FreePool (HiiFormPackage);\r
2183   }\r
2184 \r
2185   if (PointerProgress != NULL) {\r
2186     if (*Request == NULL) {\r
2187       *PointerProgress = NULL;\r
2188     } else if (EFI_ERROR (Status)) {\r
2189       *PointerProgress = Progress;\r
2190     } else {\r
2191       *PointerProgress = *Request + StrLen (*Request);\r
2192     }\r
2193   }\r
2194 \r
2195   return Status;\r
2196 }\r
2197 \r
2198 /**\r
2199   This function allows a caller to extract the current configuration\r
2200   for one or more named elements from one or more drivers.\r
2201 \r
2202   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
2203                                  instance.\r
2204   @param  Request                A null-terminated Unicode string in\r
2205                                  <MultiConfigRequest> format.\r
2206   @param  Progress               On return, points to a character in the Request\r
2207                                  string. Points to the string's null terminator if\r
2208                                  request was successful. Points to the most recent\r
2209                                  & before the first failing name / value pair (or\r
2210                                  the beginning of the string if the failure is in\r
2211                                  the first name / value pair) if the request was\r
2212                                  not successful.\r
2213   @param  Results                Null-terminated Unicode string in\r
2214                                  <MultiConfigAltResp> format which has all values\r
2215                                  filled in for the names in the Request string.\r
2216                                  String to be allocated by the called function.\r
2217 \r
2218   @retval EFI_SUCCESS            The Results string is filled with the values\r
2219                                  corresponding to all requested names.\r
2220   @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the parts of the\r
2221                                  results that must be stored awaiting possible\r
2222                                  future        protocols.\r
2223   @retval EFI_NOT_FOUND          Routing data doesn't match any known driver.\r
2224                                    Progress set to the "G" in "GUID" of the routing\r
2225                                   header that doesn't match. Note: There is no\r
2226                                     requirement that all routing data be validated\r
2227                                  before any configuration extraction.\r
2228   @retval EFI_INVALID_PARAMETER  For example, passing in a NULL for the Request\r
2229                                  parameter would result in this type of error. The\r
2230                                  Progress parameter is set to NULL.\r
2231   @retval EFI_INVALID_PARAMETER  Illegal syntax. Progress set to most recent &\r
2232                                  before the error or the beginning of the string.\r
2233   @retval EFI_INVALID_PARAMETER  Unknown name. Progress points to the & before the\r
2234                                  name in question.\r
2235 \r
2236 **/\r
2237 EFI_STATUS\r
2238 EFIAPI\r
2239 HiiConfigRoutingExtractConfig (\r
2240   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL  *This,\r
2241   IN  CONST EFI_STRING                       Request,\r
2242   OUT EFI_STRING                             *Progress,\r
2243   OUT EFI_STRING                             *Results\r
2244   )\r
2245 {\r
2246   HII_DATABASE_PRIVATE_DATA           *Private;\r
2247   EFI_STRING                          StringPtr;\r
2248   EFI_STRING                          ConfigRequest;\r
2249   UINTN                               Length;\r
2250   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;\r
2251   EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;\r
2252   EFI_STATUS                          Status;\r
2253   LIST_ENTRY                          *Link;\r
2254   HII_DATABASE_RECORD                 *Database;\r
2255   UINT8                               *DevicePathPkg;\r
2256   UINT8                               *CurrentDevicePath;\r
2257   EFI_HANDLE                          DriverHandle;\r
2258   EFI_HII_HANDLE                      HiiHandle;\r
2259   EFI_HII_CONFIG_ACCESS_PROTOCOL      *ConfigAccess;\r
2260   EFI_STRING                          AccessProgress;\r
2261   EFI_STRING                          AccessResults;\r
2262   EFI_STRING                          DefaultResults;\r
2263   BOOLEAN                             FirstElement;\r
2264   BOOLEAN                             IfrDataParsedFlag;\r
2265 \r
2266   if (This == NULL || Progress == NULL || Results == NULL) {\r
2267     return EFI_INVALID_PARAMETER;\r
2268   }\r
2269 \r
2270   if (Request == NULL) {\r
2271     *Progress = NULL;\r
2272     return EFI_INVALID_PARAMETER;\r
2273   }\r
2274 \r
2275   Private   = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
2276   StringPtr = Request;\r
2277   *Progress = StringPtr;\r
2278   DefaultResults = NULL;\r
2279   ConfigRequest  = NULL;\r
2280   Status         = EFI_SUCCESS;\r
2281   AccessResults  = NULL;\r
2282   DevicePath     = NULL;\r
2283   IfrDataParsedFlag = FALSE;\r
2284 \r
2285   //\r
2286   // The first element of <MultiConfigRequest> should be\r
2287   // <GuidHdr>, which is in 'GUID='<Guid> syntax.\r
2288   //\r
2289   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
2290     return EFI_INVALID_PARAMETER;\r
2291   }\r
2292 \r
2293   FirstElement = TRUE;\r
2294 \r
2295   //\r
2296   // Allocate a fix length of memory to store Results. Reallocate memory for\r
2297   // Results if this fix length is insufficient.\r
2298   //\r
2299   *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);\r
2300   if (*Results == NULL) {\r
2301     return EFI_OUT_OF_RESOURCES;\r
2302   }\r
2303 \r
2304   while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {\r
2305     //\r
2306     // If parsing error, set Progress to the beginning of the <MultiConfigRequest>\r
2307     // or most recent & before the error.\r
2308     //\r
2309     if (StringPtr == Request) {\r
2310       *Progress = StringPtr;\r
2311     } else {\r
2312       *Progress = StringPtr - 1;\r
2313     }\r
2314 \r
2315     //\r
2316     // Process each <ConfigRequest> of <MultiConfigRequest>\r
2317     //\r
2318     Length = CalculateConfigStringLen (StringPtr);\r
2319     ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);\r
2320     if (ConfigRequest == NULL) {\r
2321       Status = EFI_OUT_OF_RESOURCES;\r
2322       goto Done;\r
2323     }\r
2324     *(ConfigRequest + Length) = 0;\r
2325 \r
2326     //\r
2327     // Get the UEFI device path\r
2328     //\r
2329     Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);\r
2330     if (EFI_ERROR (Status)) {\r
2331       goto Done;\r
2332     }\r
2333 \r
2334     //\r
2335     // Find driver which matches the routing data.\r
2336     //\r
2337     DriverHandle     = NULL;\r
2338     HiiHandle        = NULL;\r
2339     Database         = NULL;\r
2340     for (Link = Private->DatabaseList.ForwardLink;\r
2341          Link != &Private->DatabaseList;\r
2342          Link = Link->ForwardLink\r
2343         ) {\r
2344       Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);\r
2345       if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {\r
2346         CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);\r
2347         if (CompareMem (\r
2348               DevicePath,\r
2349               CurrentDevicePath,\r
2350               GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)\r
2351               ) == 0) {\r
2352           DriverHandle = Database->DriverHandle;\r
2353           HiiHandle    = Database->Handle;\r
2354           break;\r
2355         }\r
2356       }\r
2357     }\r
2358     \r
2359     //\r
2360     // Try to find driver handle by device path.\r
2361     //\r
2362     if (DriverHandle == NULL) {\r
2363       TempDevicePath = DevicePath;\r
2364       Status = gBS->LocateDevicePath (\r
2365                       &gEfiDevicePathProtocolGuid,\r
2366                       &TempDevicePath,\r
2367                       &DriverHandle\r
2368                       );\r
2369       if (EFI_ERROR (Status) || (DriverHandle == NULL)) {\r
2370         //\r
2371         // Routing data does not match any known driver.\r
2372         // Set Progress to the 'G' in "GUID" of the routing header.\r
2373         //\r
2374         *Progress = StringPtr;\r
2375         Status = EFI_NOT_FOUND;\r
2376         goto Done;\r
2377       }\r
2378     }\r
2379     \r
2380     //\r
2381     // Check whether ConfigRequest contains request string OFFSET/WIDTH\r
2382     //\r
2383     IfrDataParsedFlag = FALSE;\r
2384     if ((HiiHandle != NULL) && (StrStr (ConfigRequest, L"&OFFSET=") == NULL)) {\r
2385       //\r
2386       // Get the full request string from IFR when HiiPackage is registered to HiiHandle \r
2387       //\r
2388       IfrDataParsedFlag = TRUE;\r
2389       Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress);\r
2390       if (EFI_ERROR (Status)) {\r
2391         //\r
2392         // AccessProgress indicates the parsing progress on <ConfigRequest>.\r
2393         // Map it to the progress on <MultiConfigRequest> then return it.\r
2394         //\r
2395         *Progress = StrStr (StringPtr, AccessProgress);\r
2396         goto Done;\r
2397       }\r
2398       //\r
2399       // Not any request block is found.\r
2400       //\r
2401       if (StrStr (ConfigRequest, L"&OFFSET=") == NULL) {\r
2402         AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);\r
2403         goto NextConfigString;\r
2404       }\r
2405     }\r
2406 \r
2407     //\r
2408     // Call corresponding ConfigAccess protocol to extract settings\r
2409     //\r
2410     Status = gBS->HandleProtocol (\r
2411                     DriverHandle,\r
2412                     &gEfiHiiConfigAccessProtocolGuid,\r
2413                     (VOID **) &ConfigAccess\r
2414                     );\r
2415     ASSERT_EFI_ERROR (Status);\r
2416 \r
2417     Status = ConfigAccess->ExtractConfig (\r
2418                              ConfigAccess,\r
2419                              ConfigRequest,\r
2420                              &AccessProgress,\r
2421                              &AccessResults\r
2422                              );\r
2423     if (EFI_ERROR (Status)) {\r
2424       //\r
2425       // AccessProgress indicates the parsing progress on <ConfigRequest>.\r
2426       // Map it to the progress on <MultiConfigRequest> then return it.\r
2427       //\r
2428       *Progress = StrStr (StringPtr, AccessProgress);\r
2429       goto Done;\r
2430     }\r
2431 \r
2432     //\r
2433     // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'\r
2434     // which seperates the first <ConfigAltResp> and the following ones.\r
2435     //\r
2436     ASSERT (*AccessProgress == 0);\r
2437 \r
2438     //\r
2439     // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle \r
2440     //\r
2441     if (!IfrDataParsedFlag && HiiHandle != NULL) {\r
2442       Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);\r
2443       ASSERT_EFI_ERROR (Status);\r
2444     }\r
2445 \r
2446     FreePool (DevicePath);\r
2447     DevicePath = NULL;\r
2448 \r
2449     if (DefaultResults != NULL) {\r
2450       Status = MergeDefaultString (&AccessResults, DefaultResults);\r
2451       ASSERT_EFI_ERROR (Status);\r
2452       FreePool (DefaultResults);\r
2453       DefaultResults = NULL;\r
2454     }\r
2455     \r
2456 NextConfigString:   \r
2457     if (!FirstElement) {\r
2458       Status = AppendToMultiString (Results, L"&");\r
2459       ASSERT_EFI_ERROR (Status);\r
2460     }\r
2461     \r
2462     Status = AppendToMultiString (Results, AccessResults);\r
2463     ASSERT_EFI_ERROR (Status);\r
2464 \r
2465     FirstElement = FALSE;\r
2466 \r
2467     FreePool (AccessResults);\r
2468     AccessResults = NULL;\r
2469     FreePool (ConfigRequest);\r
2470     ConfigRequest = NULL;\r
2471 \r
2472     //\r
2473     // Go to next <ConfigRequest> (skip '&').\r
2474     //\r
2475     StringPtr += Length;\r
2476     if (*StringPtr == 0) {\r
2477       *Progress = StringPtr;\r
2478       break;\r
2479     }\r
2480 \r
2481     StringPtr++;\r
2482   }\r
2483 \r
2484 Done:\r
2485   if (EFI_ERROR (Status)) {\r
2486     FreePool (*Results);\r
2487     *Results = NULL;\r
2488   }\r
2489   \r
2490   if (ConfigRequest != NULL) {\r
2491     FreePool (ConfigRequest);\r
2492   }\r
2493   \r
2494   if (AccessResults != NULL) {\r
2495     FreePool (AccessResults);\r
2496   }\r
2497   \r
2498   if (DefaultResults != NULL) {\r
2499     FreePool (DefaultResults);\r
2500   }\r
2501   \r
2502   if (DevicePath != NULL) {\r
2503     FreePool (DevicePath);\r
2504   }  \r
2505 \r
2506   return Status;\r
2507 }\r
2508 \r
2509 \r
2510 /**\r
2511   This function allows the caller to request the current configuration for the\r
2512   entirety of the current HII database and returns the data in a\r
2513   null-terminated Unicode string.\r
2514 \r
2515   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
2516                                  instance.\r
2517   @param  Results                Null-terminated Unicode string in\r
2518                                  <MultiConfigAltResp> format which has all values\r
2519                                  filled in for the names in the Request string.\r
2520                                  String to be allocated by the  called function.\r
2521                                  De-allocation is up to the caller.\r
2522 \r
2523   @retval EFI_SUCCESS            The Results string is filled with the values\r
2524                                  corresponding to all requested names.\r
2525   @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the parts of the\r
2526                                  results that must be stored awaiting possible\r
2527                                  future        protocols.\r
2528   @retval EFI_INVALID_PARAMETER  For example, passing in a NULL for the Results\r
2529                                  parameter would result in this type of error.\r
2530 \r
2531 **/\r
2532 EFI_STATUS\r
2533 EFIAPI\r
2534 HiiConfigRoutingExportConfig (\r
2535   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL  *This,\r
2536   OUT EFI_STRING                             *Results\r
2537   )\r
2538 {\r
2539   EFI_STATUS                          Status;\r
2540   EFI_HII_CONFIG_ACCESS_PROTOCOL      *ConfigAccess;\r
2541   EFI_STRING                          AccessResults;\r
2542   EFI_STRING                          Progress;\r
2543   EFI_STRING                          StringPtr;\r
2544   EFI_STRING                          ConfigRequest;\r
2545   UINTN                               Index;\r
2546   EFI_HANDLE                          *ConfigAccessHandles;\r
2547   UINTN                               NumberConfigAccessHandles;\r
2548   BOOLEAN                             FirstElement;\r
2549   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;\r
2550   EFI_HII_HANDLE                      HiiHandle;\r
2551   EFI_STRING                          DefaultResults;\r
2552   HII_DATABASE_PRIVATE_DATA           *Private;\r
2553   LIST_ENTRY                          *Link;\r
2554   HII_DATABASE_RECORD                 *Database;\r
2555   UINT8                               *DevicePathPkg;\r
2556   UINT8                               *CurrentDevicePath;\r
2557   BOOLEAN                             IfrDataParsedFlag;\r
2558 \r
2559   if (This == NULL || Results == NULL) {\r
2560     return EFI_INVALID_PARAMETER;\r
2561   }\r
2562 \r
2563   Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
2564 \r
2565   //\r
2566   // Allocate a fix length of memory to store Results. Reallocate memory for\r
2567   // Results if this fix length is insufficient.\r
2568   //\r
2569   *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);\r
2570   if (*Results == NULL) {\r
2571     return EFI_OUT_OF_RESOURCES;\r
2572   }\r
2573 \r
2574   NumberConfigAccessHandles = 0;\r
2575   Status = gBS->LocateHandleBuffer (\r
2576              ByProtocol,\r
2577              &gEfiHiiConfigAccessProtocolGuid,\r
2578              NULL,\r
2579              &NumberConfigAccessHandles,\r
2580              &ConfigAccessHandles\r
2581              );\r
2582   if (EFI_ERROR (Status)) {\r
2583     return Status;\r
2584   }\r
2585 \r
2586   FirstElement = TRUE;\r
2587 \r
2588   for (Index = 0; Index < NumberConfigAccessHandles; Index++) {\r
2589     Status = gBS->HandleProtocol (\r
2590                     ConfigAccessHandles[Index],\r
2591                     &gEfiHiiConfigAccessProtocolGuid,\r
2592                     (VOID **) &ConfigAccess\r
2593                     );\r
2594     if (EFI_ERROR (Status)) {\r
2595       continue;\r
2596     }\r
2597 \r
2598     //\r
2599     // Get DevicePath and HiiHandle for this ConfigAccess driver handle\r
2600     //\r
2601     IfrDataParsedFlag = FALSE;\r
2602     Progress         = NULL;\r
2603     HiiHandle        = NULL;\r
2604     DefaultResults   = NULL;\r
2605     Database         = NULL;\r
2606     ConfigRequest    = NULL;\r
2607     DevicePath       = DevicePathFromHandle (ConfigAccessHandles[Index]);\r
2608     if (DevicePath != NULL) {\r
2609       for (Link = Private->DatabaseList.ForwardLink;\r
2610            Link != &Private->DatabaseList;\r
2611            Link = Link->ForwardLink\r
2612           ) {\r
2613         Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);\r
2614         if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {\r
2615           CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);\r
2616           if (CompareMem (\r
2617                 DevicePath,\r
2618                 CurrentDevicePath,\r
2619                 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)\r
2620                 ) == 0) {\r
2621             HiiHandle = Database->Handle;\r
2622             break;\r
2623           }\r
2624         }\r
2625       }\r
2626     }\r
2627 \r
2628     Status = ConfigAccess->ExtractConfig (\r
2629                              ConfigAccess,\r
2630                              NULL,\r
2631                              &Progress,\r
2632                              &AccessResults\r
2633                              );\r
2634     if (EFI_ERROR (Status)) {\r
2635       //\r
2636       // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle \r
2637       //\r
2638       if (HiiHandle != NULL && DevicePath != NULL) {\r
2639         IfrDataParsedFlag = TRUE;\r
2640         Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);\r
2641         //\r
2642         // Get the full request string to get the Current setting again.\r
2643         //\r
2644         if (!EFI_ERROR (Status) && ConfigRequest != NULL) {\r
2645           Status = ConfigAccess->ExtractConfig (\r
2646                                    ConfigAccess,\r
2647                                    ConfigRequest,\r
2648                                    &Progress,\r
2649                                    &AccessResults\r
2650                                    );\r
2651           FreePool (ConfigRequest);\r
2652         } else {\r
2653           Status = EFI_NOT_FOUND;\r
2654         }\r
2655       }\r
2656     }\r
2657 \r
2658     if (!EFI_ERROR (Status)) {\r
2659       //\r
2660       // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle \r
2661       //\r
2662       if (!IfrDataParsedFlag && HiiHandle != NULL && DevicePath != NULL) {\r
2663         StringPtr = StrStr (AccessResults, L"&GUID=");\r
2664         if (StringPtr != NULL) {\r
2665           *StringPtr = 0;\r
2666         }\r
2667         if (StrStr (AccessResults, L"&OFFSET=") != NULL) {\r
2668           Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &AccessResults, &DefaultResults, NULL);\r
2669           ASSERT_EFI_ERROR (Status);\r
2670         }\r
2671         if (StringPtr != NULL) {\r
2672           *StringPtr = L'&';\r
2673         }\r
2674       }\r
2675       //\r
2676       // Merge the default sting from IFR code into the got setting from driver.\r
2677       //\r
2678       if (DefaultResults != NULL) {\r
2679         Status = MergeDefaultString (&AccessResults, DefaultResults);\r
2680         ASSERT_EFI_ERROR (Status);\r
2681         FreePool (DefaultResults);\r
2682         DefaultResults = NULL;\r
2683       }\r
2684       \r
2685       //\r
2686       // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'\r
2687       // which seperates the first <ConfigAltResp> and the following ones.      \r
2688       //\r
2689       if (!FirstElement) {\r
2690         Status = AppendToMultiString (Results, L"&");\r
2691         ASSERT_EFI_ERROR (Status);\r
2692       }\r
2693       \r
2694       Status = AppendToMultiString (Results, AccessResults);\r
2695       ASSERT_EFI_ERROR (Status);\r
2696 \r
2697       FirstElement = FALSE;\r
2698       \r
2699       FreePool (AccessResults);\r
2700       AccessResults = NULL;\r
2701     }\r
2702   }\r
2703   FreePool (ConfigAccessHandles);\r
2704 \r
2705   return EFI_SUCCESS;  \r
2706 }\r
2707 \r
2708 \r
2709 /**\r
2710   This function processes the results of processing forms and routes it to the\r
2711   appropriate handlers or storage.\r
2712 \r
2713   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
2714                                  instance.\r
2715   @param  Configuration          A null-terminated Unicode string in\r
2716                                  <MulltiConfigResp> format.\r
2717   @param  Progress               A pointer to a string filled in with the offset of\r
2718                                  the most recent & before the first failing name /\r
2719                                  value pair (or the beginning of the string if the\r
2720                                  failure is in the first name / value pair) or the\r
2721                                  terminating NULL if all was successful.\r
2722 \r
2723   @retval EFI_SUCCESS            The results have been distributed or are awaiting\r
2724                                  distribution.\r
2725   @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the parts of the\r
2726                                  results that must be stored awaiting possible\r
2727                                  future        protocols.\r
2728   @retval EFI_INVALID_PARAMETER  Passing in a NULL for the Configuration parameter\r
2729                                  would result in this type of error.\r
2730   @retval EFI_NOT_FOUND          Target for the specified routing data was not\r
2731                                  found.\r
2732 \r
2733 **/\r
2734 EFI_STATUS\r
2735 EFIAPI\r
2736 HiiConfigRoutingRouteConfig (\r
2737   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL  *This,\r
2738   IN  CONST EFI_STRING                       Configuration,\r
2739   OUT EFI_STRING                             *Progress\r
2740   )\r
2741 {\r
2742   HII_DATABASE_PRIVATE_DATA           *Private;\r
2743   EFI_STRING                          StringPtr;\r
2744   EFI_STRING                          ConfigResp;\r
2745   UINTN                               Length;\r
2746   EFI_STATUS                          Status;\r
2747   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;\r
2748   EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;\r
2749   LIST_ENTRY                          *Link;\r
2750   HII_DATABASE_RECORD                 *Database;\r
2751   UINT8                               *DevicePathPkg;\r
2752   UINT8                               *CurrentDevicePath;\r
2753   EFI_HANDLE                          DriverHandle;\r
2754   EFI_HII_CONFIG_ACCESS_PROTOCOL      *ConfigAccess;\r
2755   EFI_STRING                          AccessProgress;\r
2756 \r
2757   if (This == NULL || Progress == NULL) {\r
2758     return EFI_INVALID_PARAMETER;\r
2759   }\r
2760 \r
2761   if (Configuration == NULL) {\r
2762     *Progress = NULL;\r
2763     return EFI_INVALID_PARAMETER;\r
2764   }\r
2765 \r
2766   Private   = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
2767   StringPtr = Configuration;\r
2768   *Progress = StringPtr;\r
2769 \r
2770   //\r
2771   // The first element of <MultiConfigResp> should be\r
2772   // <GuidHdr>, which is in 'GUID='<Guid> syntax.\r
2773   //\r
2774   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
2775     return EFI_INVALID_PARAMETER;\r
2776   }\r
2777 \r
2778   while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {\r
2779     //\r
2780     // If parsing error, set Progress to the beginning of the <MultiConfigResp>\r
2781     // or most recent & before the error.\r
2782     //\r
2783     if (StringPtr == Configuration) {\r
2784       *Progress = StringPtr;\r
2785     } else {\r
2786       *Progress = StringPtr - 1;\r
2787     }\r
2788 \r
2789     //\r
2790     // Process each <ConfigResp> of <MultiConfigResp>\r
2791     //\r
2792     Length = CalculateConfigStringLen (StringPtr);\r
2793     ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);\r
2794     if (ConfigResp == NULL) {\r
2795       return EFI_OUT_OF_RESOURCES;\r
2796     }\r
2797     //\r
2798     // Append '\0' to the end of ConfigRequest\r
2799     //\r
2800     *(ConfigResp + Length) = 0;\r
2801 \r
2802     //\r
2803     // Get the UEFI device path\r
2804     //\r
2805     Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);\r
2806     if (EFI_ERROR (Status)) {\r
2807       FreePool (ConfigResp);\r
2808       return Status;\r
2809     }\r
2810 \r
2811     //\r
2812     // Find driver which matches the routing data.\r
2813     //\r
2814     DriverHandle     = NULL;\r
2815     for (Link = Private->DatabaseList.ForwardLink;\r
2816          Link != &Private->DatabaseList;\r
2817          Link = Link->ForwardLink\r
2818         ) {\r
2819       Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);\r
2820 \r
2821       if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {\r
2822         CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);\r
2823         if (CompareMem (\r
2824               DevicePath,\r
2825               CurrentDevicePath,\r
2826               GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)\r
2827               ) == 0) {\r
2828           DriverHandle = Database->DriverHandle;\r
2829           break;\r
2830         }\r
2831       }\r
2832     }\r
2833 \r
2834     //\r
2835     // Try to find driver handle by device path.\r
2836     //\r
2837     if (DriverHandle == NULL) {\r
2838       TempDevicePath = DevicePath;\r
2839       Status = gBS->LocateDevicePath (\r
2840                       &gEfiDevicePathProtocolGuid,\r
2841                       &TempDevicePath,\r
2842                       &DriverHandle\r
2843                       );\r
2844       if (EFI_ERROR (Status) || (DriverHandle == NULL)) {\r
2845         //\r
2846         // Routing data does not match any known driver.\r
2847         // Set Progress to the 'G' in "GUID" of the routing header.\r
2848         //\r
2849         FreePool (DevicePath);\r
2850         *Progress = StringPtr;\r
2851         FreePool (ConfigResp);\r
2852         return EFI_NOT_FOUND;\r
2853       }\r
2854     }\r
2855 \r
2856     FreePool (DevicePath);\r
2857 \r
2858     //\r
2859     // Call corresponding ConfigAccess protocol to route settings\r
2860     //\r
2861     Status = gBS->HandleProtocol (\r
2862                     DriverHandle,\r
2863                     &gEfiHiiConfigAccessProtocolGuid,\r
2864                     (VOID **)  &ConfigAccess\r
2865                     );\r
2866     ASSERT_EFI_ERROR (Status);\r
2867 \r
2868     Status = ConfigAccess->RouteConfig (\r
2869                              ConfigAccess,\r
2870                              ConfigResp,\r
2871                              &AccessProgress\r
2872                              );\r
2873 \r
2874     if (EFI_ERROR (Status)) {\r
2875       //\r
2876       // AccessProgress indicates the parsing progress on <ConfigResp>.\r
2877       // Map it to the progress on <MultiConfigResp> then return it.\r
2878       //\r
2879       *Progress = StrStr (StringPtr, AccessProgress);\r
2880 \r
2881       FreePool (ConfigResp);\r
2882       return Status;\r
2883     }\r
2884 \r
2885     FreePool (ConfigResp);\r
2886     ConfigResp = NULL;\r
2887 \r
2888     //\r
2889     // Go to next <ConfigResp> (skip '&').\r
2890     //\r
2891     StringPtr += Length;\r
2892     if (*StringPtr == 0) {\r
2893       *Progress = StringPtr;\r
2894       break;\r
2895     }\r
2896 \r
2897     StringPtr++;\r
2898 \r
2899   }\r
2900 \r
2901   return EFI_SUCCESS;\r
2902 }\r
2903 \r
2904 \r
2905 /**\r
2906   This helper function is to be called by drivers to map configuration data\r
2907   stored in byte array ("block") formats such as UEFI Variables into current\r
2908   configuration strings.\r
2909 \r
2910   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
2911                                  instance.\r
2912   @param  ConfigRequest          A null-terminated Unicode string in\r
2913                                  <ConfigRequest> format.\r
2914   @param  Block                  Array of bytes defining the block's configuration.\r
2915   @param  BlockSize              Length in bytes of Block.\r
2916   @param  Config                 Filled-in configuration string. String allocated\r
2917                                  by  the function. Returned only if call is\r
2918                                  successful. It is <ConfigResp> string format.\r
2919   @param  Progress               A pointer to a string filled in with the offset of\r
2920                                   the most recent & before the first failing\r
2921                                  name/value pair (or the beginning of the string if\r
2922                                  the failure is in the first name / value pair) or\r
2923                                  the terminating NULL if all was successful.\r
2924 \r
2925   @retval EFI_SUCCESS            The request succeeded. Progress points to the null\r
2926                                  terminator at the end of the ConfigRequest\r
2927                                  string.\r
2928   @retval EFI_OUT_OF_RESOURCES   Not enough memory to allocate Config.     Progress\r
2929                                  points to the first character of ConfigRequest.\r
2930   @retval EFI_INVALID_PARAMETER  Passing in a NULL for the ConfigRequest or\r
2931                                  Block parameter would result in this type of\r
2932                                  error. Progress points to the first character of\r
2933                                  ConfigRequest.\r
2934   @retval EFI_DEVICE_ERROR       Block not large enough. Progress undefined.\r
2935   @retval EFI_INVALID_PARAMETER  Encountered non <BlockName> formatted string.\r
2936                                      Block is left updated and Progress points at\r
2937                                  the "&" preceding the first non-<BlockName>.\r
2938 \r
2939 **/\r
2940 EFI_STATUS\r
2941 EFIAPI\r
2942 HiiBlockToConfig (\r
2943   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL  *This,\r
2944   IN  CONST EFI_STRING                       ConfigRequest,\r
2945   IN  CONST UINT8                            *Block,\r
2946   IN  CONST UINTN                            BlockSize,\r
2947   OUT EFI_STRING                             *Config,\r
2948   OUT EFI_STRING                             *Progress\r
2949   )\r
2950 {\r
2951   HII_DATABASE_PRIVATE_DATA           *Private;\r
2952   EFI_STRING                          StringPtr;\r
2953   UINTN                               Length;\r
2954   EFI_STATUS                          Status;\r
2955   EFI_STRING                          TmpPtr;\r
2956   UINT8                               *TmpBuffer;\r
2957   UINTN                               Offset;\r
2958   UINTN                               Width;\r
2959   UINT8                               *Value;\r
2960   EFI_STRING                          ValueStr;\r
2961   EFI_STRING                          ConfigElement;\r
2962   UINTN                               Index;\r
2963   UINT8                               *TemBuffer;\r
2964   CHAR16                              *TemString;\r
2965 \r
2966   if (This == NULL || Progress == NULL || Config == NULL) {\r
2967     return EFI_INVALID_PARAMETER;\r
2968   }\r
2969 \r
2970   if (Block == NULL || ConfigRequest == NULL) {\r
2971     *Progress = ConfigRequest;\r
2972     return EFI_INVALID_PARAMETER;\r
2973   }\r
2974 \r
2975 \r
2976   Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
2977   ASSERT (Private != NULL);\r
2978 \r
2979   StringPtr     = ConfigRequest;\r
2980   ValueStr      = NULL;\r
2981   Value         = NULL;\r
2982   ConfigElement = NULL;\r
2983 \r
2984   //\r
2985   // Allocate a fix length of memory to store Results. Reallocate memory for\r
2986   // Results if this fix length is insufficient.\r
2987   //\r
2988   *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);\r
2989   if (*Config == NULL) {\r
2990     return EFI_OUT_OF_RESOURCES;\r
2991   }\r
2992 \r
2993   //\r
2994   // Jump <ConfigHdr>\r
2995   //\r
2996   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
2997     *Progress = StringPtr;\r
2998     Status = EFI_INVALID_PARAMETER;\r
2999     goto Exit;\r
3000   }\r
3001   while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {\r
3002     StringPtr++;\r
3003   }\r
3004   if (*StringPtr == 0) {\r
3005     *Progress = StringPtr - 1;\r
3006     Status = EFI_INVALID_PARAMETER;\r
3007     goto Exit;\r
3008   }\r
3009 \r
3010   while (*StringPtr != L'&' && *StringPtr != 0) {\r
3011     StringPtr++;\r
3012   }\r
3013   if (*StringPtr == 0) {\r
3014     *Progress = StringPtr - 1;\r
3015     Status = EFI_INVALID_PARAMETER;\r
3016     goto Exit;\r
3017   }\r
3018   //\r
3019   // Skip '&'\r
3020   //\r
3021   StringPtr++;\r
3022 \r
3023   //\r
3024   // Copy <ConfigHdr> and an additional '&' to <ConfigResp>\r
3025   //\r
3026   Length = StringPtr - ConfigRequest;\r
3027   CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));\r
3028 \r
3029   //\r
3030   // Parse each <RequestElement> if exists\r
3031   // Only <BlockName> format is supported by this help function.\r
3032   // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>\r
3033   //\r
3034   while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {\r
3035     //\r
3036     // Back up the header of one <BlockName>\r
3037     //\r
3038     TmpPtr = StringPtr;\r
3039 \r
3040     StringPtr += StrLen (L"OFFSET=");\r
3041     //\r
3042     // Get Offset\r
3043     //\r
3044     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
3045     if (Status == EFI_OUT_OF_RESOURCES) {\r
3046       *Progress = ConfigRequest;\r
3047       goto Exit;\r
3048     }\r
3049     Offset = 0;\r
3050     CopyMem (\r
3051       &Offset,\r
3052       TmpBuffer,\r
3053       (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)\r
3054       );\r
3055     FreePool (TmpBuffer);\r
3056 \r
3057     StringPtr += Length;\r
3058     if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {\r
3059       *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;\r
3060       Status = EFI_INVALID_PARAMETER;\r
3061       goto Exit;\r
3062     }\r
3063     StringPtr += StrLen (L"&WIDTH=");\r
3064 \r
3065     //\r
3066     // Get Width\r
3067     //\r
3068     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
3069     if (Status == EFI_OUT_OF_RESOURCES) {\r
3070       *Progress = ConfigRequest;\r
3071       goto Exit;\r
3072     }\r
3073     Width = 0;\r
3074     CopyMem (\r
3075       &Width,\r
3076       TmpBuffer,\r
3077       (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)\r
3078       );\r
3079     FreePool (TmpBuffer);\r
3080 \r
3081     StringPtr += Length;\r
3082     if (*StringPtr != 0 && *StringPtr != L'&') {\r
3083       *Progress = StringPtr - Length - StrLen (L"&WIDTH=");\r
3084       Status = EFI_INVALID_PARAMETER;\r
3085       goto Exit;\r
3086     }\r
3087 \r
3088     //\r
3089     // Calculate Value and convert it to hex string.\r
3090     //\r
3091     if (Offset + Width > BlockSize) {\r
3092       *Progress = StringPtr;\r
3093       Status = EFI_DEVICE_ERROR;\r
3094       goto Exit;\r
3095     }\r
3096 \r
3097     Value = (UINT8 *) AllocateZeroPool (Width);\r
3098     if (Value == NULL) {\r
3099       *Progress = ConfigRequest;\r
3100       Status = EFI_OUT_OF_RESOURCES;\r
3101       goto Exit;\r
3102     }\r
3103 \r
3104     CopyMem (Value, (UINT8 *) Block + Offset, Width);\r
3105 \r
3106     Length = Width * 2 + 1;\r
3107     ValueStr = (EFI_STRING) AllocateZeroPool (Length  * sizeof (CHAR16));\r
3108     if (ValueStr == NULL) {\r
3109       *Progress = ConfigRequest;\r
3110       Status = EFI_OUT_OF_RESOURCES;\r
3111       goto Exit;\r
3112     }\r
3113     \r
3114     TemString = ValueStr;\r
3115     TemBuffer = Value + Width - 1;\r
3116     for (Index = 0; Index < Width; Index ++, TemBuffer --) {\r
3117       TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);\r
3118     }\r
3119 \r
3120     FreePool (Value);\r
3121     Value = NULL;\r
3122 \r
3123     //\r
3124     // Build a ConfigElement\r
3125     //\r
3126     Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");\r
3127     ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));\r
3128     if (ConfigElement == NULL) {\r
3129       Status = EFI_OUT_OF_RESOURCES;\r
3130       goto Exit;\r
3131     }\r
3132     CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));\r
3133     if (*StringPtr == 0) {\r
3134       *(ConfigElement + (StringPtr - TmpPtr)) = L'&';\r
3135     }\r
3136     *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;\r
3137     StrCat (ConfigElement, L"VALUE=");\r
3138     StrCat (ConfigElement, ValueStr);\r
3139 \r
3140     AppendToMultiString (Config, ConfigElement);\r
3141 \r
3142     FreePool (ConfigElement);\r
3143     FreePool (ValueStr);\r
3144     ConfigElement = NULL;\r
3145     ValueStr = NULL;\r
3146 \r
3147     //\r
3148     // If '\0', parsing is finished. Otherwise skip '&' to continue\r
3149     //\r
3150     if (*StringPtr == 0) {\r
3151       break;\r
3152     }\r
3153     AppendToMultiString (Config, L"&");\r
3154     StringPtr++;\r
3155 \r
3156   }\r
3157 \r
3158   if (*StringPtr != 0) {\r
3159     *Progress = StringPtr - 1;\r
3160     Status = EFI_INVALID_PARAMETER;\r
3161     goto Exit;\r
3162   }\r
3163   \r
3164   HiiToLower (*Config);\r
3165   *Progress = StringPtr;\r
3166   return EFI_SUCCESS;\r
3167 \r
3168 Exit:\r
3169   if (*Config != NULL) {\r
3170   FreePool (*Config);\r
3171   *Config = NULL;\r
3172   }\r
3173   if (ValueStr != NULL) {\r
3174     FreePool (ValueStr);\r
3175   }\r
3176   if (Value != NULL) {\r
3177     FreePool (Value);\r
3178   }\r
3179   if (ConfigElement != NULL) {\r
3180     FreePool (ConfigElement);\r
3181   }\r
3182 \r