]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c
Rollback patch 14537 & 14538, because patch 14537 is not tested by Laszlo Ersek,...
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / ProcessOptions.c
1 /** @file
2 Implementation for handling the User Interface option processing.
3
4
5 Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "Setup.h"
17
18
19 /**
20 Process Question Config.
21
22 @param Selection The UI menu selection.
23 @param Question The Question to be peocessed.
24
25 @retval EFI_SUCCESS Question Config process success.
26 @retval Other Question Config process fail.
27
28 **/
29 EFI_STATUS
30 ProcessQuestionConfig (
31 IN UI_MENU_SELECTION *Selection,
32 IN FORM_BROWSER_STATEMENT *Question
33 )
34 {
35 EFI_STATUS Status;
36 CHAR16 *ConfigResp;
37 CHAR16 *Progress;
38 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
39
40 if (Question->QuestionConfig == 0) {
41 return EFI_SUCCESS;
42 }
43
44 //
45 // Get <ConfigResp>
46 //
47 ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
48 if (ConfigResp == NULL) {
49 return EFI_NOT_FOUND;
50 }
51
52 //
53 // Send config to Configuration Driver
54 //
55 ConfigAccess = Selection->FormSet->ConfigAccess;
56 if (ConfigAccess == NULL) {
57 return EFI_UNSUPPORTED;
58 }
59 Status = ConfigAccess->RouteConfig (
60 ConfigAccess,
61 ConfigResp,
62 &Progress
63 );
64
65 return Status;
66 }
67
68
69 /**
70 Search an Option of a Question by its value.
71
72 @param Question The Question
73 @param OptionValue Value for Option to be searched.
74
75 @retval Pointer Pointer to the found Option.
76 @retval NULL Option not found.
77
78 **/
79 QUESTION_OPTION *
80 ValueToOption (
81 IN FORM_BROWSER_STATEMENT *Question,
82 IN EFI_HII_VALUE *OptionValue
83 )
84 {
85 LIST_ENTRY *Link;
86 QUESTION_OPTION *Option;
87 INTN Result;
88
89 Link = GetFirstNode (&Question->OptionListHead);
90 while (!IsNull (&Question->OptionListHead, Link)) {
91 Option = QUESTION_OPTION_FROM_LINK (Link);
92
93 if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
94 //
95 // Check the suppressif condition, only a valid option can be return.
96 //
97 if ((Option->SuppressExpression == NULL) ||
98 ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {
99 return Option;
100 }
101 }
102
103 Link = GetNextNode (&Question->OptionListHead, Link);
104 }
105
106 return NULL;
107 }
108
109
110 /**
111 Return data element in an Array by its Index.
112
113 @param Array The data array.
114 @param Type Type of the data in this array.
115 @param Index Zero based index for data in this array.
116
117 @retval Value The data to be returned
118
119 **/
120 UINT64
121 GetArrayData (
122 IN VOID *Array,
123 IN UINT8 Type,
124 IN UINTN Index
125 )
126 {
127 UINT64 Data;
128
129 ASSERT (Array != NULL);
130
131 Data = 0;
132 switch (Type) {
133 case EFI_IFR_TYPE_NUM_SIZE_8:
134 Data = (UINT64) *(((UINT8 *) Array) + Index);
135 break;
136
137 case EFI_IFR_TYPE_NUM_SIZE_16:
138 Data = (UINT64) *(((UINT16 *) Array) + Index);
139 break;
140
141 case EFI_IFR_TYPE_NUM_SIZE_32:
142 Data = (UINT64) *(((UINT32 *) Array) + Index);
143 break;
144
145 case EFI_IFR_TYPE_NUM_SIZE_64:
146 Data = (UINT64) *(((UINT64 *) Array) + Index);
147 break;
148
149 default:
150 break;
151 }
152
153 return Data;
154 }
155
156
157 /**
158 Set value of a data element in an Array by its Index.
159
160 @param Array The data array.
161 @param Type Type of the data in this array.
162 @param Index Zero based index for data in this array.
163 @param Value The value to be set.
164
165 **/
166 VOID
167 SetArrayData (
168 IN VOID *Array,
169 IN UINT8 Type,
170 IN UINTN Index,
171 IN UINT64 Value
172 )
173 {
174
175 ASSERT (Array != NULL);
176
177 switch (Type) {
178 case EFI_IFR_TYPE_NUM_SIZE_8:
179 *(((UINT8 *) Array) + Index) = (UINT8) Value;
180 break;
181
182 case EFI_IFR_TYPE_NUM_SIZE_16:
183 *(((UINT16 *) Array) + Index) = (UINT16) Value;
184 break;
185
186 case EFI_IFR_TYPE_NUM_SIZE_32:
187 *(((UINT32 *) Array) + Index) = (UINT32) Value;
188 break;
189
190 case EFI_IFR_TYPE_NUM_SIZE_64:
191 *(((UINT64 *) Array) + Index) = (UINT64) Value;
192 break;
193
194 default:
195 break;
196 }
197 }
198
199 /**
200 Check whether this value already in the array, if yes, return the index.
201
202 @param Array The data array.
203 @param Type Type of the data in this array.
204 @param Value The value to be find.
205 @param Index The index in the array which has same value with Value.
206
207 @retval TRUE Found the value in the array.
208 @retval FALSE Not found the value.
209
210 **/
211 BOOLEAN
212 FindArrayData (
213 IN VOID *Array,
214 IN UINT8 Type,
215 IN UINT64 Value,
216 OUT UINTN *Index OPTIONAL
217 )
218 {
219 UINTN Count;
220 UINT64 TmpValue;
221
222 ASSERT (Array != NULL);
223
224 Count = 0;
225 TmpValue = 0;
226
227 while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {
228 if (Value == TmpValue) {
229 if (Index != NULL) {
230 *Index = Count;
231 }
232 return TRUE;
233 }
234
235 Count ++;
236 }
237
238 return FALSE;
239 }
240
241 /**
242 Print Question Value according to it's storage width and display attributes.
243
244 @param Question The Question to be printed.
245 @param FormattedNumber Buffer for output string.
246 @param BufferSize The FormattedNumber buffer size in bytes.
247
248 @retval EFI_SUCCESS Print success.
249 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
250
251 **/
252 EFI_STATUS
253 PrintFormattedNumber (
254 IN FORM_BROWSER_STATEMENT *Question,
255 IN OUT CHAR16 *FormattedNumber,
256 IN UINTN BufferSize
257 )
258 {
259 INT64 Value;
260 CHAR16 *Format;
261 EFI_HII_VALUE *QuestionValue;
262
263 if (BufferSize < (21 * sizeof (CHAR16))) {
264 return EFI_BUFFER_TOO_SMALL;
265 }
266
267 QuestionValue = &Question->HiiValue;
268
269 Value = (INT64) QuestionValue->Value.u64;
270 switch (Question->Flags & EFI_IFR_DISPLAY) {
271 case EFI_IFR_DISPLAY_INT_DEC:
272 switch (QuestionValue->Type) {
273 case EFI_IFR_NUMERIC_SIZE_1:
274 Value = (INT64) ((INT8) QuestionValue->Value.u8);
275 break;
276
277 case EFI_IFR_NUMERIC_SIZE_2:
278 Value = (INT64) ((INT16) QuestionValue->Value.u16);
279 break;
280
281 case EFI_IFR_NUMERIC_SIZE_4:
282 Value = (INT64) ((INT32) QuestionValue->Value.u32);
283 break;
284
285 case EFI_IFR_NUMERIC_SIZE_8:
286 default:
287 break;
288 }
289
290 if (Value < 0) {
291 Value = -Value;
292 Format = L"-%ld";
293 } else {
294 Format = L"%ld";
295 }
296 break;
297
298 case EFI_IFR_DISPLAY_UINT_DEC:
299 Format = L"%ld";
300 break;
301
302 case EFI_IFR_DISPLAY_UINT_HEX:
303 Format = L"%lx";
304 break;
305
306 default:
307 return EFI_UNSUPPORTED;
308 break;
309 }
310
311 UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);
312
313 return EFI_SUCCESS;
314 }
315
316
317 /**
318 Password may be stored as encrypted by Configuration Driver. When change a
319 password, user will be challenged with old password. To validate user input old
320 password, we will send the clear text to Configuration Driver via Callback().
321 Configuration driver is responsible to check the passed in password and return
322 the validation result. If validation pass, state machine in password Callback()
323 will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.
324 After user type in new password twice, Callback() will be invoked to send the
325 new password to Configuration Driver.
326
327 @param Selection Pointer to UI_MENU_SELECTION.
328 @param MenuOption The MenuOption for this password Question.
329 @param String The clear text of password.
330
331 @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input.
332 @return In state of BROWSER_STATE_VALIDATE_PASSWORD:
333 @retval EFI_SUCCESS Password correct, Browser will prompt for new
334 password.
335 @retval EFI_NOT_READY Password incorrect, Browser will show error
336 message.
337 @retval Other Browser will do nothing.
338 @return In state of BROWSER_STATE_SET_PASSWORD:
339 @retval EFI_SUCCESS Set password success.
340 @retval Other Set password failed.
341
342 **/
343 EFI_STATUS
344 PasswordCallback (
345 IN UI_MENU_SELECTION *Selection,
346 IN UI_MENU_OPTION *MenuOption,
347 IN CHAR16 *String
348 )
349 {
350 EFI_STATUS Status;
351 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
352 EFI_BROWSER_ACTION_REQUEST ActionRequest;
353 EFI_IFR_TYPE_VALUE IfrTypeValue;
354
355 ConfigAccess = Selection->FormSet->ConfigAccess;
356 if (ConfigAccess == NULL) {
357 return EFI_UNSUPPORTED;
358 }
359
360 //
361 // Prepare password string in HII database
362 //
363 if (String != NULL) {
364 IfrTypeValue.string = NewString (String, Selection->FormSet->HiiHandle);
365 } else {
366 IfrTypeValue.string = 0;
367 }
368
369 //
370 // Send password to Configuration Driver for validation
371 //
372 Status = ConfigAccess->Callback (
373 ConfigAccess,
374 EFI_BROWSER_ACTION_CHANGING,
375 MenuOption->ThisTag->QuestionId,
376 MenuOption->ThisTag->HiiValue.Type,
377 &IfrTypeValue,
378 &ActionRequest
379 );
380
381 //
382 // Remove password string from HII database
383 //
384 if (String != NULL) {
385 DeleteString (IfrTypeValue.string, Selection->FormSet->HiiHandle);
386 }
387
388 return Status;
389 }
390
391
392 /**
393 Display error message for invalid password.
394
395 **/
396 VOID
397 PasswordInvalid (
398 VOID
399 )
400 {
401 EFI_INPUT_KEY Key;
402
403 //
404 // Invalid password, prompt error message
405 //
406 do {
407 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString);
408 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
409 }
410
411
412 /**
413 Process a Question's Option (whether selected or un-selected).
414
415 @param Selection Pointer to UI_MENU_SELECTION.
416 @param MenuOption The MenuOption for this Question.
417 @param Selected TRUE: if Question is selected.
418 @param OptionString Pointer of the Option String to be displayed.
419
420 @retval EFI_SUCCESS Question Option process success.
421 @retval Other Question Option process fail.
422
423 **/
424 EFI_STATUS
425 ProcessOptions (
426 IN UI_MENU_SELECTION *Selection,
427 IN UI_MENU_OPTION *MenuOption,
428 IN BOOLEAN Selected,
429 OUT CHAR16 **OptionString
430 )
431 {
432 EFI_STATUS Status;
433 CHAR16 *StringPtr;
434 CHAR16 *TempString;
435 UINTN Index;
436 FORM_BROWSER_STATEMENT *Question;
437 CHAR16 FormattedNumber[21];
438 UINT16 Number;
439 CHAR16 Character[2];
440 EFI_INPUT_KEY Key;
441 UINTN BufferSize;
442 QUESTION_OPTION *OneOfOption;
443 LIST_ENTRY *Link;
444 EFI_HII_VALUE HiiValue;
445 EFI_HII_VALUE *QuestionValue;
446 UINT16 Maximum;
447 QUESTION_OPTION *Option;
448 UINTN Index2;
449 UINT8 *ValueArray;
450 UINT8 ValueType;
451 EFI_STRING_ID StringId;
452
453 Status = EFI_SUCCESS;
454
455 StringPtr = NULL;
456 Character[1] = L'\0';
457 *OptionString = NULL;
458 StringId = 0;
459
460 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
461 BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow;
462
463 Question = MenuOption->ThisTag;
464 QuestionValue = &Question->HiiValue;
465 Maximum = (UINT16) Question->Maximum;
466
467 ValueArray = Question->BufferValue;
468 ValueType = Question->ValueType;
469
470 switch (Question->Operand) {
471 case EFI_IFR_ORDERED_LIST_OP:
472 //
473 // Check whether there are Options of this OrderedList
474 //
475 if (IsListEmpty (&Question->OptionListHead)) {
476 break;
477 }
478 //
479 // Initialize Option value array
480 //
481 if (GetArrayData (ValueArray, ValueType, 0) == 0) {
482 GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0);
483 }
484
485 if (Selected) {
486 //
487 // Go ask for input
488 //
489 Status = GetSelectionInputPopUp (Selection, MenuOption);
490 } else {
491 //
492 // We now know how many strings we will have, so we can allocate the
493 // space required for the array or strings.
494 //
495 *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize);
496 ASSERT (*OptionString);
497
498 HiiValue.Type = ValueType;
499 HiiValue.Value.u64 = 0;
500 for (Index = 0; Index < Question->MaxContainers; Index++) {
501 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
502 if (HiiValue.Value.u64 == 0) {
503 //
504 // Values for the options in ordered lists should never be a 0
505 //
506 break;
507 }
508
509 OneOfOption = ValueToOption (Question, &HiiValue);
510 if (OneOfOption == NULL) {
511 //
512 // Show error message
513 //
514 do {
515 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);
516 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
517
518 //
519 // The initial value of the orderedlist is invalid, force to be valid value
520 //
521 Link = GetFirstNode (&Question->OptionListHead);
522 Index2 = 0;
523 while (!IsNull (&Question->OptionListHead, Link) && Index2 < Question->MaxContainers) {
524 Option = QUESTION_OPTION_FROM_LINK (Link);
525 Link = GetNextNode (&Question->OptionListHead, Link);
526 if ((Option->SuppressExpression != NULL) &&
527 ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) {
528 continue;
529 }
530 SetArrayData (ValueArray, ValueType, Index2, Option->Value.Value.u64);
531 Index2++;
532 }
533 SetArrayData (ValueArray, ValueType, Index2, 0);
534
535 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);
536 UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
537
538 FreePool (*OptionString);
539 *OptionString = NULL;
540 return EFI_NOT_FOUND;
541 }
542
543 Character[0] = LEFT_ONEOF_DELIMITER;
544 NewStrCat (OptionString[0], Character);
545 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
546 ASSERT (StringPtr != NULL);
547 NewStrCat (OptionString[0], StringPtr);
548 Character[0] = RIGHT_ONEOF_DELIMITER;
549 NewStrCat (OptionString[0], Character);
550 Character[0] = CHAR_CARRIAGE_RETURN;
551 NewStrCat (OptionString[0], Character);
552 FreePool (StringPtr);
553 }
554
555 //
556 // Search the other options, try to find the one not in the container.
557 //
558 Link = GetFirstNode (&Question->OptionListHead);
559 while (!IsNull (&Question->OptionListHead, Link)) {
560 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
561 Link = GetNextNode (&Question->OptionListHead, Link);
562 if ((OneOfOption->SuppressExpression != NULL) &&
563 ((EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) {
564 continue;
565 }
566
567 if (FindArrayData (ValueArray, ValueType, OneOfOption->Value.Value.u64, NULL)) {
568 continue;
569 }
570
571 SetArrayData (ValueArray, ValueType, Index++, OneOfOption->Value.Value.u64);
572
573 Character[0] = LEFT_ONEOF_DELIMITER;
574 NewStrCat (OptionString[0], Character);
575 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
576 ASSERT (StringPtr != NULL);
577 NewStrCat (OptionString[0], StringPtr);
578 Character[0] = RIGHT_ONEOF_DELIMITER;
579 NewStrCat (OptionString[0], Character);
580 Character[0] = CHAR_CARRIAGE_RETURN;
581 NewStrCat (OptionString[0], Character);
582 FreePool (StringPtr);
583 }
584 }
585 break;
586
587 case EFI_IFR_ONE_OF_OP:
588 //
589 // Check whether there are Options of this OneOf
590 //
591 if (IsListEmpty (&Question->OptionListHead)) {
592 break;
593 }
594 if (Selected) {
595 //
596 // Go ask for input
597 //
598 Status = GetSelectionInputPopUp (Selection, MenuOption);
599 } else {
600 *OptionString = AllocateZeroPool (BufferSize);
601 ASSERT (*OptionString);
602
603 OneOfOption = ValueToOption (Question, QuestionValue);
604 if (OneOfOption == NULL) {
605 //
606 // Show error message
607 //
608 do {
609 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);
610 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
611
612 //
613 // Force the Question value to be valid
614 //
615 Link = GetFirstNode (&Question->OptionListHead);
616 while (!IsNull (&Question->OptionListHead, Link)) {
617 Option = QUESTION_OPTION_FROM_LINK (Link);
618
619 if ((Option->SuppressExpression == NULL) ||
620 (EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse)) {
621 CopyMem (QuestionValue, &Option->Value, sizeof (EFI_HII_VALUE));
622 SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);
623 UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
624 break;
625 }
626
627 Link = GetNextNode (&Question->OptionListHead, Link);
628 }
629
630 FreePool (*OptionString);
631 *OptionString = NULL;
632 return EFI_NOT_FOUND;
633 }
634
635 Character[0] = LEFT_ONEOF_DELIMITER;
636 NewStrCat (OptionString[0], Character);
637 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
638 ASSERT (StringPtr != NULL);
639 NewStrCat (OptionString[0], StringPtr);
640 Character[0] = RIGHT_ONEOF_DELIMITER;
641 NewStrCat (OptionString[0], Character);
642
643 FreePool (StringPtr);
644 }
645 break;
646
647 case EFI_IFR_CHECKBOX_OP:
648 *OptionString = AllocateZeroPool (BufferSize);
649 ASSERT (*OptionString);
650
651 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
652
653 if (Selected) {
654 //
655 // Since this is a BOOLEAN operation, flip it upon selection
656 //
657 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
658
659 //
660 // Perform inconsistent check
661 //
662 Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
663 if (EFI_ERROR (Status)) {
664 //
665 // Inconsistent check fail, restore Question Value
666 //
667 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
668 FreePool (*OptionString);
669 *OptionString = NULL;
670 return Status;
671 }
672
673 //
674 // Save Question value
675 //
676 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);
677 UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
678 }
679
680 if (QuestionValue->Value.b) {
681 *(OptionString[0] + 1) = CHECK_ON;
682 } else {
683 *(OptionString[0] + 1) = CHECK_OFF;
684 }
685 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
686 break;
687
688 case EFI_IFR_NUMERIC_OP:
689 if (Selected) {
690 //
691 // Go ask for input
692 //
693 Status = GetNumericInput (Selection, MenuOption);
694 } else {
695 *OptionString = AllocateZeroPool (BufferSize);
696 ASSERT (*OptionString);
697
698 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
699
700 //
701 // Formatted print
702 //
703 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
704 Number = (UINT16) GetStringWidth (FormattedNumber);
705 CopyMem (OptionString[0] + 1, FormattedNumber, Number);
706
707 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
708 }
709 break;
710
711 case EFI_IFR_DATE_OP:
712 if (Selected) {
713 //
714 // This is similar to numerics
715 //
716 Status = GetNumericInput (Selection, MenuOption);
717 } else {
718 *OptionString = AllocateZeroPool (BufferSize);
719 ASSERT (*OptionString);
720
721 switch (MenuOption->Sequence) {
722 case 0:
723 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
724 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
725 *(OptionString[0] + 3) = DATE_SEPARATOR;
726 break;
727
728 case 1:
729 SetUnicodeMem (OptionString[0], 4, L' ');
730 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
731 *(OptionString[0] + 6) = DATE_SEPARATOR;
732 break;
733
734 case 2:
735 SetUnicodeMem (OptionString[0], 7, L' ');
736 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year);
737 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
738 break;
739 }
740 }
741 break;
742
743 case EFI_IFR_TIME_OP:
744 if (Selected) {
745 //
746 // This is similar to numerics
747 //
748 Status = GetNumericInput (Selection, MenuOption);
749 } else {
750 *OptionString = AllocateZeroPool (BufferSize);
751 ASSERT (*OptionString);
752
753 switch (MenuOption->Sequence) {
754 case 0:
755 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
756 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
757 *(OptionString[0] + 3) = TIME_SEPARATOR;
758 break;
759
760 case 1:
761 SetUnicodeMem (OptionString[0], 4, L' ');
762 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
763 *(OptionString[0] + 6) = TIME_SEPARATOR;
764 break;
765
766 case 2:
767 SetUnicodeMem (OptionString[0], 7, L' ');
768 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
769 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
770 break;
771 }
772 }
773 break;
774
775 case EFI_IFR_STRING_OP:
776 if (Selected) {
777 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
778 ASSERT (StringPtr);
779 CopyMem(StringPtr, Question->BufferValue, Maximum * sizeof (CHAR16));
780
781 Status = ReadString (MenuOption, gPromptForData, StringPtr);
782 if (!EFI_ERROR (Status)) {
783 HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL);
784 Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
785 if (EFI_ERROR (Status)) {
786 HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
787 } else {
788 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
789 SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);
790
791 UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
792 }
793 }
794
795 FreePool (StringPtr);
796 } else {
797 *OptionString = AllocateZeroPool (BufferSize);
798 ASSERT (*OptionString);
799
800 if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) {
801 *(OptionString[0]) = '_';
802 } else {
803 if ((Maximum * sizeof (CHAR16)) < BufferSize) {
804 BufferSize = Maximum * sizeof (CHAR16);
805 }
806 CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize);
807 }
808 }
809 break;
810
811 case EFI_IFR_PASSWORD_OP:
812 if (Selected) {
813 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
814 ASSERT (StringPtr);
815
816 //
817 // For interactive passwords, old password is validated by callback
818 //
819 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
820 //
821 // Use a NULL password to test whether old password is required
822 //
823 *StringPtr = 0;
824 Status = PasswordCallback (Selection, MenuOption, StringPtr);
825 if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {
826 //
827 // Callback is not supported, or
828 // Callback request to terminate password input
829 //
830 FreePool (StringPtr);
831 return EFI_SUCCESS;
832 }
833
834 if (EFI_ERROR (Status)) {
835 //
836 // Old password exist, ask user for the old password
837 //
838 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
839 if (EFI_ERROR (Status)) {
840 FreePool (StringPtr);
841 return Status;
842 }
843
844 //
845 // Check user input old password
846 //
847 Status = PasswordCallback (Selection, MenuOption, StringPtr);
848 if (EFI_ERROR (Status)) {
849 if (Status == EFI_NOT_READY) {
850 //
851 // Typed in old password incorrect
852 //
853 PasswordInvalid ();
854 } else {
855 Status = EFI_SUCCESS;
856 }
857
858 FreePool (StringPtr);
859 return Status;
860 }
861 }
862 } else {
863 //
864 // For non-interactive password, validate old password in local
865 //
866 if (*((CHAR16 *) Question->BufferValue) != 0) {
867 //
868 // There is something there! Prompt for password
869 //
870 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
871 if (EFI_ERROR (Status)) {
872 FreePool (StringPtr);
873 return Status;
874 }
875
876 TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue);
877 ASSERT (TempString != NULL);
878
879 TempString[Maximum] = L'\0';
880
881 if (StrCmp (StringPtr, TempString) != 0) {
882 //
883 // Typed in old password incorrect
884 //
885 PasswordInvalid ();
886
887 FreePool (StringPtr);
888 FreePool (TempString);
889 return Status;
890 }
891
892 FreePool (TempString);
893 }
894 }
895
896 //
897 // Ask for new password
898 //
899 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
900 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
901 if (EFI_ERROR (Status)) {
902 //
903 // Reset state machine for interactive password
904 //
905 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
906 PasswordCallback (Selection, MenuOption, NULL);
907 }
908
909 FreePool (StringPtr);
910 return Status;
911 }
912
913 //
914 // Confirm new password
915 //
916 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
917 ASSERT (TempString);
918 Status = ReadString (MenuOption, gConfirmPassword, TempString);
919 if (EFI_ERROR (Status)) {
920 //
921 // Reset state machine for interactive password
922 //
923 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
924 PasswordCallback (Selection, MenuOption, NULL);
925 }
926
927 FreePool (StringPtr);
928 FreePool (TempString);
929 return Status;
930 }
931
932 //
933 // Compare two typed-in new passwords
934 //
935 if (StrCmp (StringPtr, TempString) == 0) {
936 //
937 // Prepare the Question->HiiValue.Value.string for ValidateQuestion use.
938 //
939 if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
940 StringId = Question->HiiValue.Value.string;
941 Question->HiiValue.Value.string = NewString (StringPtr, Selection->FormSet->HiiHandle);
942 } else {
943 HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL);
944 }
945
946 Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
947
948 //
949 // Researve the Question->HiiValue.Value.string.
950 //
951 if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
952 DeleteString(Question->HiiValue.Value.string, Selection->FormSet->HiiHandle);
953 Question->HiiValue.Value.string = StringId;
954 }
955
956 if (EFI_ERROR (Status)) {
957 //
958 // Reset state machine for interactive password
959 //
960 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
961 PasswordCallback (Selection, MenuOption, NULL);
962 } else {
963 //
964 // Researve the Question->HiiValue.Value.string.
965 //
966 HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
967 }
968 } else {
969 //
970 // Two password match, send it to Configuration Driver
971 //
972 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
973 PasswordCallback (Selection, MenuOption, StringPtr);
974 } else {
975 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
976 SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithHiiDriver);
977 }
978 }
979 } else {
980 //
981 // Reset state machine for interactive password
982 //
983 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
984 PasswordCallback (Selection, MenuOption, NULL);
985 }
986
987 //
988 // Two password mismatch, prompt error message
989 //
990 do {
991 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString);
992 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
993 }
994
995 FreePool (TempString);
996 FreePool (StringPtr);
997 }
998 break;
999
1000 default:
1001 break;
1002 }
1003
1004 return Status;
1005 }
1006
1007
1008 /**
1009 Process the help string: Split StringPtr to several lines of strings stored in
1010 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
1011
1012 @param StringPtr The entire help string.
1013 @param FormattedString The oupput formatted string.
1014 @param EachLineWidth The max string length of each line in the formatted string.
1015 @param RowCount TRUE: if Question is selected.
1016
1017 **/
1018 UINTN
1019 ProcessHelpString (
1020 IN CHAR16 *StringPtr,
1021 OUT CHAR16 **FormattedString,
1022 OUT UINT16 *EachLineWidth,
1023 IN UINTN RowCount
1024 )
1025 {
1026 UINTN Index;
1027 CHAR16 *OutputString;
1028 UINTN TotalRowNum;
1029 UINTN CheckedNum;
1030 UINT16 GlyphWidth;
1031 UINT16 LineWidth;
1032 UINT16 MaxStringLen;
1033 UINT16 StringLen;
1034
1035 TotalRowNum = 0;
1036 CheckedNum = 0;
1037 GlyphWidth = 1;
1038 Index = 0;
1039 MaxStringLen = 0;
1040 StringLen = 0;
1041
1042 //
1043 // Set default help string width.
1044 //
1045 LineWidth = (UINT16) (gHelpBlockWidth - 1);
1046
1047 //
1048 // Get row number of the String.
1049 //
1050 while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
1051 if (StringLen > MaxStringLen) {
1052 MaxStringLen = StringLen;
1053 }
1054
1055 TotalRowNum ++;
1056 FreePool (OutputString);
1057 }
1058 *EachLineWidth = MaxStringLen;
1059
1060 *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));
1061 ASSERT (*FormattedString != NULL);
1062
1063 //
1064 // Generate formatted help string array.
1065 //
1066 GlyphWidth = 1;
1067 Index = 0;
1068 while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
1069 CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));
1070 CheckedNum ++;
1071 FreePool (OutputString);
1072 }
1073
1074 return TotalRowNum;
1075 }