]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c
MdeModulePkg/DisplayEngine: Zero memory before free (CVE-2019-14558)
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / ProcessOptions.c
CommitLineData
7c6c064c
ED
1/** @file\r
2Implementation for handling the User Interface option processing.\r
3\r
4\r
f1d78c48 5Copyright (c) 2004 - 2020, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7c6c064c
ED
7\r
8**/\r
9\r
10#include "FormDisplay.h"\r
11\r
1c0d306f
ED
12#define MAX_TIME_OUT_LEN 0x10\r
13\r
7c6c064c
ED
14/**\r
15 Concatenate a narrow string to another string.\r
16\r
17 @param Destination The destination string.\r
01a9598e 18 @param DestMax The Max length of destination string.\r
7c6c064c
ED
19 @param Source The source string. The string to be concatenated.\r
20 to the end of Destination.\r
21\r
22**/\r
23VOID\r
24NewStrCat (\r
25 IN OUT CHAR16 *Destination,\r
5ad66ec6 26 IN UINTN DestMax,\r
7c6c064c
ED
27 IN CHAR16 *Source\r
28 )\r
29{\r
30 UINTN Length;\r
31\r
32 for (Length = 0; Destination[Length] != 0; Length++)\r
33 ;\r
34\r
35 //\r
36 // We now have the length of the original string\r
37 // We can safely assume for now that we are concatenating a narrow value to this string.\r
38 // For instance, the string is "XYZ" and cat'ing ">"\r
39 // If this assumption changes, we need to make this routine a bit more complex\r
40 //\r
41 Destination[Length] = NARROW_CHAR;\r
42 Length++;\r
43\r
5ad66ec6 44 StrCpyS (Destination + Length, DestMax - Length, Source);\r
7c6c064c
ED
45}\r
46\r
d63a9eb4
ED
47/**\r
48 Get UINT64 type value.\r
49\r
50 @param Value Input Hii value.\r
51\r
52 @retval UINT64 Return the UINT64 type value.\r
53\r
54**/\r
55UINT64\r
56HiiValueToUINT64 (\r
57 IN EFI_HII_VALUE *Value\r
58 )\r
59{\r
60 UINT64 RetVal;\r
61\r
62 RetVal = 0;\r
63\r
64 switch (Value->Type) {\r
65 case EFI_IFR_TYPE_NUM_SIZE_8:\r
66 RetVal = Value->Value.u8;\r
67 break;\r
68\r
69 case EFI_IFR_TYPE_NUM_SIZE_16:\r
70 RetVal = Value->Value.u16;\r
71 break;\r
72\r
73 case EFI_IFR_TYPE_NUM_SIZE_32:\r
74 RetVal = Value->Value.u32;\r
75 break;\r
76\r
77 case EFI_IFR_TYPE_BOOLEAN:\r
78 RetVal = Value->Value.b;\r
79 break;\r
80\r
81 case EFI_IFR_TYPE_DATE:\r
82 RetVal = *(UINT64*) &Value->Value.date;\r
83 break;\r
84\r
85 case EFI_IFR_TYPE_TIME:\r
86 RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff;\r
87 break;\r
88\r
89 default:\r
90 RetVal = Value->Value.u64;\r
91 break;\r
92 }\r
93\r
94 return RetVal;\r
95}\r
96\r
40578d09
ED
97/**\r
98 Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.\r
d1102dba
LG
99\r
100 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to\r
40578d09
ED
101 EFI_IFR_TYPE_BUFFER when do the value compare.\r
102\r
103 @param Value Expression value to compare on.\r
104\r
105 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.\r
106 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.\r
107\r
108**/\r
109BOOLEAN\r
110IsTypeInBuffer (\r
111 IN EFI_HII_VALUE *Value\r
112 )\r
113{\r
114 switch (Value->Type) {\r
115 case EFI_IFR_TYPE_BUFFER:\r
116 case EFI_IFR_TYPE_DATE:\r
117 case EFI_IFR_TYPE_TIME:\r
118 case EFI_IFR_TYPE_REF:\r
119 return TRUE;\r
120\r
121 default:\r
122 return FALSE;\r
123 }\r
124}\r
125\r
126/**\r
127 Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64\r
128\r
129 @param Value Expression value to compare on.\r
130\r
131 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.\r
132 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.\r
133\r
134**/\r
135BOOLEAN\r
136IsTypeInUINT64 (\r
137 IN EFI_HII_VALUE *Value\r
138 )\r
139{\r
140 switch (Value->Type) {\r
141 case EFI_IFR_TYPE_NUM_SIZE_8:\r
142 case EFI_IFR_TYPE_NUM_SIZE_16:\r
143 case EFI_IFR_TYPE_NUM_SIZE_32:\r
144 case EFI_IFR_TYPE_NUM_SIZE_64:\r
145 case EFI_IFR_TYPE_BOOLEAN:\r
146 return TRUE;\r
147\r
148 default:\r
149 return FALSE;\r
150 }\r
151}\r
152\r
153/**\r
154 Return the buffer length and buffer pointer for this value.\r
d1102dba
LG
155\r
156 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to\r
40578d09
ED
157 EFI_IFR_TYPE_BUFFER when do the value compare.\r
158\r
159 @param Value Expression value to compare on.\r
160 @param Buf Return the buffer pointer.\r
161 @param BufLen Return the buffer length.\r
162\r
163**/\r
164VOID\r
165GetBufAndLenForValue (\r
166 IN EFI_HII_VALUE *Value,\r
167 OUT UINT8 **Buf,\r
168 OUT UINT16 *BufLen\r
169 )\r
170{\r
171 switch (Value->Type) {\r
172 case EFI_IFR_TYPE_BUFFER:\r
173 *Buf = Value->Buffer;\r
174 *BufLen = Value->BufferLen;\r
175 break;\r
176\r
177 case EFI_IFR_TYPE_DATE:\r
178 *Buf = (UINT8 *) (&Value->Value.date);\r
179 *BufLen = (UINT16) sizeof (EFI_HII_DATE);\r
180 break;\r
181\r
182 case EFI_IFR_TYPE_TIME:\r
183 *Buf = (UINT8 *) (&Value->Value.time);\r
184 *BufLen = (UINT16) sizeof (EFI_HII_TIME);\r
185 break;\r
186\r
187 case EFI_IFR_TYPE_REF:\r
188 *Buf = (UINT8 *) (&Value->Value.ref);\r
189 *BufLen = (UINT16) sizeof (EFI_HII_REF);\r
190 break;\r
191\r
192 default:\r
193 *Buf = NULL;\r
194 *BufLen = 0;\r
195 }\r
196}\r
197\r
7c6c064c
ED
198/**\r
199 Compare two Hii value.\r
200\r
201 @param Value1 Expression value to compare on left-hand.\r
202 @param Value2 Expression value to compare on right-hand.\r
203 @param Result Return value after compare.\r
204 retval 0 Two operators equal.\r
205 return Positive value if Value1 is greater than Value2.\r
206 retval Negative value if Value1 is less than Value2.\r
207 @param HiiHandle Only required for string compare.\r
208\r
209 @retval other Could not perform compare on two values.\r
210 @retval EFI_SUCCESS Compare the value success.\r
211\r
212**/\r
213EFI_STATUS\r
214CompareHiiValue (\r
215 IN EFI_HII_VALUE *Value1,\r
216 IN EFI_HII_VALUE *Value2,\r
217 OUT INTN *Result,\r
218 IN EFI_HII_HANDLE HiiHandle OPTIONAL\r
219 )\r
220{\r
221 INT64 Temp64;\r
222 CHAR16 *Str1;\r
223 CHAR16 *Str2;\r
224 UINTN Len;\r
40578d09
ED
225 UINT8 *Buf1;\r
226 UINT16 Buf1Len;\r
227 UINT8 *Buf2;\r
228 UINT16 Buf2Len;\r
7c6c064c 229\r
40578d09 230 if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) {\r
7c6c064c
ED
231 if (Value1->Value.string == 0 || Value2->Value.string == 0) {\r
232 //\r
233 // StringId 0 is reserved\r
234 //\r
235 return EFI_INVALID_PARAMETER;\r
236 }\r
237\r
238 if (Value1->Value.string == Value2->Value.string) {\r
239 *Result = 0;\r
240 return EFI_SUCCESS;\r
241 }\r
242\r
243 Str1 = GetToken (Value1->Value.string, HiiHandle);\r
244 if (Str1 == NULL) {\r
245 //\r
246 // String not found\r
247 //\r
248 return EFI_NOT_FOUND;\r
249 }\r
250\r
251 Str2 = GetToken (Value2->Value.string, HiiHandle);\r
252 if (Str2 == NULL) {\r
253 FreePool (Str1);\r
254 return EFI_NOT_FOUND;\r
255 }\r
256\r
257 *Result = StrCmp (Str1, Str2);\r
258\r
259 FreePool (Str1);\r
260 FreePool (Str2);\r
261\r
262 return EFI_SUCCESS;\r
263 }\r
264\r
40578d09
ED
265 //\r
266 // Take types(date, time, ref, buffer) as buffer\r
267 //\r
268 if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) {\r
269 GetBufAndLenForValue(Value1, &Buf1, &Buf1Len);\r
270 GetBufAndLenForValue(Value2, &Buf2, &Buf2Len);\r
271\r
272 Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;\r
273 *Result = CompareMem (Buf1, Buf2, Len);\r
274 if ((*Result == 0) && (Buf1Len != Buf2Len)) {\r
7c6c064c
ED
275 //\r
276 // In this case, means base on samll number buffer, the data is same\r
277 // So which value has more data, which value is bigger.\r
278 //\r
40578d09 279 *Result = Buf1Len > Buf2Len ? 1 : -1;\r
7c6c064c
ED
280 }\r
281 return EFI_SUCCESS;\r
d1102dba 282 }\r
7c6c064c
ED
283\r
284 //\r
285 // Take remain types(integer, boolean, date/time) as integer\r
286 //\r
40578d09
ED
287 if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) {\r
288 Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2);\r
289 if (Temp64 > 0) {\r
290 *Result = 1;\r
291 } else if (Temp64 < 0) {\r
292 *Result = -1;\r
293 } else {\r
294 *Result = 0;\r
295 }\r
296 return EFI_SUCCESS;\r
7c6c064c
ED
297 }\r
298\r
40578d09 299 return EFI_UNSUPPORTED;\r
7c6c064c
ED
300}\r
301\r
302/**\r
303 Search an Option of a Question by its value.\r
304\r
305 @param Question The Question\r
306 @param OptionValue Value for Option to be searched.\r
307\r
308 @retval Pointer Pointer to the found Option.\r
309 @retval NULL Option not found.\r
310\r
311**/\r
312DISPLAY_QUESTION_OPTION *\r
313ValueToOption (\r
314 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,\r
315 IN EFI_HII_VALUE *OptionValue\r
316 )\r
317{\r
318 LIST_ENTRY *Link;\r
319 DISPLAY_QUESTION_OPTION *Option;\r
320 INTN Result;\r
321 EFI_HII_VALUE Value;\r
322\r
323 Link = GetFirstNode (&Question->OptionListHead);\r
324 while (!IsNull (&Question->OptionListHead, Link)) {\r
325 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
326\r
327 ZeroMem (&Value, sizeof (EFI_HII_VALUE));\r
328 Value.Type = Option->OptionOpCode->Type;\r
329 CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));\r
d1102dba 330\r
7c6c064c
ED
331 if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
332 return Option;\r
333 }\r
334\r
335 Link = GetNextNode (&Question->OptionListHead, Link);\r
336 }\r
337\r
338 return NULL;\r
339}\r
340\r
341\r
342/**\r
343 Return data element in an Array by its Index.\r
344\r
345 @param Array The data array.\r
346 @param Type Type of the data in this array.\r
347 @param Index Zero based index for data in this array.\r
348\r
349 @retval Value The data to be returned\r
350\r
351**/\r
352UINT64\r
353GetArrayData (\r
354 IN VOID *Array,\r
355 IN UINT8 Type,\r
356 IN UINTN Index\r
357 )\r
358{\r
359 UINT64 Data;\r
360\r
361 ASSERT (Array != NULL);\r
362\r
363 Data = 0;\r
364 switch (Type) {\r
365 case EFI_IFR_TYPE_NUM_SIZE_8:\r
366 Data = (UINT64) *(((UINT8 *) Array) + Index);\r
367 break;\r
368\r
369 case EFI_IFR_TYPE_NUM_SIZE_16:\r
370 Data = (UINT64) *(((UINT16 *) Array) + Index);\r
371 break;\r
372\r
373 case EFI_IFR_TYPE_NUM_SIZE_32:\r
374 Data = (UINT64) *(((UINT32 *) Array) + Index);\r
375 break;\r
376\r
377 case EFI_IFR_TYPE_NUM_SIZE_64:\r
378 Data = (UINT64) *(((UINT64 *) Array) + Index);\r
379 break;\r
380\r
381 default:\r
382 break;\r
383 }\r
384\r
385 return Data;\r
386}\r
387\r
388\r
389/**\r
390 Set value of a data element in an Array by its Index.\r
391\r
392 @param Array The data array.\r
393 @param Type Type of the data in this array.\r
394 @param Index Zero based index for data in this array.\r
395 @param Value The value to be set.\r
396\r
397**/\r
398VOID\r
399SetArrayData (\r
400 IN VOID *Array,\r
401 IN UINT8 Type,\r
402 IN UINTN Index,\r
403 IN UINT64 Value\r
404 )\r
405{\r
406\r
407 ASSERT (Array != NULL);\r
408\r
409 switch (Type) {\r
410 case EFI_IFR_TYPE_NUM_SIZE_8:\r
411 *(((UINT8 *) Array) + Index) = (UINT8) Value;\r
412 break;\r
413\r
414 case EFI_IFR_TYPE_NUM_SIZE_16:\r
415 *(((UINT16 *) Array) + Index) = (UINT16) Value;\r
416 break;\r
417\r
418 case EFI_IFR_TYPE_NUM_SIZE_32:\r
419 *(((UINT32 *) Array) + Index) = (UINT32) Value;\r
420 break;\r
421\r
422 case EFI_IFR_TYPE_NUM_SIZE_64:\r
423 *(((UINT64 *) Array) + Index) = (UINT64) Value;\r
424 break;\r
425\r
426 default:\r
427 break;\r
428 }\r
429}\r
430\r
431/**\r
432 Check whether this value already in the array, if yes, return the index.\r
433\r
434 @param Array The data array.\r
435 @param Type Type of the data in this array.\r
436 @param Value The value to be find.\r
437 @param Index The index in the array which has same value with Value.\r
d1102dba 438\r
7c6c064c
ED
439 @retval TRUE Found the value in the array.\r
440 @retval FALSE Not found the value.\r
441\r
442**/\r
d1102dba 443BOOLEAN\r
7c6c064c
ED
444FindArrayData (\r
445 IN VOID *Array,\r
446 IN UINT8 Type,\r
447 IN UINT64 Value,\r
448 OUT UINTN *Index OPTIONAL\r
449 )\r
450{\r
451 UINTN Count;\r
452 UINT64 TmpValue;\r
453 UINT64 ValueComp;\r
d1102dba 454\r
7c6c064c
ED
455 ASSERT (Array != NULL);\r
456\r
457 Count = 0;\r
458 TmpValue = 0;\r
459\r
460 switch (Type) {\r
461 case EFI_IFR_TYPE_NUM_SIZE_8:\r
462 ValueComp = (UINT8) Value;\r
463 break;\r
464\r
465 case EFI_IFR_TYPE_NUM_SIZE_16:\r
466 ValueComp = (UINT16) Value;\r
467 break;\r
468\r
469 case EFI_IFR_TYPE_NUM_SIZE_32:\r
470 ValueComp = (UINT32) Value;\r
471 break;\r
472\r
473 case EFI_IFR_TYPE_NUM_SIZE_64:\r
474 ValueComp = (UINT64) Value;\r
475 break;\r
476\r
477 default:\r
478 ValueComp = 0;\r
479 break;\r
480 }\r
481\r
482 while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {\r
483 if (ValueComp == TmpValue) {\r
484 if (Index != NULL) {\r
485 *Index = Count;\r
486 }\r
487 return TRUE;\r
488 }\r
489\r
490 Count ++;\r
491 }\r
492\r
493 return FALSE;\r
494}\r
495\r
496/**\r
497 Print Question Value according to it's storage width and display attributes.\r
498\r
499 @param Question The Question to be printed.\r
500 @param FormattedNumber Buffer for output string.\r
501 @param BufferSize The FormattedNumber buffer size in bytes.\r
502\r
503 @retval EFI_SUCCESS Print success.\r
504 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.\r
505\r
506**/\r
507EFI_STATUS\r
508PrintFormattedNumber (\r
509 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,\r
510 IN OUT CHAR16 *FormattedNumber,\r
511 IN UINTN BufferSize\r
512 )\r
513{\r
514 INT64 Value;\r
515 CHAR16 *Format;\r
516 EFI_HII_VALUE *QuestionValue;\r
517 EFI_IFR_NUMERIC *NumericOp;\r
518\r
519 if (BufferSize < (21 * sizeof (CHAR16))) {\r
520 return EFI_BUFFER_TOO_SMALL;\r
521 }\r
522\r
523 QuestionValue = &Question->CurrentValue;\r
524 NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;\r
525\r
526 Value = (INT64) QuestionValue->Value.u64;\r
527 switch (NumericOp->Flags & EFI_IFR_DISPLAY) {\r
528 case EFI_IFR_DISPLAY_INT_DEC:\r
529 switch (QuestionValue->Type) {\r
530 case EFI_IFR_NUMERIC_SIZE_1:\r
531 Value = (INT64) ((INT8) QuestionValue->Value.u8);\r
532 break;\r
533\r
534 case EFI_IFR_NUMERIC_SIZE_2:\r
535 Value = (INT64) ((INT16) QuestionValue->Value.u16);\r
536 break;\r
537\r
538 case EFI_IFR_NUMERIC_SIZE_4:\r
539 Value = (INT64) ((INT32) QuestionValue->Value.u32);\r
540 break;\r
541\r
542 case EFI_IFR_NUMERIC_SIZE_8:\r
543 default:\r
544 break;\r
545 }\r
546\r
547 if (Value < 0) {\r
548 Value = -Value;\r
549 Format = L"-%ld";\r
550 } else {\r
551 Format = L"%ld";\r
552 }\r
553 break;\r
554\r
555 case EFI_IFR_DISPLAY_UINT_DEC:\r
556 Format = L"%ld";\r
557 break;\r
558\r
559 case EFI_IFR_DISPLAY_UINT_HEX:\r
560 Format = L"%lx";\r
561 break;\r
562\r
563 default:\r
564 return EFI_UNSUPPORTED;\r
7c6c064c
ED
565 }\r
566\r
567 UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);\r
568\r
569 return EFI_SUCCESS;\r
570}\r
571\r
572\r
573/**\r
574 Draw a pop up windows based on the dimension, number of lines and\r
575 strings specified.\r
576\r
577 @param RequestedWidth The width of the pop-up.\r
578 @param NumberOfLines The number of lines.\r
579 @param Marker The variable argument list for the list of string to be printed.\r
580\r
581**/\r
582VOID\r
583CreateSharedPopUp (\r
584 IN UINTN RequestedWidth,\r
585 IN UINTN NumberOfLines,\r
586 IN VA_LIST Marker\r
587 )\r
588{\r
589 UINTN Index;\r
590 UINTN Count;\r
591 CHAR16 Character;\r
592 UINTN Start;\r
593 UINTN End;\r
594 UINTN Top;\r
595 UINTN Bottom;\r
596 CHAR16 *String;\r
597 UINTN DimensionsWidth;\r
598 UINTN DimensionsHeight;\r
599\r
600 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;\r
601 DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;\r
602\r
603 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
604\r
605 if ((RequestedWidth + 2) > DimensionsWidth) {\r
606 RequestedWidth = DimensionsWidth - 2;\r
607 }\r
608\r
609 //\r
610 // Subtract the PopUp width from total Columns, allow for one space extra on\r
611 // each end plus a border.\r
612 //\r
613 Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1;\r
614 End = Start + RequestedWidth + 1;\r
615\r
616 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1;\r
617 Bottom = Top + NumberOfLines + 2;\r
618\r
619 Character = BOXDRAW_DOWN_RIGHT;\r
620 PrintCharAt (Start, Top, Character);\r
621 Character = BOXDRAW_HORIZONTAL;\r
622 for (Index = Start; Index + 2 < End; Index++) {\r
623 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
624 }\r
625\r
626 Character = BOXDRAW_DOWN_LEFT;\r
627 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
628 Character = BOXDRAW_VERTICAL;\r
629\r
630 Count = 0;\r
631 for (Index = Top; Index + 2 < Bottom; Index++, Count++) {\r
632 String = VA_ARG (Marker, CHAR16*);\r
633\r
634 //\r
635 // This will clear the background of the line - we never know who might have been\r
636 // here before us. This differs from the next clear in that it used the non-reverse\r
637 // video for normal printing.\r
638 //\r
639 if (GetStringWidth (String) / 2 > 1) {\r
640 ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());\r
641 }\r
642\r
643 //\r
644 // Passing in a space results in the assumption that this is where typing will occur\r
645 //\r
646 if (String[0] == L' ') {\r
647 ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ());\r
648 }\r
649\r
650 //\r
651 // Passing in a NULL results in a blank space\r
652 //\r
653 if (String[0] == CHAR_NULL) {\r
654 ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());\r
655 }\r
656\r
657 PrintStringAt (\r
658 ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1,\r
659 Index + 1,\r
660 String\r
661 );\r
662 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
663 PrintCharAt (Start, Index + 1, Character);\r
664 PrintCharAt (End - 1, Index + 1, Character);\r
665 }\r
666\r
667 Character = BOXDRAW_UP_RIGHT;\r
668 PrintCharAt (Start, Bottom - 1, Character);\r
669 Character = BOXDRAW_HORIZONTAL;\r
670 for (Index = Start; Index + 2 < End; Index++) {\r
671 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
672 }\r
673\r
674 Character = BOXDRAW_UP_LEFT;\r
675 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
676}\r
677\r
678/**\r
679 Draw a pop up windows based on the dimension, number of lines and\r
680 strings specified.\r
681\r
682 @param RequestedWidth The width of the pop-up.\r
683 @param NumberOfLines The number of lines.\r
684 @param ... A series of text strings that displayed in the pop-up.\r
685\r
686**/\r
687VOID\r
688EFIAPI\r
689CreateMultiStringPopUp (\r
690 IN UINTN RequestedWidth,\r
691 IN UINTN NumberOfLines,\r
692 ...\r
693 )\r
694{\r
695 VA_LIST Marker;\r
696\r
697 VA_START (Marker, NumberOfLines);\r
698\r
699 CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);\r
700\r
701 VA_END (Marker);\r
702}\r
703\r
1c0d306f
ED
704/**\r
705 Process nothing.\r
706\r
707 @param Event The Event need to be process\r
708 @param Context The context of the event.\r
709\r
710**/\r
711VOID\r
712EFIAPI\r
713EmptyEventProcess (\r
714 IN EFI_EVENT Event,\r
715 IN VOID *Context\r
716 )\r
717{\r
718}\r
719\r
720/**\r
721 Process for the refresh interval statement.\r
722\r
723 @param Event The Event need to be process\r
724 @param Context The context of the event.\r
725\r
726**/\r
727VOID\r
728EFIAPI\r
729RefreshTimeOutProcess (\r
730 IN EFI_EVENT Event,\r
731 IN VOID *Context\r
732 )\r
733{\r
734 WARNING_IF_CONTEXT *EventInfo;\r
735 CHAR16 TimeOutString[MAX_TIME_OUT_LEN];\r
736\r
737 EventInfo = (WARNING_IF_CONTEXT *) Context;\r
738\r
739 if (*(EventInfo->TimeOut) == 0) {\r
740 gBS->CloseEvent (Event);\r
741\r
742 gBS->SignalEvent (EventInfo->SyncEvent);\r
743 return;\r
744 }\r
745\r
746 UnicodeSPrint(TimeOutString, MAX_TIME_OUT_LEN, L"%d", *(EventInfo->TimeOut));\r
747\r
748 CreateDialog (NULL, gEmptyString, EventInfo->ErrorInfo, gPressEnter, gEmptyString, TimeOutString, NULL);\r
749\r
750 *(EventInfo->TimeOut) -= 1;\r
751}\r
752\r
7c6c064c
ED
753/**\r
754 Display error message for invalid password.\r
755\r
756**/\r
757VOID\r
758PasswordInvalid (\r
759 VOID\r
760 )\r
761{\r
762 EFI_INPUT_KEY Key;\r
763\r
764 //\r
765 // Invalid password, prompt error message\r
766 //\r
767 do {\r
768 CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL);\r
769 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
770}\r
771\r
772/**\r
773 Process password op code.\r
774\r
775 @param MenuOption The menu for current password op code.\r
776\r
777 @retval EFI_SUCCESS Question Option process success.\r
778 @retval Other Question Option process fail.\r
779\r
780**/\r
781EFI_STATUS\r
782PasswordProcess (\r
783 IN UI_MENU_OPTION *MenuOption\r
784 )\r
785{\r
786 CHAR16 *StringPtr;\r
787 CHAR16 *TempString;\r
788 UINTN Maximum;\r
789 EFI_STATUS Status;\r
790 EFI_IFR_PASSWORD *PasswordInfo;\r
791 FORM_DISPLAY_ENGINE_STATEMENT *Question;\r
792 EFI_INPUT_KEY Key;\r
793\r
794 Question = MenuOption->ThisTag;\r
795 PasswordInfo = (EFI_IFR_PASSWORD *) Question->OpCode;\r
796 Maximum = PasswordInfo->MaxSize;\r
797 Status = EFI_SUCCESS;\r
798\r
799 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
800 ASSERT (StringPtr);\r
d1102dba 801\r
7c6c064c
ED
802 //\r
803 // Use a NULL password to test whether old password is required\r
804 //\r
805 *StringPtr = 0;\r
806 Status = Question->PasswordCheck (gFormData, Question, StringPtr);\r
807 if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {\r
808 //\r
d1102dba 809 // Password can't be set now.\r
7c6c064c 810 //\r
88f0c4e2
DB
811 if (Status == EFI_UNSUPPORTED) {\r
812 do {\r
813 CreateDialog (&Key, gEmptyString, gPasswordUnsupported, gPressEnter, gEmptyString, NULL);\r
814 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
815 }\r
7c6c064c
ED
816 FreePool (StringPtr);\r
817 return EFI_SUCCESS;\r
818 }\r
819\r
820 if (EFI_ERROR (Status)) {\r
821 //\r
822 // Old password exist, ask user for the old password\r
823 //\r
824 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);\r
825 if (EFI_ERROR (Status)) {\r
f1d78c48 826 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
7c6c064c
ED
827 FreePool (StringPtr);\r
828 return Status;\r
829 }\r
830\r
831 //\r
832 // Check user input old password\r
833 //\r
834 Status = Question->PasswordCheck (gFormData, Question, StringPtr);\r
835 if (EFI_ERROR (Status)) {\r
836 if (Status == EFI_NOT_READY) {\r
837 //\r
838 // Typed in old password incorrect\r
839 //\r
840 PasswordInvalid ();\r
841 } else {\r
842 Status = EFI_SUCCESS;\r
843 }\r
f1d78c48 844 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
7c6c064c
ED
845 FreePool (StringPtr);\r
846 return Status;\r
847 }\r
848 }\r
d1102dba 849\r
7c6c064c
ED
850 //\r
851 // Ask for new password\r
852 //\r
853 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
854 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);\r
855 if (EFI_ERROR (Status)) {\r
856 //\r
857 // Reset state machine for password\r
858 //\r
859 Question->PasswordCheck (gFormData, Question, NULL);\r
f1d78c48 860 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
7c6c064c
ED
861 FreePool (StringPtr);\r
862 return Status;\r
863 }\r
d1102dba 864\r
7c6c064c
ED
865 //\r
866 // Confirm new password\r
867 //\r
868 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
869 ASSERT (TempString);\r
870 Status = ReadString (MenuOption, gConfirmPassword, TempString);\r
871 if (EFI_ERROR (Status)) {\r
872 //\r
873 // Reset state machine for password\r
874 //\r
875 Question->PasswordCheck (gFormData, Question, NULL);\r
f1d78c48
DB
876 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
877 ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16));\r
7c6c064c
ED
878 FreePool (StringPtr);\r
879 FreePool (TempString);\r
880 return Status;\r
881 }\r
d1102dba 882\r
7c6c064c
ED
883 //\r
884 // Compare two typed-in new passwords\r
885 //\r
d1102dba 886 if (StrCmp (StringPtr, TempString) == 0) {\r
7c6c064c
ED
887 gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);\r
888 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
889 gUserInput->InputValue.Type = Question->CurrentValue.Type;\r
890 gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);\r
7c6c064c 891\r
bfae1330 892 Status = EFI_SUCCESS;\r
7c6c064c
ED
893 } else {\r
894 //\r
895 // Reset state machine for password\r
896 //\r
897 Question->PasswordCheck (gFormData, Question, NULL);\r
d1102dba 898\r
7c6c064c
ED
899 //\r
900 // Two password mismatch, prompt error message\r
901 //\r
902 do {\r
903 CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL);\r
904 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
905\r
906 Status = EFI_INVALID_PARAMETER;\r
907 }\r
a275df8f
DB
908 ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16));\r
909 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
7c6c064c
ED
910 FreePool (TempString);\r
911 FreePool (StringPtr);\r
912\r
913 return Status;\r
914}\r
915\r
916/**\r
917 Process a Question's Option (whether selected or un-selected).\r
918\r
919 @param MenuOption The MenuOption for this Question.\r
920 @param Selected TRUE: if Question is selected.\r
921 @param OptionString Pointer of the Option String to be displayed.\r
922 @param SkipErrorValue Whether need to return when value without option for it.\r
923\r
924 @retval EFI_SUCCESS Question Option process success.\r
925 @retval Other Question Option process fail.\r
926\r
927**/\r
928EFI_STATUS\r
929ProcessOptions (\r
930 IN UI_MENU_OPTION *MenuOption,\r
931 IN BOOLEAN Selected,\r
932 OUT CHAR16 **OptionString,\r
933 IN BOOLEAN SkipErrorValue\r
934 )\r
935{\r
936 EFI_STATUS Status;\r
937 CHAR16 *StringPtr;\r
938 UINTN Index;\r
939 FORM_DISPLAY_ENGINE_STATEMENT *Question;\r
940 CHAR16 FormattedNumber[21];\r
941 UINT16 Number;\r
942 CHAR16 Character[2];\r
943 EFI_INPUT_KEY Key;\r
944 UINTN BufferSize;\r
945 DISPLAY_QUESTION_OPTION *OneOfOption;\r
946 LIST_ENTRY *Link;\r
947 EFI_HII_VALUE HiiValue;\r
948 EFI_HII_VALUE *QuestionValue;\r
949 DISPLAY_QUESTION_OPTION *Option;\r
950 UINTN Index2;\r
951 UINT8 *ValueArray;\r
952 UINT8 ValueType;\r
7c6c064c
ED
953 EFI_IFR_ORDERED_LIST *OrderList;\r
954 BOOLEAN ValueInvalid;\r
5ad66ec6 955 UINTN MaxLen;\r
7c6c064c
ED
956\r
957 Status = EFI_SUCCESS;\r
958\r
959 StringPtr = NULL;\r
960 Character[1] = L'\0';\r
961 *OptionString = NULL;\r
7c6c064c
ED
962 ValueInvalid = FALSE;\r
963\r
964 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));\r
965 BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow;\r
966\r
967 Question = MenuOption->ThisTag;\r
968 QuestionValue = &Question->CurrentValue;\r
969\r
970 switch (Question->OpCode->OpCode) {\r
971 case EFI_IFR_ORDERED_LIST_OP:\r
972\r
973 //\r
974 // Check whether there are Options of this OrderedList\r
975 //\r
976 if (IsListEmpty (&Question->OptionListHead)) {\r
977 break;\r
978 }\r
979\r
980 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;\r
981\r
982 Link = GetFirstNode (&Question->OptionListHead);\r
983 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
984\r
985 ValueType = OneOfOption->OptionOpCode->Type;\r
986 ValueArray = Question->CurrentValue.Buffer;\r
987\r
988 if (Selected) {\r
989 //\r
990 // Go ask for input\r
991 //\r
992 Status = GetSelectionInputPopUp (MenuOption);\r
993 } else {\r
994 //\r
995 // We now know how many strings we will have, so we can allocate the\r
996 // space required for the array or strings.\r
997 //\r
5ad66ec6
DB
998 MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16);\r
999 *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16));\r
7c6c064c
ED
1000 ASSERT (*OptionString);\r
1001\r
1002 HiiValue.Type = ValueType;\r
1003 HiiValue.Value.u64 = 0;\r
1004 for (Index = 0; Index < OrderList->MaxContainers; Index++) {\r
1005 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
1006 if (HiiValue.Value.u64 == 0) {\r
1007 //\r
1008 // Values for the options in ordered lists should never be a 0\r
1009 //\r
1010 break;\r
1011 }\r
1012\r
1013 OneOfOption = ValueToOption (Question, &HiiValue);\r
1014 if (OneOfOption == NULL) {\r
1015 if (SkipErrorValue) {\r
1016 //\r
1017 // Just try to get the option string, skip the value which not has option.\r
1018 //\r
1019 continue;\r
1020 }\r
1021\r
1022 //\r
1023 // Show error message\r
1024 //\r
1025 do {\r
1026 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);\r
1027 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1028\r
1029 //\r
1030 // The initial value of the orderedlist is invalid, force to be valid value\r
1031 // Exit current DisplayForm with new value.\r
1032 //\r
1033 gUserInput->SelectedStatement = Question;\r
42645c3d 1034 gMisMatch = TRUE;\r
7c6c064c
ED
1035 ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen);\r
1036 ASSERT (ValueArray != NULL);\r
1037 gUserInput->InputValue.Buffer = ValueArray;\r
1038 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
1039 gUserInput->InputValue.Type = Question->CurrentValue.Type;\r
d1102dba 1040\r
7c6c064c
ED
1041 Link = GetFirstNode (&Question->OptionListHead);\r
1042 Index2 = 0;\r
1043 while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) {\r
1044 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1045 Link = GetNextNode (&Question->OptionListHead, Link);\r
1046 SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64);\r
1047 Index2++;\r
1048 }\r
1049 SetArrayData (ValueArray, ValueType, Index2, 0);\r
1050\r
1051 FreePool (*OptionString);\r
1052 *OptionString = NULL;\r
1053 return EFI_NOT_FOUND;\r
1054 }\r
1055\r
1056 Character[0] = LEFT_ONEOF_DELIMITER;\r
5ad66ec6 1057 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1058 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
1059 ASSERT (StringPtr != NULL);\r
5ad66ec6 1060 NewStrCat (OptionString[0], MaxLen, StringPtr);\r
7c6c064c 1061 Character[0] = RIGHT_ONEOF_DELIMITER;\r
5ad66ec6 1062 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c 1063 Character[0] = CHAR_CARRIAGE_RETURN;\r
5ad66ec6 1064 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1065 FreePool (StringPtr);\r
1066 }\r
1067\r
1068 //\r
1069 // If valid option more than the max container, skip these options.\r
1070 //\r
1071 if (Index >= OrderList->MaxContainers) {\r
1072 break;\r
1073 }\r
1074\r
1075 //\r
1076 // Search the other options, try to find the one not in the container.\r
1077 //\r
1078 Link = GetFirstNode (&Question->OptionListHead);\r
1079 while (!IsNull (&Question->OptionListHead, Link)) {\r
1080 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1081 Link = GetNextNode (&Question->OptionListHead, Link);\r
1082\r
1083 if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) {\r
1084 continue;\r
1085 }\r
1086\r
1087 if (SkipErrorValue) {\r
1088 //\r
1089 // Not report error, just get the correct option string info.\r
1090 //\r
1091 Character[0] = LEFT_ONEOF_DELIMITER;\r
5ad66ec6 1092 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1093 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
1094 ASSERT (StringPtr != NULL);\r
5ad66ec6 1095 NewStrCat (OptionString[0], MaxLen, StringPtr);\r
7c6c064c 1096 Character[0] = RIGHT_ONEOF_DELIMITER;\r
5ad66ec6 1097 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c 1098 Character[0] = CHAR_CARRIAGE_RETURN;\r
5ad66ec6 1099 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1100 FreePool (StringPtr);\r
1101\r
1102 continue;\r
1103 }\r
1104\r
1105 if (!ValueInvalid) {\r
1106 ValueInvalid = TRUE;\r
1107 //\r
1108 // Show error message\r
1109 //\r
1110 do {\r
1111 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);\r
1112 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1113\r
1114 //\r
1115 // The initial value of the orderedlist is invalid, force to be valid value\r
1116 // Exit current DisplayForm with new value.\r
1117 //\r
1118 gUserInput->SelectedStatement = Question;\r
42645c3d 1119 gMisMatch = TRUE;\r
7c6c064c
ED
1120 ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer);\r
1121 ASSERT (ValueArray != NULL);\r
1122 gUserInput->InputValue.Buffer = ValueArray;\r
1123 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
1124 gUserInput->InputValue.Type = Question->CurrentValue.Type;\r
1125 }\r
d1102dba 1126\r
7c6c064c
ED
1127 SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64);\r
1128 }\r
1129\r
1130 if (ValueInvalid) {\r
1131 FreePool (*OptionString);\r
1132 *OptionString = NULL;\r
1133 return EFI_NOT_FOUND;\r
1134 }\r
1135 }\r
1136 break;\r
1137\r
1138 case EFI_IFR_ONE_OF_OP:\r
1139 //\r
1140 // Check whether there are Options of this OneOf\r
1141 //\r
1142 if (IsListEmpty (&Question->OptionListHead)) {\r
1143 break;\r
1144 }\r
1145 if (Selected) {\r
1146 //\r
1147 // Go ask for input\r
1148 //\r
1149 Status = GetSelectionInputPopUp (MenuOption);\r
1150 } else {\r
5ad66ec6 1151 MaxLen = BufferSize / sizeof(CHAR16);\r
7c6c064c
ED
1152 *OptionString = AllocateZeroPool (BufferSize);\r
1153 ASSERT (*OptionString);\r
1154\r
1155 OneOfOption = ValueToOption (Question, QuestionValue);\r
1156 if (OneOfOption == NULL) {\r
1157 if (SkipErrorValue) {\r
1158 //\r
1159 // Not report error, just get the correct option string info.\r
d1102dba 1160 //\r
7c6c064c
ED
1161 Link = GetFirstNode (&Question->OptionListHead);\r
1162 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1163 } else {\r
1164 //\r
1165 // Show error message\r
1166 //\r
1167 do {\r
1168 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);\r
1169 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1170\r
1171 //\r
1172 // Force the Question value to be valid\r
1173 // Exit current DisplayForm with new value.\r
1174 //\r
1175 Link = GetFirstNode (&Question->OptionListHead);\r
1176 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1177\r
7c6c064c 1178 gUserInput->InputValue.Type = Option->OptionOpCode->Type;\r
d63a9eb4
ED
1179 switch (gUserInput->InputValue.Type) {\r
1180 case EFI_IFR_TYPE_NUM_SIZE_8:\r
1181 gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8;\r
1182 break;\r
1183 case EFI_IFR_TYPE_NUM_SIZE_16:\r
1184 CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16));\r
1185 break;\r
1186 case EFI_IFR_TYPE_NUM_SIZE_32:\r
1187 CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32));\r
1188 break;\r
1189 case EFI_IFR_TYPE_NUM_SIZE_64:\r
1190 CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64));\r
1191 break;\r
1192 default:\r
1193 ASSERT (FALSE);\r
1194 break;\r
1195 }\r
7c6c064c 1196 gUserInput->SelectedStatement = Question;\r
42645c3d 1197 gMisMatch = TRUE;\r
7c6c064c
ED
1198 FreePool (*OptionString);\r
1199 *OptionString = NULL;\r
1200 return EFI_NOT_FOUND;\r
1201 }\r
1202 }\r
1203\r
1204 Character[0] = LEFT_ONEOF_DELIMITER;\r
5ad66ec6 1205 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1206 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
1207 ASSERT (StringPtr != NULL);\r
5ad66ec6 1208 NewStrCat (OptionString[0], MaxLen, StringPtr);\r
7c6c064c 1209 Character[0] = RIGHT_ONEOF_DELIMITER;\r
5ad66ec6 1210 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1211\r
1212 FreePool (StringPtr);\r
1213 }\r
1214 break;\r
1215\r
1216 case EFI_IFR_CHECKBOX_OP:\r
1217 if (Selected) {\r
1218 //\r
1219 // Since this is a BOOLEAN operation, flip it upon selection\r
1220 //\r
1221 gUserInput->InputValue.Type = QuestionValue->Type;\r
1222 gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);\r
1223\r
1224 //\r
1225 // Perform inconsistent check\r
1226 //\r
bfae1330 1227 return EFI_SUCCESS;\r
d1102dba 1228 } else {\r
7c6c064c
ED
1229 *OptionString = AllocateZeroPool (BufferSize);\r
1230 ASSERT (*OptionString);\r
1231\r
1232 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;\r
1233\r
1234 if (QuestionValue->Value.b) {\r
1235 *(OptionString[0] + 1) = CHECK_ON;\r
1236 } else {\r
1237 *(OptionString[0] + 1) = CHECK_OFF;\r
1238 }\r
1239 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;\r
1240 }\r
1241 break;\r
1242\r
1243 case EFI_IFR_NUMERIC_OP:\r
1244 if (Selected) {\r
1245 //\r
1246 // Go ask for input\r
1247 //\r
1248 Status = GetNumericInput (MenuOption);\r
1249 } else {\r
1250 *OptionString = AllocateZeroPool (BufferSize);\r
1251 ASSERT (*OptionString);\r
1252\r
1253 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
1254\r
1255 //\r
1256 // Formatted print\r
1257 //\r
1258 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
1259 Number = (UINT16) GetStringWidth (FormattedNumber);\r
1260 CopyMem (OptionString[0] + 1, FormattedNumber, Number);\r
1261\r
1262 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;\r
1263 }\r
1264 break;\r
1265\r
1266 case EFI_IFR_DATE_OP:\r
1267 if (Selected) {\r
1268 //\r
1269 // This is similar to numerics\r
1270 //\r
1271 Status = GetNumericInput (MenuOption);\r
1272 } else {\r
1273 *OptionString = AllocateZeroPool (BufferSize);\r
1274 ASSERT (*OptionString);\r
1275\r
1276 switch (MenuOption->Sequence) {\r
1277 case 0:\r
1278 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
cc63add8
DB
1279 if (QuestionValue->Value.date.Month == 0xff){\r
1280 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");\r
1281 } else {\r
1282 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);\r
1283 }\r
7c6c064c
ED
1284 *(OptionString[0] + 3) = DATE_SEPARATOR;\r
1285 break;\r
1286\r
1287 case 1:\r
1288 SetUnicodeMem (OptionString[0], 4, L' ');\r
cc63add8
DB
1289 if (QuestionValue->Value.date.Day == 0xff){\r
1290 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");\r
1291 } else {\r
1292 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);\r
1293 }\r
7c6c064c
ED
1294 *(OptionString[0] + 6) = DATE_SEPARATOR;\r
1295 break;\r
1296\r
1297 case 2:\r
1298 SetUnicodeMem (OptionString[0], 7, L' ');\r
cc63add8
DB
1299 if (QuestionValue->Value.date.Year == 0xff){\r
1300 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????");\r
1301 } else {\r
1302 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year);\r
1303 }\r
7c6c064c
ED
1304 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;\r
1305 break;\r
1306 }\r
1307 }\r
1308 break;\r
1309\r
1310 case EFI_IFR_TIME_OP:\r
1311 if (Selected) {\r
1312 //\r
1313 // This is similar to numerics\r
1314 //\r
1315 Status = GetNumericInput (MenuOption);\r
1316 } else {\r
1317 *OptionString = AllocateZeroPool (BufferSize);\r
1318 ASSERT (*OptionString);\r
1319\r
1320 switch (MenuOption->Sequence) {\r
1321 case 0:\r
1322 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
cc63add8
DB
1323 if (QuestionValue->Value.time.Hour == 0xff){\r
1324 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");\r
1325 } else {\r
1326 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);\r
1327 }\r
7c6c064c
ED
1328 *(OptionString[0] + 3) = TIME_SEPARATOR;\r
1329 break;\r
1330\r
1331 case 1:\r
1332 SetUnicodeMem (OptionString[0], 4, L' ');\r
cc63add8
DB
1333 if (QuestionValue->Value.time.Minute == 0xff){\r
1334 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");\r
1335 } else {\r
1336 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);\r
1337 }\r
7c6c064c
ED
1338 *(OptionString[0] + 6) = TIME_SEPARATOR;\r
1339 break;\r
1340\r
1341 case 2:\r
1342 SetUnicodeMem (OptionString[0], 7, L' ');\r
cc63add8
DB
1343 if (QuestionValue->Value.time.Second == 0xff){\r
1344 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??");\r
1345 } else {\r
1346 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);\r
1347 }\r
7c6c064c
ED
1348 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;\r
1349 break;\r
1350 }\r
1351 }\r
1352 break;\r
1353\r
1354 case EFI_IFR_STRING_OP:\r
1355 if (Selected) {\r
1356 StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16));\r
1357 ASSERT (StringPtr);\r
1358 CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);\r
1359\r
1360 Status = ReadString (MenuOption, gPromptForData, StringPtr);\r
1361 if (EFI_ERROR (Status)) {\r
1362 FreePool (StringPtr);\r
1363 return Status;\r
1364 }\r
d1102dba 1365\r
7c6c064c
ED
1366 gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);\r
1367 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
1368 gUserInput->InputValue.Type = Question->CurrentValue.Type;\r
1369 gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);\r
1370 FreePool (StringPtr);\r
bfae1330 1371 return EFI_SUCCESS;\r
7c6c064c
ED
1372 } else {\r
1373 *OptionString = AllocateZeroPool (BufferSize);\r
1374 ASSERT (*OptionString);\r
1375\r
1376 if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) {\r
1377 *(OptionString[0]) = '_';\r
1378 } else {\r
1379 if (Question->CurrentValue.BufferLen < BufferSize) {\r
1380 BufferSize = Question->CurrentValue.BufferLen;\r
1381 }\r
1382 CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize);\r
1383 }\r
1384 }\r
1385 break;\r
1386\r
1387 case EFI_IFR_PASSWORD_OP:\r
1388 if (Selected) {\r
1389 Status = PasswordProcess (MenuOption);\r
1390 }\r
1391 break;\r
1392\r
1393 default:\r
1394 break;\r
1395 }\r
1396\r
1397 return Status;\r
1398}\r
1399\r
1400\r
1401/**\r
1402 Process the help string: Split StringPtr to several lines of strings stored in\r
1403 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.\r
1404\r
1405 @param StringPtr The entire help string.\r
1406 @param FormattedString The oupput formatted string.\r
1407 @param EachLineWidth The max string length of each line in the formatted string.\r
1408 @param RowCount TRUE: if Question is selected.\r
1409\r
1410**/\r
1411UINTN\r
1412ProcessHelpString (\r
1413 IN CHAR16 *StringPtr,\r
1414 OUT CHAR16 **FormattedString,\r
1415 OUT UINT16 *EachLineWidth,\r
1416 IN UINTN RowCount\r
1417 )\r
1418{\r
1419 UINTN Index;\r
1420 CHAR16 *OutputString;\r
1421 UINTN TotalRowNum;\r
1422 UINTN CheckedNum;\r
1423 UINT16 GlyphWidth;\r
1424 UINT16 LineWidth;\r
1425 UINT16 MaxStringLen;\r
1426 UINT16 StringLen;\r
1427\r
1428 TotalRowNum = 0;\r
1429 CheckedNum = 0;\r
1430 GlyphWidth = 1;\r
1431 Index = 0;\r
1432 MaxStringLen = 0;\r
1433 StringLen = 0;\r
1434\r
1435 //\r
1436 // Set default help string width.\r
1437 //\r
1438 LineWidth = (UINT16) (gHelpBlockWidth - 1);\r
1439\r
1440 //\r
1441 // Get row number of the String.\r
1442 //\r
1443 while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {\r
1444 if (StringLen > MaxStringLen) {\r
1445 MaxStringLen = StringLen;\r
1446 }\r
1447\r
1448 TotalRowNum ++;\r
1449 FreePool (OutputString);\r
1450 }\r
1451 *EachLineWidth = MaxStringLen;\r
1452\r
1453 *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));\r
1454 ASSERT (*FormattedString != NULL);\r
1455\r
1456 //\r
1457 // Generate formatted help string array.\r
1458 //\r
1459 GlyphWidth = 1;\r
1460 Index = 0;\r
1461 while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {\r
1462 CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));\r
1463 CheckedNum ++;\r
1464 FreePool (OutputString);\r
1465 }\r
1466\r
d1102dba 1467 return TotalRowNum;\r
7c6c064c 1468}\r