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