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