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