]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c
Add comments to MdeModulePkg.dec, Correct minor comments for other files and Add...
[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 - 2007, 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
313 Status = EFI_SUCCESS;
314
315 StringPtr = NULL;
316 Character[1] = L'\0';
317 *OptionString = NULL;
318
319 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
320 BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow;
321
322 Question = MenuOption->ThisTag;
323 QuestionValue = &Question->HiiValue;
324 Maximum = (UINT16) Question->Maximum;
325
326 switch (Question->Operand) {
327 case EFI_IFR_ORDERED_LIST_OP:
328 //
329 // Initialize Option value array
330 //
331 if (Question->BufferValue[0] == 0) {
332 GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0);
333 }
334
335 if (Selected) {
336 //
337 // Go ask for input
338 //
339 Status = GetSelectionInputPopUp (Selection, MenuOption);
340 } else {
341 //
342 // We now know how many strings we will have, so we can allocate the
343 // space required for the array or strings.
344 //
345 *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize);
346 ASSERT (*OptionString);
347
348 HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8;
349 HiiValue.Value.u64 = 0;
350 for (Index = 0; Index < Question->MaxContainers; Index++) {
351 HiiValue.Value.u8 = Question->BufferValue[Index];
352 if (HiiValue.Value.u8 == 0) {
353 //
354 // Values for the options in ordered lists should never be a 0
355 //
356 break;
357 }
358
359 OneOfOption = ValueToOption (Question, &HiiValue);
360 if (OneOfOption == NULL) {
361 gBS->FreePool (*OptionString);
362 return EFI_NOT_FOUND;
363 }
364
365 Suppress = FALSE;
366 if ((OneOfOption->SuppressExpression != NULL) &&
367 (OneOfOption->SuppressExpression->Result.Value.b)) {
368 //
369 // This option is suppressed
370 //
371 Suppress = TRUE;
372 }
373
374 if (!Suppress) {
375 Character[0] = LEFT_ONEOF_DELIMITER;
376 NewStrCat (OptionString[0], Character);
377 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
378 NewStrCat (OptionString[0], StringPtr);
379 Character[0] = RIGHT_ONEOF_DELIMITER;
380 NewStrCat (OptionString[0], Character);
381 Character[0] = CHAR_CARRIAGE_RETURN;
382 NewStrCat (OptionString[0], Character);
383
384 gBS->FreePool (StringPtr);
385 }
386 }
387 }
388 break;
389
390 case EFI_IFR_ONE_OF_OP:
391 if (Selected) {
392 //
393 // Go ask for input
394 //
395 Status = GetSelectionInputPopUp (Selection, MenuOption);
396 } else {
397 *OptionString = AllocateZeroPool (BufferSize);
398 ASSERT (*OptionString);
399
400 OneOfOption = ValueToOption (Question, QuestionValue);
401 if (OneOfOption == NULL) {
402 gBS->FreePool (*OptionString);
403 return EFI_NOT_FOUND;
404 }
405
406 if ((OneOfOption->SuppressExpression != NULL) &&
407 (OneOfOption->SuppressExpression->Result.Value.b)) {
408 //
409 // This option is suppressed
410 //
411 Suppress = TRUE;
412 } else {
413 Suppress = FALSE;
414 }
415
416 if (Suppress) {
417 //
418 // Current selected option happen to be suppressed,
419 // enforce to select on a non-suppressed option
420 //
421 Link = GetFirstNode (&Question->OptionListHead);
422 while (!IsNull (&Question->OptionListHead, Link)) {
423 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
424
425 if ((OneOfOption->SuppressExpression == NULL) ||
426 !OneOfOption->SuppressExpression->Result.Value.b) {
427 Suppress = FALSE;
428 CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE));
429 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
430 break;
431 }
432
433 Link = GetNextNode (&Question->OptionListHead, Link);
434 }
435 }
436
437 if (!Suppress) {
438 Character[0] = LEFT_ONEOF_DELIMITER;
439 NewStrCat (OptionString[0], Character);
440 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
441 NewStrCat (OptionString[0], StringPtr);
442 Character[0] = RIGHT_ONEOF_DELIMITER;
443 NewStrCat (OptionString[0], Character);
444
445 gBS->FreePool (StringPtr);
446 }
447 }
448 break;
449
450 case EFI_IFR_CHECKBOX_OP:
451 *OptionString = AllocateZeroPool (BufferSize);
452 ASSERT (*OptionString);
453
454 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
455
456 if (Selected) {
457 //
458 // Since this is a BOOLEAN operation, flip it upon selection
459 //
460 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
461
462 //
463 // Perform inconsistent check
464 //
465 Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
466 if (EFI_ERROR (Status)) {
467 //
468 // Inconsistent check fail, restore Question Value
469 //
470 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
471 gBS->FreePool (*OptionString);
472 return Status;
473 }
474
475 //
476 // Save Question value
477 //
478 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
479 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
480 }
481
482 if (QuestionValue->Value.b) {
483 *(OptionString[0] + 1) = CHECK_ON;
484 } else {
485 *(OptionString[0] + 1) = CHECK_OFF;
486 }
487 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
488 break;
489
490 case EFI_IFR_NUMERIC_OP:
491 if (Selected) {
492 //
493 // Go ask for input
494 //
495 Status = GetNumericInput (Selection, MenuOption);
496 } else {
497 *OptionString = AllocateZeroPool (BufferSize);
498 ASSERT (*OptionString);
499
500 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
501
502 //
503 // Formatted print
504 //
505 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
506 Number = (UINT16) GetStringWidth (FormattedNumber);
507 CopyMem (OptionString[0] + 1, FormattedNumber, Number);
508
509 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
510 }
511 break;
512
513 case EFI_IFR_DATE_OP:
514 if (Selected) {
515 //
516 // This is similar to numerics
517 //
518 Status = GetNumericInput (Selection, MenuOption);
519 } else {
520 *OptionString = AllocateZeroPool (BufferSize);
521 ASSERT (*OptionString);
522
523 switch (MenuOption->Sequence) {
524 case 0:
525 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
526 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
527 *(OptionString[0] + 3) = DATE_SEPARATOR;
528 break;
529
530 case 1:
531 SetUnicodeMem (OptionString[0], 4, L' ');
532 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
533 *(OptionString[0] + 6) = DATE_SEPARATOR;
534 break;
535
536 case 2:
537 SetUnicodeMem (OptionString[0], 7, L' ');
538 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", QuestionValue->Value.date.Year);
539 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
540 break;
541 }
542 }
543 break;
544
545 case EFI_IFR_TIME_OP:
546 if (Selected) {
547 //
548 // This is similar to numerics
549 //
550 Status = GetNumericInput (Selection, MenuOption);
551 } else {
552 *OptionString = AllocateZeroPool (BufferSize);
553 ASSERT (*OptionString);
554
555 switch (MenuOption->Sequence) {
556 case 0:
557 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
558 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
559 *(OptionString[0] + 3) = TIME_SEPARATOR;
560 break;
561
562 case 1:
563 SetUnicodeMem (OptionString[0], 4, L' ');
564 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
565 *(OptionString[0] + 6) = TIME_SEPARATOR;
566 break;
567
568 case 2:
569 SetUnicodeMem (OptionString[0], 7, L' ');
570 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
571 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
572 break;
573 }
574 }
575 break;
576
577 case EFI_IFR_STRING_OP:
578 if (Selected) {
579 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
580 ASSERT (StringPtr);
581
582 Status = ReadString (MenuOption, gPromptForData, StringPtr);
583 if (!EFI_ERROR (Status)) {
584 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
585 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
586
587 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
588 }
589
590 gBS->FreePool (StringPtr);
591 } else {
592 *OptionString = AllocateZeroPool (BufferSize);
593 ASSERT (*OptionString);
594
595 if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) {
596 *(OptionString[0]) = '_';
597 } else {
598 if ((Maximum * sizeof (CHAR16)) < BufferSize) {
599 BufferSize = Maximum * sizeof (CHAR16);
600 }
601 CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize);
602 }
603 }
604 break;
605
606 case EFI_IFR_PASSWORD_OP:
607 if (Selected) {
608 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
609 ASSERT (StringPtr);
610
611 //
612 // For interactive passwords, old password is validated by callback
613 //
614 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
615 //
616 // Use a NULL password to test whether old password is required
617 //
618 *StringPtr = 0;
619 Status = PasswordCallback (Selection, MenuOption, StringPtr);
620 if (Status == EFI_NOT_AVAILABLE_YET) {
621 //
622 // Callback request to terminate password input
623 //
624 gBS->FreePool (StringPtr);
625 return EFI_SUCCESS;
626 }
627
628 if (EFI_ERROR (Status)) {
629 //
630 // Old password exist, ask user for the old password
631 //
632 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
633 if (EFI_ERROR (Status)) {
634 gBS->FreePool (StringPtr);
635 return Status;
636 }
637
638 //
639 // Check user input old password
640 //
641 Status = PasswordCallback (Selection, MenuOption, StringPtr);
642 if (EFI_ERROR (Status)) {
643 if (Status == EFI_NOT_READY) {
644 //
645 // Typed in old password incorrect
646 //
647 PasswordInvalid ();
648 } else {
649 Status = EFI_SUCCESS;
650 }
651
652 gBS->FreePool (StringPtr);
653 return Status;
654 }
655 }
656 } else {
657 //
658 // For non-interactive password, validate old password in local
659 //
660 if (*((CHAR16 *) Question->BufferValue) != 0) {
661 //
662 // There is something there! Prompt for password
663 //
664 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
665 if (EFI_ERROR (Status)) {
666 gBS->FreePool (StringPtr);
667 return Status;
668 }
669
670 TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue);
671 TempString[Maximum] = L'\0';
672
673 if (StrCmp (StringPtr, TempString) != 0) {
674 //
675 // Typed in old password incorrect
676 //
677 PasswordInvalid ();
678
679 gBS->FreePool (StringPtr);
680 gBS->FreePool (TempString);
681 return Status;
682 }
683
684 gBS->FreePool (TempString);
685 }
686 }
687
688 //
689 // Ask for new password
690 //
691 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
692 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
693 if (EFI_ERROR (Status)) {
694 //
695 // Reset state machine for interactive password
696 //
697 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
698 PasswordCallback (Selection, MenuOption, NULL);
699 }
700
701 gBS->FreePool (StringPtr);
702 return Status;
703 }
704
705 //
706 // Confirm new password
707 //
708 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
709 ASSERT (TempString);
710 Status = ReadString (MenuOption, gConfirmPassword, TempString);
711 if (EFI_ERROR (Status)) {
712 //
713 // Reset state machine for interactive password
714 //
715 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
716 PasswordCallback (Selection, MenuOption, NULL);
717 }
718
719 gBS->FreePool (StringPtr);
720 gBS->FreePool (TempString);
721 return Status;
722 }
723
724 //
725 // Compare two typed-in new passwords
726 //
727 if (StrCmp (StringPtr, TempString) == 0) {
728 //
729 // Two password match, send it to Configuration Driver
730 //
731 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
732 PasswordCallback (Selection, MenuOption, StringPtr);
733 } else {
734 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
735 SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);
736 }
737 } else {
738 //
739 // Reset state machine for interactive password
740 //
741 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
742 PasswordCallback (Selection, MenuOption, NULL);
743 }
744
745 //
746 // Two password mismatch, prompt error message
747 //
748 do {
749 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString);
750 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
751 }
752
753 gBS->FreePool (TempString);
754 gBS->FreePool (StringPtr);
755 }
756 break;
757
758 default:
759 break;
760 }
761
762 return Status;
763 }
764
765
766 /**
767 Process the help string: Split StringPtr to several lines of strings stored in
768 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
769
770 @param StringPtr The entire help string.
771 @param FormattedString The oupput formatted string.
772 @param RowCount TRUE: if Question is selected.
773
774 **/
775 VOID
776 ProcessHelpString (
777 IN CHAR16 *StringPtr,
778 OUT CHAR16 **FormattedString,
779 IN UINTN RowCount
780 )
781 {
782 CONST UINTN BlockWidth = (UINTN) gHelpBlockWidth - 1;
783 UINTN AllocateSize;
784 //
785 // [PrevCurrIndex, CurrIndex) forms a range of a screen-line
786 //
787 UINTN CurrIndex;
788 UINTN PrevCurrIndex;
789 UINTN LineCount;
790 UINTN VirtualLineCount;
791 //
792 // GlyphOffset stores glyph width of current screen-line
793 //
794 UINTN GlyphOffset;
795 //
796 // GlyphWidth equals to 2 if we meet width directive
797 //
798 UINTN GlyphWidth;
799 //
800 // during scanning, we remember the position of last space character
801 // in case that if next word cannot put in current line, we could restore back to the position
802 // of last space character
803 // while we should also remmeber the glyph width of the last space character for restoring
804 //
805 UINTN LastSpaceIndex;
806 UINTN LastSpaceGlyphWidth;
807 //
808 // every time we begin to form a new screen-line, we should remember glyph width of single character
809 // of last line
810 //
811 UINTN LineStartGlyphWidth;
812 UINTN *IndexArray;
813 UINTN *OldIndexArray;
814
815 //
816 // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )
817 // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want
818 // to bring the width directive of the last line to current screen-line.
819 // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line
820 // different from that of "\wideabcde", we should remember the width directive.
821 //
822 AllocateSize = 0x20;
823 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);
824
825 if (*FormattedString != NULL) {
826 gBS->FreePool (*FormattedString);
827 *FormattedString = NULL;
828 }
829
830 for (PrevCurrIndex = 0, CurrIndex = 0, LineCount = 0, LastSpaceIndex = 0,
831 IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1;
832 (StringPtr[CurrIndex] != CHAR_NULL);
833 CurrIndex ++) {
834
835 if (LineCount == AllocateSize) {
836 AllocateSize += 0x10;
837 OldIndexArray = IndexArray;
838 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);
839 CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3);
840 gBS->FreePool (OldIndexArray);
841 }
842 switch (StringPtr[CurrIndex]) {
843
844 case NARROW_CHAR:
845 case WIDE_CHAR:
846 GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1);
847 if (CurrIndex == 0) {
848 LineStartGlyphWidth = GlyphWidth;
849 }
850 break;
851
852 //
853 // char is '\n'
854 // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN
855 //
856 case CHAR_LINEFEED:
857 //
858 // Store a range of string as a line
859 //
860 IndexArray[LineCount*3] = PrevCurrIndex;
861 IndexArray[LineCount*3+1] = CurrIndex;
862 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
863 LineCount ++;
864 //
865 // Reset offset and save begin position of line
866 //
867 GlyphOffset = 0;
868 LineStartGlyphWidth = GlyphWidth;
869 PrevCurrIndex = CurrIndex + 1;
870 break;
871
872 //
873 // char is '\r'
874 // "\r\n" and "\r" both are handled here
875 //
876 case CHAR_CARRIAGE_RETURN:
877 if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) {
878 //
879 // next char is '\n'
880 //
881 IndexArray[LineCount*3] = PrevCurrIndex;
882 IndexArray[LineCount*3+1] = CurrIndex;
883 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
884 LineCount ++;
885 CurrIndex ++;
886 }
887 GlyphOffset = 0;
888 LineStartGlyphWidth = GlyphWidth;
889 PrevCurrIndex = CurrIndex + 1;
890 break;
891
892 //
893 // char is space or other char
894 //
895 default:
896 GlyphOffset += GlyphWidth;
897 if (GlyphOffset >= BlockWidth) {
898 if (LastSpaceIndex > PrevCurrIndex) {
899 //
900 // LastSpaceIndex points to space inside current screen-line,
901 // restore to LastSpaceIndex
902 // (Otherwise the word is too long to fit one screen-line, just cut it)
903 //
904 CurrIndex = LastSpaceIndex;
905 GlyphWidth = LastSpaceGlyphWidth;
906 } else if (GlyphOffset > BlockWidth) {
907 //
908 // the word is too long to fit one screen-line and we don't get the chance
909 // of GlyphOffset == BlockWidth because GlyphWidth = 2
910 //
911 CurrIndex --;
912 }
913
914 IndexArray[LineCount*3] = PrevCurrIndex;
915 IndexArray[LineCount*3+1] = CurrIndex + 1;
916 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
917 LineStartGlyphWidth = GlyphWidth;
918 LineCount ++;
919 //
920 // Reset offset and save begin position of line
921 //
922 GlyphOffset = 0;
923 PrevCurrIndex = CurrIndex + 1;
924 }
925
926 //
927 // LastSpaceIndex: remember position of last space
928 //
929 if (StringPtr[CurrIndex] == CHAR_SPACE) {
930 LastSpaceIndex = CurrIndex;
931 LastSpaceGlyphWidth = GlyphWidth;
932 }
933 break;
934 }
935 }
936
937 if (GlyphOffset > 0) {
938 IndexArray[LineCount*3] = PrevCurrIndex;
939 IndexArray[LineCount*3+1] = CurrIndex;
940 IndexArray[LineCount*3+2] = GlyphWidth;
941 LineCount ++;
942 }
943
944 if (LineCount == 0) {
945 //
946 // in case we meet null string
947 //
948 IndexArray[0] = 0;
949 IndexArray[1] = 1;
950 //
951 // we assume null string's glyph width is 1
952 //
953 IndexArray[1] = 1;
954 LineCount ++;
955 }
956
957 VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0));
958 *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2);
959
960 for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) {
961 *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (CHAR16) ((IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR);
962 StrnCpy (
963 *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1,
964 StringPtr + IndexArray[CurrIndex*3],
965 IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3]
966 );
967 }
968
969 gBS->FreePool (IndexArray);
970 }