]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c
1. Support inconsistent if opcode used in string/password opcode.
[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 - 2010, 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
88 Link = GetFirstNode (&Question->OptionListHead);
89 while (!IsNull (&Question->OptionListHead, Link)) {
90 Option = QUESTION_OPTION_FROM_LINK (Link);
91
92 if (CompareHiiValue (&Option->Value, OptionValue, NULL) == 0) {
93 return Option;
94 }
95
96 Link = GetNextNode (&Question->OptionListHead, Link);
97 }
98
99 return NULL;
100 }
101
102
103 /**
104 Return data element in an Array by its Index.
105
106 @param Array The data array.
107 @param Type Type of the data in this array.
108 @param Index Zero based index for data in this array.
109
110 @retval Value The data to be returned
111
112 **/
113 UINT64
114 GetArrayData (
115 IN VOID *Array,
116 IN UINT8 Type,
117 IN UINTN Index
118 )
119 {
120 UINT64 Data;
121
122 ASSERT (Array != NULL);
123
124 Data = 0;
125 switch (Type) {
126 case EFI_IFR_TYPE_NUM_SIZE_8:
127 Data = (UINT64) *(((UINT8 *) Array) + Index);
128 break;
129
130 case EFI_IFR_TYPE_NUM_SIZE_16:
131 Data = (UINT64) *(((UINT16 *) Array) + Index);
132 break;
133
134 case EFI_IFR_TYPE_NUM_SIZE_32:
135 Data = (UINT64) *(((UINT32 *) Array) + Index);
136 break;
137
138 case EFI_IFR_TYPE_NUM_SIZE_64:
139 Data = (UINT64) *(((UINT64 *) Array) + Index);
140 break;
141
142 default:
143 break;
144 }
145
146 return Data;
147 }
148
149
150 /**
151 Set value of a data element in an Array by its Index.
152
153 @param Array The data array.
154 @param Type Type of the data in this array.
155 @param Index Zero based index for data in this array.
156 @param Value The value to be set.
157
158 **/
159 VOID
160 SetArrayData (
161 IN VOID *Array,
162 IN UINT8 Type,
163 IN UINTN Index,
164 IN UINT64 Value
165 )
166 {
167
168 ASSERT (Array != NULL);
169
170 switch (Type) {
171 case EFI_IFR_TYPE_NUM_SIZE_8:
172 *(((UINT8 *) Array) + Index) = (UINT8) Value;
173 break;
174
175 case EFI_IFR_TYPE_NUM_SIZE_16:
176 *(((UINT16 *) Array) + Index) = (UINT16) Value;
177 break;
178
179 case EFI_IFR_TYPE_NUM_SIZE_32:
180 *(((UINT32 *) Array) + Index) = (UINT32) Value;
181 break;
182
183 case EFI_IFR_TYPE_NUM_SIZE_64:
184 *(((UINT64 *) Array) + Index) = (UINT64) Value;
185 break;
186
187 default:
188 break;
189 }
190 }
191
192
193 /**
194 Print Question Value according to it's storage width and display attributes.
195
196 @param Question The Question to be printed.
197 @param FormattedNumber Buffer for output string.
198 @param BufferSize The FormattedNumber buffer size in bytes.
199
200 @retval EFI_SUCCESS Print success.
201 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
202
203 **/
204 EFI_STATUS
205 PrintFormattedNumber (
206 IN FORM_BROWSER_STATEMENT *Question,
207 IN OUT CHAR16 *FormattedNumber,
208 IN UINTN BufferSize
209 )
210 {
211 INT64 Value;
212 CHAR16 *Format;
213 EFI_HII_VALUE *QuestionValue;
214
215 if (BufferSize < (21 * sizeof (CHAR16))) {
216 return EFI_BUFFER_TOO_SMALL;
217 }
218
219 QuestionValue = &Question->HiiValue;
220
221 Value = (INT64) QuestionValue->Value.u64;
222 switch (Question->Flags & EFI_IFR_DISPLAY) {
223 case EFI_IFR_DISPLAY_INT_DEC:
224 switch (QuestionValue->Type) {
225 case EFI_IFR_NUMERIC_SIZE_1:
226 Value = (INT64) ((INT8) QuestionValue->Value.u8);
227 break;
228
229 case EFI_IFR_NUMERIC_SIZE_2:
230 Value = (INT64) ((INT16) QuestionValue->Value.u16);
231 break;
232
233 case EFI_IFR_NUMERIC_SIZE_4:
234 Value = (INT64) ((INT32) QuestionValue->Value.u32);
235 break;
236
237 case EFI_IFR_NUMERIC_SIZE_8:
238 default:
239 break;
240 }
241
242 if (Value < 0) {
243 Value = -Value;
244 Format = L"-%ld";
245 } else {
246 Format = L"%ld";
247 }
248 break;
249
250 case EFI_IFR_DISPLAY_UINT_DEC:
251 Format = L"%ld";
252 break;
253
254 case EFI_IFR_DISPLAY_UINT_HEX:
255 Format = L"%lx";
256 break;
257
258 default:
259 return EFI_UNSUPPORTED;
260 break;
261 }
262
263 UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);
264
265 return EFI_SUCCESS;
266 }
267
268
269 /**
270 Password may be stored as encrypted by Configuration Driver. When change a
271 password, user will be challenged with old password. To validate user input old
272 password, we will send the clear text to Configuration Driver via Callback().
273 Configuration driver is responsible to check the passed in password and return
274 the validation result. If validation pass, state machine in password Callback()
275 will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.
276 After user type in new password twice, Callback() will be invoked to send the
277 new password to Configuration Driver.
278
279 @param Selection Pointer to UI_MENU_SELECTION.
280 @param MenuOption The MenuOption for this password Question.
281 @param String The clear text of password.
282
283 @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input.
284 @return In state of BROWSER_STATE_VALIDATE_PASSWORD:
285 @retval EFI_SUCCESS Password correct, Browser will prompt for new
286 password.
287 @retval EFI_NOT_READY Password incorrect, Browser will show error
288 message.
289 @retval Other Browser will do nothing.
290 @return In state of BROWSER_STATE_SET_PASSWORD:
291 @retval EFI_SUCCESS Set password success.
292 @retval Other Set password failed.
293
294 **/
295 EFI_STATUS
296 PasswordCallback (
297 IN UI_MENU_SELECTION *Selection,
298 IN UI_MENU_OPTION *MenuOption,
299 IN CHAR16 *String
300 )
301 {
302 EFI_STATUS Status;
303 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
304 EFI_BROWSER_ACTION_REQUEST ActionRequest;
305 EFI_IFR_TYPE_VALUE IfrTypeValue;
306
307 ConfigAccess = Selection->FormSet->ConfigAccess;
308 if (ConfigAccess == NULL) {
309 return EFI_UNSUPPORTED;
310 }
311
312 //
313 // Prepare password string in HII database
314 //
315 if (String != NULL) {
316 IfrTypeValue.string = NewString (String, Selection->FormSet->HiiHandle);
317 } else {
318 IfrTypeValue.string = 0;
319 }
320
321 //
322 // Send password to Configuration Driver for validation
323 //
324 Status = ConfigAccess->Callback (
325 ConfigAccess,
326 EFI_BROWSER_ACTION_CHANGING,
327 MenuOption->ThisTag->QuestionId,
328 MenuOption->ThisTag->HiiValue.Type,
329 &IfrTypeValue,
330 &ActionRequest
331 );
332
333 //
334 // Remove password string from HII database
335 //
336 if (String != NULL) {
337 DeleteString (IfrTypeValue.string, Selection->FormSet->HiiHandle);
338 }
339
340 return Status;
341 }
342
343
344 /**
345 Display error message for invalid password.
346
347 **/
348 VOID
349 PasswordInvalid (
350 VOID
351 )
352 {
353 EFI_INPUT_KEY Key;
354
355 //
356 // Invalid password, prompt error message
357 //
358 do {
359 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString);
360 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
361 }
362
363
364 /**
365 Process a Question's Option (whether selected or un-selected).
366
367 @param Selection Pointer to UI_MENU_SELECTION.
368 @param MenuOption The MenuOption for this Question.
369 @param Selected TRUE: if Question is selected.
370 @param OptionString Pointer of the Option String to be displayed.
371
372 @retval EFI_SUCCESS Question Option process success.
373 @retval Other Question Option process fail.
374
375 **/
376 EFI_STATUS
377 ProcessOptions (
378 IN UI_MENU_SELECTION *Selection,
379 IN UI_MENU_OPTION *MenuOption,
380 IN BOOLEAN Selected,
381 OUT CHAR16 **OptionString
382 )
383 {
384 EFI_STATUS Status;
385 CHAR16 *StringPtr;
386 CHAR16 *TempString;
387 UINTN Index;
388 FORM_BROWSER_STATEMENT *Question;
389 CHAR16 FormattedNumber[21];
390 UINT16 Number;
391 CHAR16 Character[2];
392 EFI_INPUT_KEY Key;
393 UINTN BufferSize;
394 QUESTION_OPTION *OneOfOption;
395 LIST_ENTRY *Link;
396 EFI_HII_VALUE HiiValue;
397 EFI_HII_VALUE *QuestionValue;
398 BOOLEAN Suppress;
399 UINT16 Maximum;
400 QUESTION_OPTION *Option;
401 UINTN Index2;
402 UINT8 *ValueArray;
403 UINT8 ValueType;
404 EFI_STRING_ID StringId;
405
406 Status = EFI_SUCCESS;
407
408 StringPtr = NULL;
409 Character[1] = L'\0';
410 *OptionString = NULL;
411 StringId = 0;
412
413 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
414 BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow;
415
416 Question = MenuOption->ThisTag;
417 QuestionValue = &Question->HiiValue;
418 Maximum = (UINT16) Question->Maximum;
419
420 ValueArray = Question->BufferValue;
421 ValueType = Question->ValueType;
422
423 switch (Question->Operand) {
424 case EFI_IFR_ORDERED_LIST_OP:
425 //
426 // Check whether there are Options of this OrderedList
427 //
428 if (IsListEmpty (&Question->OptionListHead)) {
429 break;
430 }
431 //
432 // Initialize Option value array
433 //
434 if (GetArrayData (ValueArray, ValueType, 0) == 0) {
435 GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0);
436 }
437
438 if (Selected) {
439 //
440 // Go ask for input
441 //
442 Status = GetSelectionInputPopUp (Selection, MenuOption);
443 } else {
444 //
445 // We now know how many strings we will have, so we can allocate the
446 // space required for the array or strings.
447 //
448 *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize);
449 ASSERT (*OptionString);
450
451 HiiValue.Type = ValueType;
452 HiiValue.Value.u64 = 0;
453 for (Index = 0; Index < Question->MaxContainers; Index++) {
454 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
455 if (HiiValue.Value.u64 == 0) {
456 //
457 // Values for the options in ordered lists should never be a 0
458 //
459 break;
460 }
461
462 OneOfOption = ValueToOption (Question, &HiiValue);
463 if (OneOfOption == NULL) {
464 //
465 // Show error message
466 //
467 do {
468 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);
469 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
470
471 //
472 // The initial value of the orderedlist is invalid, force to be valid value
473 //
474 Link = GetFirstNode (&Question->OptionListHead);
475 Index2 = 0;
476 while (!IsNull (&Question->OptionListHead, Link) && Index2 < Question->MaxContainers) {
477 Option = QUESTION_OPTION_FROM_LINK (Link);
478 SetArrayData (ValueArray, ValueType, Index2, Option->Value.Value.u64);
479 Index2++;
480 Link = GetNextNode (&Question->OptionListHead, Link);
481 }
482 SetArrayData (ValueArray, ValueType, Index2, 0);
483
484 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
485 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
486
487 FreePool (*OptionString);
488 *OptionString = NULL;
489 return EFI_NOT_FOUND;
490 }
491
492 Suppress = FALSE;
493 if ((OneOfOption->SuppressExpression != NULL) &&
494 (OneOfOption->SuppressExpression->Result.Value.b)) {
495 //
496 // This option is suppressed
497 //
498 Suppress = TRUE;
499 }
500
501 if (!Suppress) {
502 Character[0] = LEFT_ONEOF_DELIMITER;
503 NewStrCat (OptionString[0], Character);
504 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
505 NewStrCat (OptionString[0], StringPtr);
506 Character[0] = RIGHT_ONEOF_DELIMITER;
507 NewStrCat (OptionString[0], Character);
508 Character[0] = CHAR_CARRIAGE_RETURN;
509 NewStrCat (OptionString[0], Character);
510
511 FreePool (StringPtr);
512 }
513 }
514 }
515 break;
516
517 case EFI_IFR_ONE_OF_OP:
518 //
519 // Check whether there are Options of this OneOf
520 //
521 if (IsListEmpty (&Question->OptionListHead)) {
522 break;
523 }
524 if (Selected) {
525 //
526 // Go ask for input
527 //
528 Status = GetSelectionInputPopUp (Selection, MenuOption);
529 } else {
530 *OptionString = AllocateZeroPool (BufferSize);
531 ASSERT (*OptionString);
532
533 OneOfOption = ValueToOption (Question, QuestionValue);
534 if (OneOfOption == NULL) {
535 //
536 // Show error message
537 //
538 do {
539 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);
540 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
541
542 //
543 // Force the Question value to be valid
544 //
545 Link = GetFirstNode (&Question->OptionListHead);
546 while (!IsNull (&Question->OptionListHead, Link)) {
547 Option = QUESTION_OPTION_FROM_LINK (Link);
548
549 if ((Option->SuppressExpression == NULL) ||
550 !Option->SuppressExpression->Result.Value.b) {
551 CopyMem (QuestionValue, &Option->Value, sizeof (EFI_HII_VALUE));
552 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
553 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
554 break;
555 }
556
557 Link = GetNextNode (&Question->OptionListHead, Link);
558 }
559
560 FreePool (*OptionString);
561 *OptionString = NULL;
562 return EFI_NOT_FOUND;
563 }
564
565 if ((OneOfOption->SuppressExpression != NULL) &&
566 (OneOfOption->SuppressExpression->Result.Value.b)) {
567 //
568 // This option is suppressed
569 //
570 Suppress = TRUE;
571 } else {
572 Suppress = FALSE;
573 }
574
575 if (Suppress) {
576 //
577 // Current selected option happen to be suppressed,
578 // enforce to select on a non-suppressed option
579 //
580 Link = GetFirstNode (&Question->OptionListHead);
581 while (!IsNull (&Question->OptionListHead, Link)) {
582 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
583
584 if ((OneOfOption->SuppressExpression == NULL) ||
585 !OneOfOption->SuppressExpression->Result.Value.b) {
586 Suppress = FALSE;
587 CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE));
588 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
589 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
590 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
591 break;
592 }
593
594 Link = GetNextNode (&Question->OptionListHead, Link);
595 }
596 }
597
598 if (!Suppress) {
599 Character[0] = LEFT_ONEOF_DELIMITER;
600 NewStrCat (OptionString[0], Character);
601 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
602 NewStrCat (OptionString[0], StringPtr);
603 Character[0] = RIGHT_ONEOF_DELIMITER;
604 NewStrCat (OptionString[0], Character);
605
606 FreePool (StringPtr);
607 }
608 }
609 break;
610
611 case EFI_IFR_CHECKBOX_OP:
612 *OptionString = AllocateZeroPool (BufferSize);
613 ASSERT (*OptionString);
614
615 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
616
617 if (Selected) {
618 //
619 // Since this is a BOOLEAN operation, flip it upon selection
620 //
621 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
622
623 //
624 // Perform inconsistent check
625 //
626 Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
627 if (EFI_ERROR (Status)) {
628 //
629 // Inconsistent check fail, restore Question Value
630 //
631 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
632 FreePool (*OptionString);
633 *OptionString = NULL;
634 return Status;
635 }
636
637 //
638 // Save Question value
639 //
640 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
641 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
642 }
643
644 if (QuestionValue->Value.b) {
645 *(OptionString[0] + 1) = CHECK_ON;
646 } else {
647 *(OptionString[0] + 1) = CHECK_OFF;
648 }
649 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
650 break;
651
652 case EFI_IFR_NUMERIC_OP:
653 if (Selected) {
654 //
655 // Go ask for input
656 //
657 Status = GetNumericInput (Selection, MenuOption);
658 } else {
659 *OptionString = AllocateZeroPool (BufferSize);
660 ASSERT (*OptionString);
661
662 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
663
664 //
665 // Formatted print
666 //
667 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
668 Number = (UINT16) GetStringWidth (FormattedNumber);
669 CopyMem (OptionString[0] + 1, FormattedNumber, Number);
670
671 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
672 }
673 break;
674
675 case EFI_IFR_DATE_OP:
676 if (Selected) {
677 //
678 // This is similar to numerics
679 //
680 Status = GetNumericInput (Selection, MenuOption);
681 } else {
682 *OptionString = AllocateZeroPool (BufferSize);
683 ASSERT (*OptionString);
684
685 switch (MenuOption->Sequence) {
686 case 0:
687 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
688 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
689 *(OptionString[0] + 3) = DATE_SEPARATOR;
690 break;
691
692 case 1:
693 SetUnicodeMem (OptionString[0], 4, L' ');
694 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
695 *(OptionString[0] + 6) = DATE_SEPARATOR;
696 break;
697
698 case 2:
699 SetUnicodeMem (OptionString[0], 7, L' ');
700 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", QuestionValue->Value.date.Year);
701 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
702 break;
703 }
704 }
705 break;
706
707 case EFI_IFR_TIME_OP:
708 if (Selected) {
709 //
710 // This is similar to numerics
711 //
712 Status = GetNumericInput (Selection, MenuOption);
713 } else {
714 *OptionString = AllocateZeroPool (BufferSize);
715 ASSERT (*OptionString);
716
717 switch (MenuOption->Sequence) {
718 case 0:
719 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
720 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
721 *(OptionString[0] + 3) = TIME_SEPARATOR;
722 break;
723
724 case 1:
725 SetUnicodeMem (OptionString[0], 4, L' ');
726 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
727 *(OptionString[0] + 6) = TIME_SEPARATOR;
728 break;
729
730 case 2:
731 SetUnicodeMem (OptionString[0], 7, L' ');
732 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
733 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
734 break;
735 }
736 }
737 break;
738
739 case EFI_IFR_STRING_OP:
740 if (Selected) {
741 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
742 ASSERT (StringPtr);
743
744 Status = ReadString (MenuOption, gPromptForData, StringPtr);
745 if (!EFI_ERROR (Status)) {
746 HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL);
747 Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
748 if (EFI_ERROR (Status)) {
749 HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
750 } else {
751 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
752 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
753
754 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
755 }
756 }
757
758 FreePool (StringPtr);
759 } else {
760 *OptionString = AllocateZeroPool (BufferSize);
761 ASSERT (*OptionString);
762
763 if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) {
764 *(OptionString[0]) = '_';
765 } else {
766 if ((Maximum * sizeof (CHAR16)) < BufferSize) {
767 BufferSize = Maximum * sizeof (CHAR16);
768 }
769 CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize);
770 }
771 }
772 break;
773
774 case EFI_IFR_PASSWORD_OP:
775 if (Selected) {
776 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
777 ASSERT (StringPtr);
778
779 //
780 // For interactive passwords, old password is validated by callback
781 //
782 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
783 //
784 // Use a NULL password to test whether old password is required
785 //
786 *StringPtr = 0;
787 Status = PasswordCallback (Selection, MenuOption, StringPtr);
788 if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {
789 //
790 // Callback is not supported, or
791 // Callback request to terminate password input
792 //
793 FreePool (StringPtr);
794 return EFI_SUCCESS;
795 }
796
797 if (EFI_ERROR (Status)) {
798 //
799 // Old password exist, ask user for the old password
800 //
801 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
802 if (EFI_ERROR (Status)) {
803 FreePool (StringPtr);
804 return Status;
805 }
806
807 //
808 // Check user input old password
809 //
810 Status = PasswordCallback (Selection, MenuOption, StringPtr);
811 if (EFI_ERROR (Status)) {
812 if (Status == EFI_NOT_READY) {
813 //
814 // Typed in old password incorrect
815 //
816 PasswordInvalid ();
817 } else {
818 Status = EFI_SUCCESS;
819 }
820
821 FreePool (StringPtr);
822 return Status;
823 }
824 }
825 } else {
826 //
827 // For non-interactive password, validate old password in local
828 //
829 if (*((CHAR16 *) Question->BufferValue) != 0) {
830 //
831 // There is something there! Prompt for password
832 //
833 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
834 if (EFI_ERROR (Status)) {
835 FreePool (StringPtr);
836 return Status;
837 }
838
839 TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue);
840 ASSERT (TempString != NULL);
841
842 TempString[Maximum] = L'\0';
843
844 if (StrCmp (StringPtr, TempString) != 0) {
845 //
846 // Typed in old password incorrect
847 //
848 PasswordInvalid ();
849
850 FreePool (StringPtr);
851 FreePool (TempString);
852 return Status;
853 }
854
855 FreePool (TempString);
856 }
857 }
858
859 //
860 // Ask for new password
861 //
862 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
863 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
864 if (EFI_ERROR (Status)) {
865 //
866 // Reset state machine for interactive password
867 //
868 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
869 PasswordCallback (Selection, MenuOption, NULL);
870 }
871
872 FreePool (StringPtr);
873 return Status;
874 }
875
876 //
877 // Confirm new password
878 //
879 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
880 ASSERT (TempString);
881 Status = ReadString (MenuOption, gConfirmPassword, TempString);
882 if (EFI_ERROR (Status)) {
883 //
884 // Reset state machine for interactive password
885 //
886 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
887 PasswordCallback (Selection, MenuOption, NULL);
888 }
889
890 FreePool (StringPtr);
891 FreePool (TempString);
892 return Status;
893 }
894
895 //
896 // Compare two typed-in new passwords
897 //
898 if (StrCmp (StringPtr, TempString) == 0) {
899 //
900 // Prepare the Question->HiiValue.Value.string for ValidateQuestion use.
901 //
902 if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
903 StringId = Question->HiiValue.Value.string;
904 Question->HiiValue.Value.string = NewString (StringPtr, Selection->FormSet->HiiHandle);
905 } else {
906 HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, StringPtr, NULL);
907 }
908
909 Status = ValidateQuestion(Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
910
911 //
912 // Researve the Question->HiiValue.Value.string.
913 //
914 if((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
915 DeleteString(Question->HiiValue.Value.string, Selection->FormSet->HiiHandle);
916 Question->HiiValue.Value.string = StringId;
917 }
918
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 } else {
926 //
927 // Researve the Question->HiiValue.Value.string.
928 //
929 HiiSetString(Selection->FormSet->HiiHandle, Question->HiiValue.Value.string, (CHAR16*)Question->BufferValue, NULL);
930 }
931 } else {
932 //
933 // Two password match, send it to Configuration Driver
934 //
935 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
936 PasswordCallback (Selection, MenuOption, StringPtr);
937 } else {
938 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
939 SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);
940 }
941 }
942 } else {
943 //
944 // Reset state machine for interactive password
945 //
946 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
947 PasswordCallback (Selection, MenuOption, NULL);
948 }
949
950 //
951 // Two password mismatch, prompt error message
952 //
953 do {
954 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString);
955 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
956 }
957
958 FreePool (TempString);
959 FreePool (StringPtr);
960 }
961 break;
962
963 default:
964 break;
965 }
966
967 return Status;
968 }
969
970
971 /**
972 Process the help string: Split StringPtr to several lines of strings stored in
973 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
974
975 @param StringPtr The entire help string.
976 @param FormattedString The oupput formatted string.
977 @param RowCount TRUE: if Question is selected.
978
979 **/
980 VOID
981 ProcessHelpString (
982 IN CHAR16 *StringPtr,
983 OUT CHAR16 **FormattedString,
984 IN UINTN RowCount
985 )
986 {
987 UINTN BlockWidth;
988 UINTN AllocateSize;
989 //
990 // [PrevCurrIndex, CurrIndex) forms a range of a screen-line
991 //
992 UINTN CurrIndex;
993 UINTN PrevCurrIndex;
994 UINTN LineCount;
995 UINTN VirtualLineCount;
996 //
997 // GlyphOffset stores glyph width of current screen-line
998 //
999 UINTN GlyphOffset;
1000 //
1001 // GlyphWidth equals to 2 if we meet width directive
1002 //
1003 UINTN GlyphWidth;
1004 //
1005 // during scanning, we remember the position of last space character
1006 // in case that if next word cannot put in current line, we could restore back to the position
1007 // of last space character
1008 // while we should also remmeber the glyph width of the last space character for restoring
1009 //
1010 UINTN LastSpaceIndex;
1011 UINTN LastSpaceGlyphWidth;
1012 //
1013 // every time we begin to form a new screen-line, we should remember glyph width of single character
1014 // of last line
1015 //
1016 UINTN LineStartGlyphWidth;
1017 UINTN *IndexArray;
1018 UINTN *OldIndexArray;
1019
1020 BlockWidth = (UINTN) gHelpBlockWidth - 1;
1021
1022 //
1023 // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )
1024 // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want
1025 // to bring the width directive of the last line to current screen-line.
1026 // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line
1027 // different from that of "\wideabcde", we should remember the width directive.
1028 //
1029 AllocateSize = 0x20;
1030 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);
1031 ASSERT (IndexArray != NULL);
1032
1033 if (*FormattedString != NULL) {
1034 FreePool (*FormattedString);
1035 *FormattedString = NULL;
1036 }
1037
1038 for (PrevCurrIndex = 0, CurrIndex = 0, LineCount = 0, LastSpaceIndex = 0,
1039 IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1;
1040 (StringPtr[CurrIndex] != CHAR_NULL);
1041 CurrIndex ++) {
1042
1043 if (LineCount == AllocateSize) {
1044 AllocateSize += 0x10;
1045 OldIndexArray = IndexArray;
1046 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);
1047 ASSERT (IndexArray != NULL);
1048
1049 CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3);
1050 FreePool (OldIndexArray);
1051 }
1052 switch (StringPtr[CurrIndex]) {
1053
1054 case NARROW_CHAR:
1055 case WIDE_CHAR:
1056 GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1);
1057 if (CurrIndex == 0) {
1058 LineStartGlyphWidth = GlyphWidth;
1059 }
1060 break;
1061
1062 //
1063 // char is '\n'
1064 // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN
1065 //
1066 case CHAR_LINEFEED:
1067 //
1068 // Store a range of string as a line
1069 //
1070 IndexArray[LineCount*3] = PrevCurrIndex;
1071 IndexArray[LineCount*3+1] = CurrIndex;
1072 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
1073 LineCount ++;
1074 //
1075 // Reset offset and save begin position of line
1076 //
1077 GlyphOffset = 0;
1078 LineStartGlyphWidth = GlyphWidth;
1079 PrevCurrIndex = CurrIndex + 1;
1080 break;
1081
1082 //
1083 // char is '\r'
1084 // "\r\n" and "\r" both are handled here
1085 //
1086 case CHAR_CARRIAGE_RETURN:
1087 if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) {
1088 //
1089 // next char is '\n'
1090 //
1091 IndexArray[LineCount*3] = PrevCurrIndex;
1092 IndexArray[LineCount*3+1] = CurrIndex;
1093 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
1094 LineCount ++;
1095 CurrIndex ++;
1096 }
1097 GlyphOffset = 0;
1098 LineStartGlyphWidth = GlyphWidth;
1099 PrevCurrIndex = CurrIndex + 1;
1100 break;
1101
1102 //
1103 // char is space or other char
1104 //
1105 default:
1106 GlyphOffset += GlyphWidth;
1107 if (GlyphOffset >= BlockWidth) {
1108 if (LastSpaceIndex > PrevCurrIndex) {
1109 //
1110 // LastSpaceIndex points to space inside current screen-line,
1111 // restore to LastSpaceIndex
1112 // (Otherwise the word is too long to fit one screen-line, just cut it)
1113 //
1114 CurrIndex = LastSpaceIndex;
1115 GlyphWidth = LastSpaceGlyphWidth;
1116 } else if (GlyphOffset > BlockWidth) {
1117 //
1118 // the word is too long to fit one screen-line and we don't get the chance
1119 // of GlyphOffset == BlockWidth because GlyphWidth = 2
1120 //
1121 CurrIndex --;
1122 }
1123
1124 IndexArray[LineCount*3] = PrevCurrIndex;
1125 IndexArray[LineCount*3+1] = CurrIndex + 1;
1126 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
1127 LineStartGlyphWidth = GlyphWidth;
1128 LineCount ++;
1129 //
1130 // Reset offset and save begin position of line
1131 //
1132 GlyphOffset = 0;
1133 PrevCurrIndex = CurrIndex + 1;
1134 }
1135
1136 //
1137 // LastSpaceIndex: remember position of last space
1138 //
1139 if (StringPtr[CurrIndex] == CHAR_SPACE) {
1140 LastSpaceIndex = CurrIndex;
1141 LastSpaceGlyphWidth = GlyphWidth;
1142 }
1143 break;
1144 }
1145 }
1146
1147 if (GlyphOffset > 0) {
1148 IndexArray[LineCount*3] = PrevCurrIndex;
1149 IndexArray[LineCount*3+1] = CurrIndex;
1150 IndexArray[LineCount*3+2] = GlyphWidth;
1151 LineCount ++;
1152 }
1153
1154 if (LineCount == 0) {
1155 //
1156 // in case we meet null string
1157 //
1158 IndexArray[0] = 0;
1159 IndexArray[1] = 1;
1160 //
1161 // we assume null string's glyph width is 1
1162 //
1163 IndexArray[1] = 1;
1164 LineCount ++;
1165 }
1166
1167 VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0));
1168 *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2);
1169 ASSERT (*FormattedString != NULL);
1170
1171 for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) {
1172 *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (CHAR16) ((IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR);
1173 StrnCpy (
1174 *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1,
1175 StringPtr + IndexArray[CurrIndex*3],
1176 IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3]
1177 );
1178 }
1179
1180 FreePool (IndexArray);
1181 }