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