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