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