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