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