]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c
sync comments, fix function header, rename variable name to follow coding style.
[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 gBS->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 gBS->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 gBS->FreePool (*OptionString);
454 *OptionString = NULL;
455 }
456
457 if ((OneOfOption->SuppressExpression != NULL) &&
458 (OneOfOption->SuppressExpression->Result.Value.b)) {
459 //
460 // This option is suppressed
461 //
462 Suppress = TRUE;
463 } else {
464 Suppress = FALSE;
465 }
466
467 if (Suppress) {
468 //
469 // Current selected option happen to be suppressed,
470 // enforce to select on a non-suppressed option
471 //
472 Link = GetFirstNode (&Question->OptionListHead);
473 while (!IsNull (&Question->OptionListHead, Link)) {
474 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
475
476 if ((OneOfOption->SuppressExpression == NULL) ||
477 !OneOfOption->SuppressExpression->Result.Value.b) {
478 Suppress = FALSE;
479 CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE));
480 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
481 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
482 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
483 break;
484 }
485
486 Link = GetNextNode (&Question->OptionListHead, Link);
487 }
488 }
489
490 if (!Suppress) {
491 Character[0] = LEFT_ONEOF_DELIMITER;
492 NewStrCat (OptionString[0], Character);
493 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
494 NewStrCat (OptionString[0], StringPtr);
495 Character[0] = RIGHT_ONEOF_DELIMITER;
496 NewStrCat (OptionString[0], Character);
497
498 gBS->FreePool (StringPtr);
499 }
500 }
501 break;
502
503 case EFI_IFR_CHECKBOX_OP:
504 *OptionString = AllocateZeroPool (BufferSize);
505 ASSERT (*OptionString);
506
507 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
508
509 if (Selected) {
510 //
511 // Since this is a BOOLEAN operation, flip it upon selection
512 //
513 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
514
515 //
516 // Perform inconsistent check
517 //
518 Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
519 if (EFI_ERROR (Status)) {
520 //
521 // Inconsistent check fail, restore Question Value
522 //
523 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
524 gBS->FreePool (*OptionString);
525 *OptionString = NULL;
526 return Status;
527 }
528
529 //
530 // Save Question value
531 //
532 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
533 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
534 }
535
536 if (QuestionValue->Value.b) {
537 *(OptionString[0] + 1) = CHECK_ON;
538 } else {
539 *(OptionString[0] + 1) = CHECK_OFF;
540 }
541 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
542 break;
543
544 case EFI_IFR_NUMERIC_OP:
545 if (Selected) {
546 //
547 // Go ask for input
548 //
549 Status = GetNumericInput (Selection, MenuOption);
550 } else {
551 *OptionString = AllocateZeroPool (BufferSize);
552 ASSERT (*OptionString);
553
554 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
555
556 //
557 // Formatted print
558 //
559 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
560 Number = (UINT16) GetStringWidth (FormattedNumber);
561 CopyMem (OptionString[0] + 1, FormattedNumber, Number);
562
563 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
564 }
565 break;
566
567 case EFI_IFR_DATE_OP:
568 if (Selected) {
569 //
570 // This is similar to numerics
571 //
572 Status = GetNumericInput (Selection, MenuOption);
573 } else {
574 *OptionString = AllocateZeroPool (BufferSize);
575 ASSERT (*OptionString);
576
577 switch (MenuOption->Sequence) {
578 case 0:
579 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
580 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
581 *(OptionString[0] + 3) = DATE_SEPARATOR;
582 break;
583
584 case 1:
585 SetUnicodeMem (OptionString[0], 4, L' ');
586 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
587 *(OptionString[0] + 6) = DATE_SEPARATOR;
588 break;
589
590 case 2:
591 SetUnicodeMem (OptionString[0], 7, L' ');
592 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", QuestionValue->Value.date.Year);
593 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
594 break;
595 }
596 }
597 break;
598
599 case EFI_IFR_TIME_OP:
600 if (Selected) {
601 //
602 // This is similar to numerics
603 //
604 Status = GetNumericInput (Selection, MenuOption);
605 } else {
606 *OptionString = AllocateZeroPool (BufferSize);
607 ASSERT (*OptionString);
608
609 switch (MenuOption->Sequence) {
610 case 0:
611 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
612 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
613 *(OptionString[0] + 3) = TIME_SEPARATOR;
614 break;
615
616 case 1:
617 SetUnicodeMem (OptionString[0], 4, L' ');
618 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
619 *(OptionString[0] + 6) = TIME_SEPARATOR;
620 break;
621
622 case 2:
623 SetUnicodeMem (OptionString[0], 7, L' ');
624 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
625 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
626 break;
627 }
628 }
629 break;
630
631 case EFI_IFR_STRING_OP:
632 if (Selected) {
633 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
634 ASSERT (StringPtr);
635
636 Status = ReadString (MenuOption, gPromptForData, StringPtr);
637 if (!EFI_ERROR (Status)) {
638 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
639 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
640
641 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
642 }
643
644 gBS->FreePool (StringPtr);
645 } else {
646 *OptionString = AllocateZeroPool (BufferSize);
647 ASSERT (*OptionString);
648
649 if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) {
650 *(OptionString[0]) = '_';
651 } else {
652 if ((Maximum * sizeof (CHAR16)) < BufferSize) {
653 BufferSize = Maximum * sizeof (CHAR16);
654 }
655 CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize);
656 }
657 }
658 break;
659
660 case EFI_IFR_PASSWORD_OP:
661 if (Selected) {
662 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
663 ASSERT (StringPtr);
664
665 //
666 // For interactive passwords, old password is validated by callback
667 //
668 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
669 //
670 // Use a NULL password to test whether old password is required
671 //
672 *StringPtr = 0;
673 Status = PasswordCallback (Selection, MenuOption, StringPtr);
674 if (Status == EFI_NOT_AVAILABLE_YET) {
675 //
676 // Callback request to terminate password input
677 //
678 gBS->FreePool (StringPtr);
679 return EFI_SUCCESS;
680 }
681
682 if (EFI_ERROR (Status)) {
683 //
684 // Old password exist, ask user for the old password
685 //
686 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
687 if (EFI_ERROR (Status)) {
688 gBS->FreePool (StringPtr);
689 return Status;
690 }
691
692 //
693 // Check user input old password
694 //
695 Status = PasswordCallback (Selection, MenuOption, StringPtr);
696 if (EFI_ERROR (Status)) {
697 if (Status == EFI_NOT_READY) {
698 //
699 // Typed in old password incorrect
700 //
701 PasswordInvalid ();
702 } else {
703 Status = EFI_SUCCESS;
704 }
705
706 gBS->FreePool (StringPtr);
707 return Status;
708 }
709 }
710 } else {
711 //
712 // For non-interactive password, validate old password in local
713 //
714 if (*((CHAR16 *) Question->BufferValue) != 0) {
715 //
716 // There is something there! Prompt for password
717 //
718 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
719 if (EFI_ERROR (Status)) {
720 gBS->FreePool (StringPtr);
721 return Status;
722 }
723
724 TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue);
725 TempString[Maximum] = L'\0';
726
727 if (StrCmp (StringPtr, TempString) != 0) {
728 //
729 // Typed in old password incorrect
730 //
731 PasswordInvalid ();
732
733 gBS->FreePool (StringPtr);
734 gBS->FreePool (TempString);
735 return Status;
736 }
737
738 gBS->FreePool (TempString);
739 }
740 }
741
742 //
743 // Ask for new password
744 //
745 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
746 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
747 if (EFI_ERROR (Status)) {
748 //
749 // Reset state machine for interactive password
750 //
751 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
752 PasswordCallback (Selection, MenuOption, NULL);
753 }
754
755 gBS->FreePool (StringPtr);
756 return Status;
757 }
758
759 //
760 // Confirm new password
761 //
762 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
763 ASSERT (TempString);
764 Status = ReadString (MenuOption, gConfirmPassword, TempString);
765 if (EFI_ERROR (Status)) {
766 //
767 // Reset state machine for interactive password
768 //
769 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
770 PasswordCallback (Selection, MenuOption, NULL);
771 }
772
773 gBS->FreePool (StringPtr);
774 gBS->FreePool (TempString);
775 return Status;
776 }
777
778 //
779 // Compare two typed-in new passwords
780 //
781 if (StrCmp (StringPtr, TempString) == 0) {
782 //
783 // Two password match, send it to Configuration Driver
784 //
785 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
786 PasswordCallback (Selection, MenuOption, StringPtr);
787 } else {
788 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
789 SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);
790 }
791 } else {
792 //
793 // Reset state machine for interactive password
794 //
795 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
796 PasswordCallback (Selection, MenuOption, NULL);
797 }
798
799 //
800 // Two password mismatch, prompt error message
801 //
802 do {
803 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString);
804 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
805 }
806
807 gBS->FreePool (TempString);
808 gBS->FreePool (StringPtr);
809 }
810 break;
811
812 default:
813 break;
814 }
815
816 return Status;
817 }
818
819
820 /**
821 Process the help string: Split StringPtr to several lines of strings stored in
822 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
823
824 @param StringPtr The entire help string.
825 @param FormattedString The oupput formatted string.
826 @param RowCount TRUE: if Question is selected.
827
828 **/
829 VOID
830 ProcessHelpString (
831 IN CHAR16 *StringPtr,
832 OUT CHAR16 **FormattedString,
833 IN UINTN RowCount
834 )
835 {
836 CONST UINTN BlockWidth = (UINTN) gHelpBlockWidth - 1;
837 UINTN AllocateSize;
838 //
839 // [PrevCurrIndex, CurrIndex) forms a range of a screen-line
840 //
841 UINTN CurrIndex;
842 UINTN PrevCurrIndex;
843 UINTN LineCount;
844 UINTN VirtualLineCount;
845 //
846 // GlyphOffset stores glyph width of current screen-line
847 //
848 UINTN GlyphOffset;
849 //
850 // GlyphWidth equals to 2 if we meet width directive
851 //
852 UINTN GlyphWidth;
853 //
854 // during scanning, we remember the position of last space character
855 // in case that if next word cannot put in current line, we could restore back to the position
856 // of last space character
857 // while we should also remmeber the glyph width of the last space character for restoring
858 //
859 UINTN LastSpaceIndex;
860 UINTN LastSpaceGlyphWidth;
861 //
862 // every time we begin to form a new screen-line, we should remember glyph width of single character
863 // of last line
864 //
865 UINTN LineStartGlyphWidth;
866 UINTN *IndexArray;
867 UINTN *OldIndexArray;
868
869 //
870 // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )
871 // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want
872 // to bring the width directive of the last line to current screen-line.
873 // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line
874 // different from that of "\wideabcde", we should remember the width directive.
875 //
876 AllocateSize = 0x20;
877 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);
878
879 if (*FormattedString != NULL) {
880 gBS->FreePool (*FormattedString);
881 *FormattedString = NULL;
882 }
883
884 for (PrevCurrIndex = 0, CurrIndex = 0, LineCount = 0, LastSpaceIndex = 0,
885 IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1;
886 (StringPtr[CurrIndex] != CHAR_NULL);
887 CurrIndex ++) {
888
889 if (LineCount == AllocateSize) {
890 AllocateSize += 0x10;
891 OldIndexArray = IndexArray;
892 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);
893 CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3);
894 gBS->FreePool (OldIndexArray);
895 }
896 switch (StringPtr[CurrIndex]) {
897
898 case NARROW_CHAR:
899 case WIDE_CHAR:
900 GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1);
901 if (CurrIndex == 0) {
902 LineStartGlyphWidth = GlyphWidth;
903 }
904 break;
905
906 //
907 // char is '\n'
908 // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN
909 //
910 case CHAR_LINEFEED:
911 //
912 // Store a range of string as a line
913 //
914 IndexArray[LineCount*3] = PrevCurrIndex;
915 IndexArray[LineCount*3+1] = CurrIndex;
916 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
917 LineCount ++;
918 //
919 // Reset offset and save begin position of line
920 //
921 GlyphOffset = 0;
922 LineStartGlyphWidth = GlyphWidth;
923 PrevCurrIndex = CurrIndex + 1;
924 break;
925
926 //
927 // char is '\r'
928 // "\r\n" and "\r" both are handled here
929 //
930 case CHAR_CARRIAGE_RETURN:
931 if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) {
932 //
933 // next char is '\n'
934 //
935 IndexArray[LineCount*3] = PrevCurrIndex;
936 IndexArray[LineCount*3+1] = CurrIndex;
937 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
938 LineCount ++;
939 CurrIndex ++;
940 }
941 GlyphOffset = 0;
942 LineStartGlyphWidth = GlyphWidth;
943 PrevCurrIndex = CurrIndex + 1;
944 break;
945
946 //
947 // char is space or other char
948 //
949 default:
950 GlyphOffset += GlyphWidth;
951 if (GlyphOffset >= BlockWidth) {
952 if (LastSpaceIndex > PrevCurrIndex) {
953 //
954 // LastSpaceIndex points to space inside current screen-line,
955 // restore to LastSpaceIndex
956 // (Otherwise the word is too long to fit one screen-line, just cut it)
957 //
958 CurrIndex = LastSpaceIndex;
959 GlyphWidth = LastSpaceGlyphWidth;
960 } else if (GlyphOffset > BlockWidth) {
961 //
962 // the word is too long to fit one screen-line and we don't get the chance
963 // of GlyphOffset == BlockWidth because GlyphWidth = 2
964 //
965 CurrIndex --;
966 }
967
968 IndexArray[LineCount*3] = PrevCurrIndex;
969 IndexArray[LineCount*3+1] = CurrIndex + 1;
970 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
971 LineStartGlyphWidth = GlyphWidth;
972 LineCount ++;
973 //
974 // Reset offset and save begin position of line
975 //
976 GlyphOffset = 0;
977 PrevCurrIndex = CurrIndex + 1;
978 }
979
980 //
981 // LastSpaceIndex: remember position of last space
982 //
983 if (StringPtr[CurrIndex] == CHAR_SPACE) {
984 LastSpaceIndex = CurrIndex;
985 LastSpaceGlyphWidth = GlyphWidth;
986 }
987 break;
988 }
989 }
990
991 if (GlyphOffset > 0) {
992 IndexArray[LineCount*3] = PrevCurrIndex;
993 IndexArray[LineCount*3+1] = CurrIndex;
994 IndexArray[LineCount*3+2] = GlyphWidth;
995 LineCount ++;
996 }
997
998 if (LineCount == 0) {
999 //
1000 // in case we meet null string
1001 //
1002 IndexArray[0] = 0;
1003 IndexArray[1] = 1;
1004 //
1005 // we assume null string's glyph width is 1
1006 //
1007 IndexArray[1] = 1;
1008 LineCount ++;
1009 }
1010
1011 VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0));
1012 *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2);
1013
1014 for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) {
1015 *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (CHAR16) ((IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR);
1016 StrnCpy (
1017 *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1,
1018 StringPtr + IndexArray[CurrIndex*3],
1019 IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3]
1020 );
1021 }
1022
1023 gBS->FreePool (IndexArray);
1024 }