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