1 /** @file 2 Implementation for handling the User Interface option processing. 3 4 5 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "FormDisplay.h" 17 18 #define MAX_TIME_OUT_LEN 0x10 19 20 /** 21 Concatenate a narrow string to another string. 22 23 @param Destination The destination string. 24 @param DestMax The Max length of destination string. 25 @param Source The source string. The string to be concatenated. 26 to the end of Destination. 27 28 **/ 29 VOID 30 NewStrCat ( 31 IN OUT CHAR16 *Destination, 32 IN UINTN DestMax, 33 IN CHAR16 *Source 34 ) 35 { 36 UINTN Length; 37 38 for (Length = 0; Destination[Length] != 0; Length++) 39 ; 40 41 // 42 // We now have the length of the original string 43 // We can safely assume for now that we are concatenating a narrow value to this string. 44 // For instance, the string is "XYZ" and cat'ing ">" 45 // If this assumption changes, we need to make this routine a bit more complex 46 // 47 Destination[Length] = NARROW_CHAR; 48 Length++; 49 50 StrCpyS (Destination + Length, DestMax - Length, Source); 51 } 52 53 /** 54 Get UINT64 type value. 55 56 @param Value Input Hii value. 57 58 @retval UINT64 Return the UINT64 type value. 59 60 **/ 61 UINT64 62 HiiValueToUINT64 ( 63 IN EFI_HII_VALUE *Value 64 ) 65 { 66 UINT64 RetVal; 67 68 RetVal = 0; 69 70 switch (Value->Type) { 71 case EFI_IFR_TYPE_NUM_SIZE_8: 72 RetVal = Value->Value.u8; 73 break; 74 75 case EFI_IFR_TYPE_NUM_SIZE_16: 76 RetVal = Value->Value.u16; 77 break; 78 79 case EFI_IFR_TYPE_NUM_SIZE_32: 80 RetVal = Value->Value.u32; 81 break; 82 83 case EFI_IFR_TYPE_BOOLEAN: 84 RetVal = Value->Value.b; 85 break; 86 87 case EFI_IFR_TYPE_DATE: 88 RetVal = *(UINT64*) &Value->Value.date; 89 break; 90 91 case EFI_IFR_TYPE_TIME: 92 RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff; 93 break; 94 95 default: 96 RetVal = Value->Value.u64; 97 break; 98 } 99 100 return RetVal; 101 } 102 103 /** 104 Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type. 105 106 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to 107 EFI_IFR_TYPE_BUFFER when do the value compare. 108 109 @param Value Expression value to compare on. 110 111 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type. 112 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type. 113 114 **/ 115 BOOLEAN 116 IsTypeInBuffer ( 117 IN EFI_HII_VALUE *Value 118 ) 119 { 120 switch (Value->Type) { 121 case EFI_IFR_TYPE_BUFFER: 122 case EFI_IFR_TYPE_DATE: 123 case EFI_IFR_TYPE_TIME: 124 case EFI_IFR_TYPE_REF: 125 return TRUE; 126 127 default: 128 return FALSE; 129 } 130 } 131 132 /** 133 Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64 134 135 @param Value Expression value to compare on. 136 137 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type. 138 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type. 139 140 **/ 141 BOOLEAN 142 IsTypeInUINT64 ( 143 IN EFI_HII_VALUE *Value 144 ) 145 { 146 switch (Value->Type) { 147 case EFI_IFR_TYPE_NUM_SIZE_8: 148 case EFI_IFR_TYPE_NUM_SIZE_16: 149 case EFI_IFR_TYPE_NUM_SIZE_32: 150 case EFI_IFR_TYPE_NUM_SIZE_64: 151 case EFI_IFR_TYPE_BOOLEAN: 152 return TRUE; 153 154 default: 155 return FALSE; 156 } 157 } 158 159 /** 160 Return the buffer length and buffer pointer for this value. 161 162 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to 163 EFI_IFR_TYPE_BUFFER when do the value compare. 164 165 @param Value Expression value to compare on. 166 @param Buf Return the buffer pointer. 167 @param BufLen Return the buffer length. 168 169 **/ 170 VOID 171 GetBufAndLenForValue ( 172 IN EFI_HII_VALUE *Value, 173 OUT UINT8 **Buf, 174 OUT UINT16 *BufLen 175 ) 176 { 177 switch (Value->Type) { 178 case EFI_IFR_TYPE_BUFFER: 179 *Buf = Value->Buffer; 180 *BufLen = Value->BufferLen; 181 break; 182 183 case EFI_IFR_TYPE_DATE: 184 *Buf = (UINT8 *) (&Value->Value.date); 185 *BufLen = (UINT16) sizeof (EFI_HII_DATE); 186 break; 187 188 case EFI_IFR_TYPE_TIME: 189 *Buf = (UINT8 *) (&Value->Value.time); 190 *BufLen = (UINT16) sizeof (EFI_HII_TIME); 191 break; 192 193 case EFI_IFR_TYPE_REF: 194 *Buf = (UINT8 *) (&Value->Value.ref); 195 *BufLen = (UINT16) sizeof (EFI_HII_REF); 196 break; 197 198 default: 199 *Buf = NULL; 200 *BufLen = 0; 201 } 202 } 203 204 /** 205 Compare two Hii value. 206 207 @param Value1 Expression value to compare on left-hand. 208 @param Value2 Expression value to compare on right-hand. 209 @param Result Return value after compare. 210 retval 0 Two operators equal. 211 return Positive value if Value1 is greater than Value2. 212 retval Negative value if Value1 is less than Value2. 213 @param HiiHandle Only required for string compare. 214 215 @retval other Could not perform compare on two values. 216 @retval EFI_SUCCESS Compare the value success. 217 218 **/ 219 EFI_STATUS 220 CompareHiiValue ( 221 IN EFI_HII_VALUE *Value1, 222 IN EFI_HII_VALUE *Value2, 223 OUT INTN *Result, 224 IN EFI_HII_HANDLE HiiHandle OPTIONAL 225 ) 226 { 227 INT64 Temp64; 228 CHAR16 *Str1; 229 CHAR16 *Str2; 230 UINTN Len; 231 UINT8 *Buf1; 232 UINT16 Buf1Len; 233 UINT8 *Buf2; 234 UINT16 Buf2Len; 235 236 if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) { 237 if (Value1->Value.string == 0 || Value2->Value.string == 0) { 238 // 239 // StringId 0 is reserved 240 // 241 return EFI_INVALID_PARAMETER; 242 } 243 244 if (Value1->Value.string == Value2->Value.string) { 245 *Result = 0; 246 return EFI_SUCCESS; 247 } 248 249 Str1 = GetToken (Value1->Value.string, HiiHandle); 250 if (Str1 == NULL) { 251 // 252 // String not found 253 // 254 return EFI_NOT_FOUND; 255 } 256 257 Str2 = GetToken (Value2->Value.string, HiiHandle); 258 if (Str2 == NULL) { 259 FreePool (Str1); 260 return EFI_NOT_FOUND; 261 } 262 263 *Result = StrCmp (Str1, Str2); 264 265 FreePool (Str1); 266 FreePool (Str2); 267 268 return EFI_SUCCESS; 269 } 270 271 // 272 // Take types(date, time, ref, buffer) as buffer 273 // 274 if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) { 275 GetBufAndLenForValue(Value1, &Buf1, &Buf1Len); 276 GetBufAndLenForValue(Value2, &Buf2, &Buf2Len); 277 278 Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len; 279 *Result = CompareMem (Buf1, Buf2, Len); 280 if ((*Result == 0) && (Buf1Len != Buf2Len)) { 281 // 282 // In this case, means base on samll number buffer, the data is same 283 // So which value has more data, which value is bigger. 284 // 285 *Result = Buf1Len > Buf2Len ? 1 : -1; 286 } 287 return EFI_SUCCESS; 288 } 289 290 // 291 // Take remain types(integer, boolean, date/time) as integer 292 // 293 if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) { 294 Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2); 295 if (Temp64 > 0) { 296 *Result = 1; 297 } else if (Temp64 < 0) { 298 *Result = -1; 299 } else { 300 *Result = 0; 301 } 302 return EFI_SUCCESS; 303 } 304 305 return EFI_UNSUPPORTED; 306 } 307 308 /** 309 Search an Option of a Question by its value. 310 311 @param Question The Question 312 @param OptionValue Value for Option to be searched. 313 314 @retval Pointer Pointer to the found Option. 315 @retval NULL Option not found. 316 317 **/ 318 DISPLAY_QUESTION_OPTION * 319 ValueToOption ( 320 IN FORM_DISPLAY_ENGINE_STATEMENT *Question, 321 IN EFI_HII_VALUE *OptionValue 322 ) 323 { 324 LIST_ENTRY *Link; 325 DISPLAY_QUESTION_OPTION *Option; 326 INTN Result; 327 EFI_HII_VALUE Value; 328 329 Link = GetFirstNode (&Question->OptionListHead); 330 while (!IsNull (&Question->OptionListHead, Link)) { 331 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); 332 333 ZeroMem (&Value, sizeof (EFI_HII_VALUE)); 334 Value.Type = Option->OptionOpCode->Type; 335 CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value)); 336 337 if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) { 338 return Option; 339 } 340 341 Link = GetNextNode (&Question->OptionListHead, Link); 342 } 343 344 return NULL; 345 } 346 347 348 /** 349 Return data element in an Array by its Index. 350 351 @param Array The data array. 352 @param Type Type of the data in this array. 353 @param Index Zero based index for data in this array. 354 355 @retval Value The data to be returned 356 357 **/ 358 UINT64 359 GetArrayData ( 360 IN VOID *Array, 361 IN UINT8 Type, 362 IN UINTN Index 363 ) 364 { 365 UINT64 Data; 366 367 ASSERT (Array != NULL); 368 369 Data = 0; 370 switch (Type) { 371 case EFI_IFR_TYPE_NUM_SIZE_8: 372 Data = (UINT64) *(((UINT8 *) Array) + Index); 373 break; 374 375 case EFI_IFR_TYPE_NUM_SIZE_16: 376 Data = (UINT64) *(((UINT16 *) Array) + Index); 377 break; 378 379 case EFI_IFR_TYPE_NUM_SIZE_32: 380 Data = (UINT64) *(((UINT32 *) Array) + Index); 381 break; 382 383 case EFI_IFR_TYPE_NUM_SIZE_64: 384 Data = (UINT64) *(((UINT64 *) Array) + Index); 385 break; 386 387 default: 388 break; 389 } 390 391 return Data; 392 } 393 394 395 /** 396 Set value of a data element in an Array by its Index. 397 398 @param Array The data array. 399 @param Type Type of the data in this array. 400 @param Index Zero based index for data in this array. 401 @param Value The value to be set. 402 403 **/ 404 VOID 405 SetArrayData ( 406 IN VOID *Array, 407 IN UINT8 Type, 408 IN UINTN Index, 409 IN UINT64 Value 410 ) 411 { 412 413 ASSERT (Array != NULL); 414 415 switch (Type) { 416 case EFI_IFR_TYPE_NUM_SIZE_8: 417 *(((UINT8 *) Array) + Index) = (UINT8) Value; 418 break; 419 420 case EFI_IFR_TYPE_NUM_SIZE_16: 421 *(((UINT16 *) Array) + Index) = (UINT16) Value; 422 break; 423 424 case EFI_IFR_TYPE_NUM_SIZE_32: 425 *(((UINT32 *) Array) + Index) = (UINT32) Value; 426 break; 427 428 case EFI_IFR_TYPE_NUM_SIZE_64: 429 *(((UINT64 *) Array) + Index) = (UINT64) Value; 430 break; 431 432 default: 433 break; 434 } 435 } 436 437 /** 438 Check whether this value already in the array, if yes, return the index. 439 440 @param Array The data array. 441 @param Type Type of the data in this array. 442 @param Value The value to be find. 443 @param Index The index in the array which has same value with Value. 444 445 @retval TRUE Found the value in the array. 446 @retval FALSE Not found the value. 447 448 **/ 449 BOOLEAN 450 FindArrayData ( 451 IN VOID *Array, 452 IN UINT8 Type, 453 IN UINT64 Value, 454 OUT UINTN *Index OPTIONAL 455 ) 456 { 457 UINTN Count; 458 UINT64 TmpValue; 459 UINT64 ValueComp; 460 461 ASSERT (Array != NULL); 462 463 Count = 0; 464 TmpValue = 0; 465 466 switch (Type) { 467 case EFI_IFR_TYPE_NUM_SIZE_8: 468 ValueComp = (UINT8) Value; 469 break; 470 471 case EFI_IFR_TYPE_NUM_SIZE_16: 472 ValueComp = (UINT16) Value; 473 break; 474 475 case EFI_IFR_TYPE_NUM_SIZE_32: 476 ValueComp = (UINT32) Value; 477 break; 478 479 case EFI_IFR_TYPE_NUM_SIZE_64: 480 ValueComp = (UINT64) Value; 481 break; 482 483 default: 484 ValueComp = 0; 485 break; 486 } 487 488 while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) { 489 if (ValueComp == TmpValue) { 490 if (Index != NULL) { 491 *Index = Count; 492 } 493 return TRUE; 494 } 495 496 Count ++; 497 } 498 499 return FALSE; 500 } 501 502 /** 503 Print Question Value according to it's storage width and display attributes. 504 505 @param Question The Question to be printed. 506 @param FormattedNumber Buffer for output string. 507 @param BufferSize The FormattedNumber buffer size in bytes. 508 509 @retval EFI_SUCCESS Print success. 510 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number. 511 512 **/ 513 EFI_STATUS 514 PrintFormattedNumber ( 515 IN FORM_DISPLAY_ENGINE_STATEMENT *Question, 516 IN OUT CHAR16 *FormattedNumber, 517 IN UINTN BufferSize 518 ) 519 { 520 INT64 Value; 521 CHAR16 *Format; 522 EFI_HII_VALUE *QuestionValue; 523 EFI_IFR_NUMERIC *NumericOp; 524 525 if (BufferSize < (21 * sizeof (CHAR16))) { 526 return EFI_BUFFER_TOO_SMALL; 527 } 528 529 QuestionValue = &Question->CurrentValue; 530 NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode; 531 532 Value = (INT64) QuestionValue->Value.u64; 533 switch (NumericOp->Flags & EFI_IFR_DISPLAY) { 534 case EFI_IFR_DISPLAY_INT_DEC: 535 switch (QuestionValue->Type) { 536 case EFI_IFR_NUMERIC_SIZE_1: 537 Value = (INT64) ((INT8) QuestionValue->Value.u8); 538 break; 539 540 case EFI_IFR_NUMERIC_SIZE_2: 541 Value = (INT64) ((INT16) QuestionValue->Value.u16); 542 break; 543 544 case EFI_IFR_NUMERIC_SIZE_4: 545 Value = (INT64) ((INT32) QuestionValue->Value.u32); 546 break; 547 548 case EFI_IFR_NUMERIC_SIZE_8: 549 default: 550 break; 551 } 552 553 if (Value < 0) { 554 Value = -Value; 555 Format = L"-%ld"; 556 } else { 557 Format = L"%ld"; 558 } 559 break; 560 561 case EFI_IFR_DISPLAY_UINT_DEC: 562 Format = L"%ld"; 563 break; 564 565 case EFI_IFR_DISPLAY_UINT_HEX: 566 Format = L"%lx"; 567 break; 568 569 default: 570 return EFI_UNSUPPORTED; 571 } 572 573 UnicodeSPrint (FormattedNumber, BufferSize, Format, Value); 574 575 return EFI_SUCCESS; 576 } 577 578 579 /** 580 Draw a pop up windows based on the dimension, number of lines and 581 strings specified. 582 583 @param RequestedWidth The width of the pop-up. 584 @param NumberOfLines The number of lines. 585 @param Marker The variable argument list for the list of string to be printed. 586 587 **/ 588 VOID 589 CreateSharedPopUp ( 590 IN UINTN RequestedWidth, 591 IN UINTN NumberOfLines, 592 IN VA_LIST Marker 593 ) 594 { 595 UINTN Index; 596 UINTN Count; 597 CHAR16 Character; 598 UINTN Start; 599 UINTN End; 600 UINTN Top; 601 UINTN Bottom; 602 CHAR16 *String; 603 UINTN DimensionsWidth; 604 UINTN DimensionsHeight; 605 606 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn; 607 DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow; 608 609 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); 610 611 if ((RequestedWidth + 2) > DimensionsWidth) { 612 RequestedWidth = DimensionsWidth - 2; 613 } 614 615 // 616 // Subtract the PopUp width from total Columns, allow for one space extra on 617 // each end plus a border. 618 // 619 Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1; 620 End = Start + RequestedWidth + 1; 621 622 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1; 623 Bottom = Top + NumberOfLines + 2; 624 625 Character = BOXDRAW_DOWN_RIGHT; 626 PrintCharAt (Start, Top, Character); 627 Character = BOXDRAW_HORIZONTAL; 628 for (Index = Start; Index + 2 < End; Index++) { 629 PrintCharAt ((UINTN)-1, (UINTN)-1, Character); 630 } 631 632 Character = BOXDRAW_DOWN_LEFT; 633 PrintCharAt ((UINTN)-1, (UINTN)-1, Character); 634 Character = BOXDRAW_VERTICAL; 635 636 Count = 0; 637 for (Index = Top; Index + 2 < Bottom; Index++, Count++) { 638 String = VA_ARG (Marker, CHAR16*); 639 640 // 641 // This will clear the background of the line - we never know who might have been 642 // here before us. This differs from the next clear in that it used the non-reverse 643 // video for normal printing. 644 // 645 if (GetStringWidth (String) / 2 > 1) { 646 ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ()); 647 } 648 649 // 650 // Passing in a space results in the assumption that this is where typing will occur 651 // 652 if (String[0] == L' ') { 653 ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ()); 654 } 655 656 // 657 // Passing in a NULL results in a blank space 658 // 659 if (String[0] == CHAR_NULL) { 660 ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ()); 661 } 662 663 PrintStringAt ( 664 ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1, 665 Index + 1, 666 String 667 ); 668 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ()); 669 PrintCharAt (Start, Index + 1, Character); 670 PrintCharAt (End - 1, Index + 1, Character); 671 } 672 673 Character = BOXDRAW_UP_RIGHT; 674 PrintCharAt (Start, Bottom - 1, Character); 675 Character = BOXDRAW_HORIZONTAL; 676 for (Index = Start; Index + 2 < End; Index++) { 677 PrintCharAt ((UINTN)-1, (UINTN)-1, Character); 678 } 679 680 Character = BOXDRAW_UP_LEFT; 681 PrintCharAt ((UINTN)-1, (UINTN)-1, Character); 682 } 683 684 /** 685 Draw a pop up windows based on the dimension, number of lines and 686 strings specified. 687 688 @param RequestedWidth The width of the pop-up. 689 @param NumberOfLines The number of lines. 690 @param ... A series of text strings that displayed in the pop-up. 691 692 **/ 693 VOID 694 EFIAPI 695 CreateMultiStringPopUp ( 696 IN UINTN RequestedWidth, 697 IN UINTN NumberOfLines, 698 ... 699 ) 700 { 701 VA_LIST Marker; 702 703 VA_START (Marker, NumberOfLines); 704 705 CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker); 706 707 VA_END (Marker); 708 } 709 710 /** 711 Process nothing. 712 713 @param Event The Event need to be process 714 @param Context The context of the event. 715 716 **/ 717 VOID 718 EFIAPI 719 EmptyEventProcess ( 720 IN EFI_EVENT Event, 721 IN VOID *Context 722 ) 723 { 724 } 725 726 /** 727 Process for the refresh interval statement. 728 729 @param Event The Event need to be process 730 @param Context The context of the event. 731 732 **/ 733 VOID 734 EFIAPI 735 RefreshTimeOutProcess ( 736 IN EFI_EVENT Event, 737 IN VOID *Context 738 ) 739 { 740 WARNING_IF_CONTEXT *EventInfo; 741 CHAR16 TimeOutString[MAX_TIME_OUT_LEN]; 742 743 EventInfo = (WARNING_IF_CONTEXT *) Context; 744 745 if (*(EventInfo->TimeOut) == 0) { 746 gBS->CloseEvent (Event); 747 748 gBS->SignalEvent (EventInfo->SyncEvent); 749 return; 750 } 751 752 UnicodeSPrint(TimeOutString, MAX_TIME_OUT_LEN, L"%d", *(EventInfo->TimeOut)); 753 754 CreateDialog (NULL, gEmptyString, EventInfo->ErrorInfo, gPressEnter, gEmptyString, TimeOutString, NULL); 755 756 *(EventInfo->TimeOut) -= 1; 757 } 758 759 /** 760 Display error message for invalid password. 761 762 **/ 763 VOID 764 PasswordInvalid ( 765 VOID 766 ) 767 { 768 EFI_INPUT_KEY Key; 769 770 // 771 // Invalid password, prompt error message 772 // 773 do { 774 CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL); 775 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); 776 } 777 778 /** 779 Process password op code. 780 781 @param MenuOption The menu for current password op code. 782 783 @retval EFI_SUCCESS Question Option process success. 784 @retval Other Question Option process fail. 785 786 **/ 787 EFI_STATUS 788 PasswordProcess ( 789 IN UI_MENU_OPTION *MenuOption 790 ) 791 { 792 CHAR16 *StringPtr; 793 CHAR16 *TempString; 794 UINTN Maximum; 795 EFI_STATUS Status; 796 EFI_IFR_PASSWORD *PasswordInfo; 797 FORM_DISPLAY_ENGINE_STATEMENT *Question; 798 EFI_INPUT_KEY Key; 799 800 Question = MenuOption->ThisTag; 801 PasswordInfo = (EFI_IFR_PASSWORD *) Question->OpCode; 802 Maximum = PasswordInfo->MaxSize; 803 Status = EFI_SUCCESS; 804 805 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); 806 ASSERT (StringPtr); 807 808 // 809 // Use a NULL password to test whether old password is required 810 // 811 *StringPtr = 0; 812 Status = Question->PasswordCheck (gFormData, Question, StringPtr); 813 if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) { 814 // 815 // Password can't be set now. 816 // 817 if (Status == EFI_UNSUPPORTED) { 818 do { 819 CreateDialog (&Key, gEmptyString, gPasswordUnsupported, gPressEnter, gEmptyString, NULL); 820 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); 821 } 822 FreePool (StringPtr); 823 return EFI_SUCCESS; 824 } 825 826 if (EFI_ERROR (Status)) { 827 // 828 // Old password exist, ask user for the old password 829 // 830 Status = ReadString (MenuOption, gPromptForPassword, StringPtr); 831 if (EFI_ERROR (Status)) { 832 FreePool (StringPtr); 833 return Status; 834 } 835 836 // 837 // Check user input old password 838 // 839 Status = Question->PasswordCheck (gFormData, Question, StringPtr); 840 if (EFI_ERROR (Status)) { 841 if (Status == EFI_NOT_READY) { 842 // 843 // Typed in old password incorrect 844 // 845 PasswordInvalid (); 846 } else { 847 Status = EFI_SUCCESS; 848 } 849 850 FreePool (StringPtr); 851 return Status; 852 } 853 } 854 855 // 856 // Ask for new password 857 // 858 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); 859 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr); 860 if (EFI_ERROR (Status)) { 861 // 862 // Reset state machine for password 863 // 864 Question->PasswordCheck (gFormData, Question, NULL); 865 FreePool (StringPtr); 866 return Status; 867 } 868 869 // 870 // Confirm new password 871 // 872 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); 873 ASSERT (TempString); 874 Status = ReadString (MenuOption, gConfirmPassword, TempString); 875 if (EFI_ERROR (Status)) { 876 // 877 // Reset state machine for password 878 // 879 Question->PasswordCheck (gFormData, Question, NULL); 880 FreePool (StringPtr); 881 FreePool (TempString); 882 return Status; 883 } 884 885 // 886 // Compare two typed-in new passwords 887 // 888 if (StrCmp (StringPtr, TempString) == 0) { 889 gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr); 890 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; 891 gUserInput->InputValue.Type = Question->CurrentValue.Type; 892 gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL); 893 894 Status = EFI_SUCCESS; 895 } else { 896 // 897 // Reset state machine for password 898 // 899 Question->PasswordCheck (gFormData, Question, NULL); 900 901 // 902 // Two password mismatch, prompt error message 903 // 904 do { 905 CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL); 906 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); 907 908 Status = EFI_INVALID_PARAMETER; 909 } 910 ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16)); 911 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); 912 FreePool (TempString); 913 FreePool (StringPtr); 914 915 return Status; 916 } 917 918 /** 919 Process a Question's Option (whether selected or un-selected). 920 921 @param MenuOption The MenuOption for this Question. 922 @param Selected TRUE: if Question is selected. 923 @param OptionString Pointer of the Option String to be displayed. 924 @param SkipErrorValue Whether need to return when value without option for it. 925 926 @retval EFI_SUCCESS Question Option process success. 927 @retval Other Question Option process fail. 928 929 **/ 930 EFI_STATUS 931 ProcessOptions ( 932 IN UI_MENU_OPTION *MenuOption, 933 IN BOOLEAN Selected, 934 OUT CHAR16 **OptionString, 935 IN BOOLEAN SkipErrorValue 936 ) 937 { 938 EFI_STATUS Status; 939 CHAR16 *StringPtr; 940 UINTN Index; 941 FORM_DISPLAY_ENGINE_STATEMENT *Question; 942 CHAR16 FormattedNumber[21]; 943 UINT16 Number; 944 CHAR16 Character[2]; 945 EFI_INPUT_KEY Key; 946 UINTN BufferSize; 947 DISPLAY_QUESTION_OPTION *OneOfOption; 948 LIST_ENTRY *Link; 949 EFI_HII_VALUE HiiValue; 950 EFI_HII_VALUE *QuestionValue; 951 DISPLAY_QUESTION_OPTION *Option; 952 UINTN Index2; 953 UINT8 *ValueArray; 954 UINT8 ValueType; 955 EFI_IFR_ORDERED_LIST *OrderList; 956 BOOLEAN ValueInvalid; 957 UINTN MaxLen; 958 959 Status = EFI_SUCCESS; 960 961 StringPtr = NULL; 962 Character[1] = L'\0'; 963 *OptionString = NULL; 964 ValueInvalid = FALSE; 965 966 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); 967 BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow; 968 969 Question = MenuOption->ThisTag; 970 QuestionValue = &Question->CurrentValue; 971 972 switch (Question->OpCode->OpCode) { 973 case EFI_IFR_ORDERED_LIST_OP: 974 975 // 976 // Check whether there are Options of this OrderedList 977 // 978 if (IsListEmpty (&Question->OptionListHead)) { 979 break; 980 } 981 982 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode; 983 984 Link = GetFirstNode (&Question->OptionListHead); 985 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); 986 987 ValueType = OneOfOption->OptionOpCode->Type; 988 ValueArray = Question->CurrentValue.Buffer; 989 990 if (Selected) { 991 // 992 // Go ask for input 993 // 994 Status = GetSelectionInputPopUp (MenuOption); 995 } else { 996 // 997 // We now know how many strings we will have, so we can allocate the 998 // space required for the array or strings. 999 // 1000 MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16); 1001 *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16)); 1002 ASSERT (*OptionString); 1003 1004 HiiValue.Type = ValueType; 1005 HiiValue.Value.u64 = 0; 1006 for (Index = 0; Index < OrderList->MaxContainers; Index++) { 1007 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index); 1008 if (HiiValue.Value.u64 == 0) { 1009 // 1010 // Values for the options in ordered lists should never be a 0 1011 // 1012 break; 1013 } 1014 1015 OneOfOption = ValueToOption (Question, &HiiValue); 1016 if (OneOfOption == NULL) { 1017 if (SkipErrorValue) { 1018 // 1019 // Just try to get the option string, skip the value which not has option. 1020 // 1021 continue; 1022 } 1023 1024 // 1025 // Show error message 1026 // 1027 do { 1028 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); 1029 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); 1030 1031 // 1032 // The initial value of the orderedlist is invalid, force to be valid value 1033 // Exit current DisplayForm with new value. 1034 // 1035 gUserInput->SelectedStatement = Question; 1036 gMisMatch = TRUE; 1037 ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen); 1038 ASSERT (ValueArray != NULL); 1039 gUserInput->InputValue.Buffer = ValueArray; 1040 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; 1041 gUserInput->InputValue.Type = Question->CurrentValue.Type; 1042 1043 Link = GetFirstNode (&Question->OptionListHead); 1044 Index2 = 0; 1045 while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) { 1046 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); 1047 Link = GetNextNode (&Question->OptionListHead, Link); 1048 SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64); 1049 Index2++; 1050 } 1051 SetArrayData (ValueArray, ValueType, Index2, 0); 1052 1053 FreePool (*OptionString); 1054 *OptionString = NULL; 1055 return EFI_NOT_FOUND; 1056 } 1057 1058 Character[0] = LEFT_ONEOF_DELIMITER; 1059 NewStrCat (OptionString[0], MaxLen, Character); 1060 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); 1061 ASSERT (StringPtr != NULL); 1062 NewStrCat (OptionString[0], MaxLen, StringPtr); 1063 Character[0] = RIGHT_ONEOF_DELIMITER; 1064 NewStrCat (OptionString[0], MaxLen, Character); 1065 Character[0] = CHAR_CARRIAGE_RETURN; 1066 NewStrCat (OptionString[0], MaxLen, Character); 1067 FreePool (StringPtr); 1068 } 1069 1070 // 1071 // If valid option more than the max container, skip these options. 1072 // 1073 if (Index >= OrderList->MaxContainers) { 1074 break; 1075 } 1076 1077 // 1078 // Search the other options, try to find the one not in the container. 1079 // 1080 Link = GetFirstNode (&Question->OptionListHead); 1081 while (!IsNull (&Question->OptionListHead, Link)) { 1082 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); 1083 Link = GetNextNode (&Question->OptionListHead, Link); 1084 1085 if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) { 1086 continue; 1087 } 1088 1089 if (SkipErrorValue) { 1090 // 1091 // Not report error, just get the correct option string info. 1092 // 1093 Character[0] = LEFT_ONEOF_DELIMITER; 1094 NewStrCat (OptionString[0], MaxLen, Character); 1095 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); 1096 ASSERT (StringPtr != NULL); 1097 NewStrCat (OptionString[0], MaxLen, StringPtr); 1098 Character[0] = RIGHT_ONEOF_DELIMITER; 1099 NewStrCat (OptionString[0], MaxLen, Character); 1100 Character[0] = CHAR_CARRIAGE_RETURN; 1101 NewStrCat (OptionString[0], MaxLen, Character); 1102 FreePool (StringPtr); 1103 1104 continue; 1105 } 1106 1107 if (!ValueInvalid) { 1108 ValueInvalid = TRUE; 1109 // 1110 // Show error message 1111 // 1112 do { 1113 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); 1114 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); 1115 1116 // 1117 // The initial value of the orderedlist is invalid, force to be valid value 1118 // Exit current DisplayForm with new value. 1119 // 1120 gUserInput->SelectedStatement = Question; 1121 gMisMatch = TRUE; 1122 ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer); 1123 ASSERT (ValueArray != NULL); 1124 gUserInput->InputValue.Buffer = ValueArray; 1125 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; 1126 gUserInput->InputValue.Type = Question->CurrentValue.Type; 1127 } 1128 1129 SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64); 1130 } 1131 1132 if (ValueInvalid) { 1133 FreePool (*OptionString); 1134 *OptionString = NULL; 1135 return EFI_NOT_FOUND; 1136 } 1137 } 1138 break; 1139 1140 case EFI_IFR_ONE_OF_OP: 1141 // 1142 // Check whether there are Options of this OneOf 1143 // 1144 if (IsListEmpty (&Question->OptionListHead)) { 1145 break; 1146 } 1147 if (Selected) { 1148 // 1149 // Go ask for input 1150 // 1151 Status = GetSelectionInputPopUp (MenuOption); 1152 } else { 1153 MaxLen = BufferSize / sizeof(CHAR16); 1154 *OptionString = AllocateZeroPool (BufferSize); 1155 ASSERT (*OptionString); 1156 1157 OneOfOption = ValueToOption (Question, QuestionValue); 1158 if (OneOfOption == NULL) { 1159 if (SkipErrorValue) { 1160 // 1161 // Not report error, just get the correct option string info. 1162 // 1163 Link = GetFirstNode (&Question->OptionListHead); 1164 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); 1165 } else { 1166 // 1167 // Show error message 1168 // 1169 do { 1170 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL); 1171 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); 1172 1173 // 1174 // Force the Question value to be valid 1175 // Exit current DisplayForm with new value. 1176 // 1177 Link = GetFirstNode (&Question->OptionListHead); 1178 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link); 1179 1180 gUserInput->InputValue.Type = Option->OptionOpCode->Type; 1181 switch (gUserInput->InputValue.Type) { 1182 case EFI_IFR_TYPE_NUM_SIZE_8: 1183 gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8; 1184 break; 1185 case EFI_IFR_TYPE_NUM_SIZE_16: 1186 CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16)); 1187 break; 1188 case EFI_IFR_TYPE_NUM_SIZE_32: 1189 CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32)); 1190 break; 1191 case EFI_IFR_TYPE_NUM_SIZE_64: 1192 CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64)); 1193 break; 1194 default: 1195 ASSERT (FALSE); 1196 break; 1197 } 1198 gUserInput->SelectedStatement = Question; 1199 gMisMatch = TRUE; 1200 FreePool (*OptionString); 1201 *OptionString = NULL; 1202 return EFI_NOT_FOUND; 1203 } 1204 } 1205 1206 Character[0] = LEFT_ONEOF_DELIMITER; 1207 NewStrCat (OptionString[0], MaxLen, Character); 1208 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle); 1209 ASSERT (StringPtr != NULL); 1210 NewStrCat (OptionString[0], MaxLen, StringPtr); 1211 Character[0] = RIGHT_ONEOF_DELIMITER; 1212 NewStrCat (OptionString[0], MaxLen, Character); 1213 1214 FreePool (StringPtr); 1215 } 1216 break; 1217 1218 case EFI_IFR_CHECKBOX_OP: 1219 if (Selected) { 1220 // 1221 // Since this is a BOOLEAN operation, flip it upon selection 1222 // 1223 gUserInput->InputValue.Type = QuestionValue->Type; 1224 gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE); 1225 1226 // 1227 // Perform inconsistent check 1228 // 1229 return EFI_SUCCESS; 1230 } else { 1231 *OptionString = AllocateZeroPool (BufferSize); 1232 ASSERT (*OptionString); 1233 1234 *OptionString[0] = LEFT_CHECKBOX_DELIMITER; 1235 1236 if (QuestionValue->Value.b) { 1237 *(OptionString[0] + 1) = CHECK_ON; 1238 } else { 1239 *(OptionString[0] + 1) = CHECK_OFF; 1240 } 1241 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER; 1242 } 1243 break; 1244 1245 case EFI_IFR_NUMERIC_OP: 1246 if (Selected) { 1247 // 1248 // Go ask for input 1249 // 1250 Status = GetNumericInput (MenuOption); 1251 } else { 1252 *OptionString = AllocateZeroPool (BufferSize); 1253 ASSERT (*OptionString); 1254 1255 *OptionString[0] = LEFT_NUMERIC_DELIMITER; 1256 1257 // 1258 // Formatted print 1259 // 1260 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); 1261 Number = (UINT16) GetStringWidth (FormattedNumber); 1262 CopyMem (OptionString[0] + 1, FormattedNumber, Number); 1263 1264 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER; 1265 } 1266 break; 1267 1268 case EFI_IFR_DATE_OP: 1269 if (Selected) { 1270 // 1271 // This is similar to numerics 1272 // 1273 Status = GetNumericInput (MenuOption); 1274 } else { 1275 *OptionString = AllocateZeroPool (BufferSize); 1276 ASSERT (*OptionString); 1277 1278 switch (MenuOption->Sequence) { 1279 case 0: 1280 *OptionString[0] = LEFT_NUMERIC_DELIMITER; 1281 if (QuestionValue->Value.date.Month == 0xff){ 1282 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??"); 1283 } else { 1284 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month); 1285 } 1286 *(OptionString[0] + 3) = DATE_SEPARATOR; 1287 break; 1288 1289 case 1: 1290 SetUnicodeMem (OptionString[0], 4, L' '); 1291 if (QuestionValue->Value.date.Day == 0xff){ 1292 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??"); 1293 } else { 1294 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day); 1295 } 1296 *(OptionString[0] + 6) = DATE_SEPARATOR; 1297 break; 1298 1299 case 2: 1300 SetUnicodeMem (OptionString[0], 7, L' '); 1301 if (QuestionValue->Value.date.Year == 0xff){ 1302 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????"); 1303 } else { 1304 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year); 1305 } 1306 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER; 1307 break; 1308 } 1309 } 1310 break; 1311 1312 case EFI_IFR_TIME_OP: 1313 if (Selected) { 1314 // 1315 // This is similar to numerics 1316 // 1317 Status = GetNumericInput (MenuOption); 1318 } else { 1319 *OptionString = AllocateZeroPool (BufferSize); 1320 ASSERT (*OptionString); 1321 1322 switch (MenuOption->Sequence) { 1323 case 0: 1324 *OptionString[0] = LEFT_NUMERIC_DELIMITER; 1325 if (QuestionValue->Value.time.Hour == 0xff){ 1326 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??"); 1327 } else { 1328 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour); 1329 } 1330 *(OptionString[0] + 3) = TIME_SEPARATOR; 1331 break; 1332 1333 case 1: 1334 SetUnicodeMem (OptionString[0], 4, L' '); 1335 if (QuestionValue->Value.time.Minute == 0xff){ 1336 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??"); 1337 } else { 1338 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute); 1339 } 1340 *(OptionString[0] + 6) = TIME_SEPARATOR; 1341 break; 1342 1343 case 2: 1344 SetUnicodeMem (OptionString[0], 7, L' '); 1345 if (QuestionValue->Value.time.Second == 0xff){ 1346 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??"); 1347 } else { 1348 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second); 1349 } 1350 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER; 1351 break; 1352 } 1353 } 1354 break; 1355 1356 case EFI_IFR_STRING_OP: 1357 if (Selected) { 1358 StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16)); 1359 ASSERT (StringPtr); 1360 CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen); 1361 1362 Status = ReadString (MenuOption, gPromptForData, StringPtr); 1363 if (EFI_ERROR (Status)) { 1364 FreePool (StringPtr); 1365 return Status; 1366 } 1367 1368 gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr); 1369 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen; 1370 gUserInput->InputValue.Type = Question->CurrentValue.Type; 1371 gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL); 1372 FreePool (StringPtr); 1373 return EFI_SUCCESS; 1374 } else { 1375 *OptionString = AllocateZeroPool (BufferSize); 1376 ASSERT (*OptionString); 1377 1378 if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) { 1379 *(OptionString[0]) = '_'; 1380 } else { 1381 if (Question->CurrentValue.BufferLen < BufferSize) { 1382 BufferSize = Question->CurrentValue.BufferLen; 1383 } 1384 CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize); 1385 } 1386 } 1387 break; 1388 1389 case EFI_IFR_PASSWORD_OP: 1390 if (Selected) { 1391 Status = PasswordProcess (MenuOption); 1392 } 1393 break; 1394 1395 default: 1396 break; 1397 } 1398 1399 return Status; 1400 } 1401 1402 1403 /** 1404 Process the help string: Split StringPtr to several lines of strings stored in 1405 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. 1406 1407 @param StringPtr The entire help string. 1408 @param FormattedString The oupput formatted string. 1409 @param EachLineWidth The max string length of each line in the formatted string. 1410 @param RowCount TRUE: if Question is selected. 1411 1412 **/ 1413 UINTN 1414 ProcessHelpString ( 1415 IN CHAR16 *StringPtr, 1416 OUT CHAR16 **FormattedString, 1417 OUT UINT16 *EachLineWidth, 1418 IN UINTN RowCount 1419 ) 1420 { 1421 UINTN Index; 1422 CHAR16 *OutputString; 1423 UINTN TotalRowNum; 1424 UINTN CheckedNum; 1425 UINT16 GlyphWidth; 1426 UINT16 LineWidth; 1427 UINT16 MaxStringLen; 1428 UINT16 StringLen; 1429 1430 TotalRowNum = 0; 1431 CheckedNum = 0; 1432 GlyphWidth = 1; 1433 Index = 0; 1434 MaxStringLen = 0; 1435 StringLen = 0; 1436 1437 // 1438 // Set default help string width. 1439 // 1440 LineWidth = (UINT16) (gHelpBlockWidth - 1); 1441 1442 // 1443 // Get row number of the String. 1444 // 1445 while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) { 1446 if (StringLen > MaxStringLen) { 1447 MaxStringLen = StringLen; 1448 } 1449 1450 TotalRowNum ++; 1451 FreePool (OutputString); 1452 } 1453 *EachLineWidth = MaxStringLen; 1454 1455 *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16)); 1456 ASSERT (*FormattedString != NULL); 1457 1458 // 1459 // Generate formatted help string array. 1460 // 1461 GlyphWidth = 1; 1462 Index = 0; 1463 while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) { 1464 CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16)); 1465 CheckedNum ++; 1466 FreePool (OutputString); 1467 } 1468 1469 return TotalRowNum; 1470 } 1471