]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c
MdeModulePkg:Use safe string functions
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / ProcessOptions.c
1 /** @file
2 Implementation for handling the User Interface option processing.
3
4
5 Copyright (c) 2004 - 2015, 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 Source The source string. The string to be concatenated.
25 to the end of Destination.
26
27 **/
28 VOID
29 NewStrCat (
30 IN OUT CHAR16 *Destination,
31 IN UINTN DestMax,
32 IN CHAR16 *Source
33 )
34 {
35 UINTN Length;
36
37 for (Length = 0; Destination[Length] != 0; Length++)
38 ;
39
40 //
41 // We now have the length of the original string
42 // We can safely assume for now that we are concatenating a narrow value to this string.
43 // For instance, the string is "XYZ" and cat'ing ">"
44 // If this assumption changes, we need to make this routine a bit more complex
45 //
46 Destination[Length] = NARROW_CHAR;
47 Length++;
48
49 StrCpyS (Destination + Length, DestMax - Length, Source);
50 }
51
52 /**
53 Get UINT64 type value.
54
55 @param Value Input Hii value.
56
57 @retval UINT64 Return the UINT64 type value.
58
59 **/
60 UINT64
61 HiiValueToUINT64 (
62 IN EFI_HII_VALUE *Value
63 )
64 {
65 UINT64 RetVal;
66
67 RetVal = 0;
68
69 switch (Value->Type) {
70 case EFI_IFR_TYPE_NUM_SIZE_8:
71 RetVal = Value->Value.u8;
72 break;
73
74 case EFI_IFR_TYPE_NUM_SIZE_16:
75 RetVal = Value->Value.u16;
76 break;
77
78 case EFI_IFR_TYPE_NUM_SIZE_32:
79 RetVal = Value->Value.u32;
80 break;
81
82 case EFI_IFR_TYPE_BOOLEAN:
83 RetVal = Value->Value.b;
84 break;
85
86 case EFI_IFR_TYPE_DATE:
87 RetVal = *(UINT64*) &Value->Value.date;
88 break;
89
90 case EFI_IFR_TYPE_TIME:
91 RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff;
92 break;
93
94 default:
95 RetVal = Value->Value.u64;
96 break;
97 }
98
99 return RetVal;
100 }
101
102 /**
103 Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
104
105 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
106 EFI_IFR_TYPE_BUFFER when do the value compare.
107
108 @param Value Expression value to compare on.
109
110 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
111 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
112
113 **/
114 BOOLEAN
115 IsTypeInBuffer (
116 IN EFI_HII_VALUE *Value
117 )
118 {
119 switch (Value->Type) {
120 case EFI_IFR_TYPE_BUFFER:
121 case EFI_IFR_TYPE_DATE:
122 case EFI_IFR_TYPE_TIME:
123 case EFI_IFR_TYPE_REF:
124 return TRUE;
125
126 default:
127 return FALSE;
128 }
129 }
130
131 /**
132 Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
133
134 @param Value Expression value to compare on.
135
136 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
137 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
138
139 **/
140 BOOLEAN
141 IsTypeInUINT64 (
142 IN EFI_HII_VALUE *Value
143 )
144 {
145 switch (Value->Type) {
146 case EFI_IFR_TYPE_NUM_SIZE_8:
147 case EFI_IFR_TYPE_NUM_SIZE_16:
148 case EFI_IFR_TYPE_NUM_SIZE_32:
149 case EFI_IFR_TYPE_NUM_SIZE_64:
150 case EFI_IFR_TYPE_BOOLEAN:
151 return TRUE;
152
153 default:
154 return FALSE;
155 }
156 }
157
158 /**
159 Return the buffer length and buffer pointer for this value.
160
161 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
162 EFI_IFR_TYPE_BUFFER when do the value compare.
163
164 @param Value Expression value to compare on.
165 @param Buf Return the buffer pointer.
166 @param BufLen Return the buffer length.
167
168 **/
169 VOID
170 GetBufAndLenForValue (
171 IN EFI_HII_VALUE *Value,
172 OUT UINT8 **Buf,
173 OUT UINT16 *BufLen
174 )
175 {
176 switch (Value->Type) {
177 case EFI_IFR_TYPE_BUFFER:
178 *Buf = Value->Buffer;
179 *BufLen = Value->BufferLen;
180 break;
181
182 case EFI_IFR_TYPE_DATE:
183 *Buf = (UINT8 *) (&Value->Value.date);
184 *BufLen = (UINT16) sizeof (EFI_HII_DATE);
185 break;
186
187 case EFI_IFR_TYPE_TIME:
188 *Buf = (UINT8 *) (&Value->Value.time);
189 *BufLen = (UINT16) sizeof (EFI_HII_TIME);
190 break;
191
192 case EFI_IFR_TYPE_REF:
193 *Buf = (UINT8 *) (&Value->Value.ref);
194 *BufLen = (UINT16) sizeof (EFI_HII_REF);
195 break;
196
197 default:
198 *Buf = NULL;
199 *BufLen = 0;
200 }
201 }
202
203 /**
204 Compare two Hii value.
205
206 @param Value1 Expression value to compare on left-hand.
207 @param Value2 Expression value to compare on right-hand.
208 @param Result Return value after compare.
209 retval 0 Two operators equal.
210 return Positive value if Value1 is greater than Value2.
211 retval Negative value if Value1 is less than Value2.
212 @param HiiHandle Only required for string compare.
213
214 @retval other Could not perform compare on two values.
215 @retval EFI_SUCCESS Compare the value success.
216
217 **/
218 EFI_STATUS
219 CompareHiiValue (
220 IN EFI_HII_VALUE *Value1,
221 IN EFI_HII_VALUE *Value2,
222 OUT INTN *Result,
223 IN EFI_HII_HANDLE HiiHandle OPTIONAL
224 )
225 {
226 INT64 Temp64;
227 CHAR16 *Str1;
228 CHAR16 *Str2;
229 UINTN Len;
230 UINT8 *Buf1;
231 UINT16 Buf1Len;
232 UINT8 *Buf2;
233 UINT16 Buf2Len;
234
235 if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) {
236 if (Value1->Value.string == 0 || Value2->Value.string == 0) {
237 //
238 // StringId 0 is reserved
239 //
240 return EFI_INVALID_PARAMETER;
241 }
242
243 if (Value1->Value.string == Value2->Value.string) {
244 *Result = 0;
245 return EFI_SUCCESS;
246 }
247
248 Str1 = GetToken (Value1->Value.string, HiiHandle);
249 if (Str1 == NULL) {
250 //
251 // String not found
252 //
253 return EFI_NOT_FOUND;
254 }
255
256 Str2 = GetToken (Value2->Value.string, HiiHandle);
257 if (Str2 == NULL) {
258 FreePool (Str1);
259 return EFI_NOT_FOUND;
260 }
261
262 *Result = StrCmp (Str1, Str2);
263
264 FreePool (Str1);
265 FreePool (Str2);
266
267 return EFI_SUCCESS;
268 }
269
270 //
271 // Take types(date, time, ref, buffer) as buffer
272 //
273 if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) {
274 GetBufAndLenForValue(Value1, &Buf1, &Buf1Len);
275 GetBufAndLenForValue(Value2, &Buf2, &Buf2Len);
276
277 Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;
278 *Result = CompareMem (Buf1, Buf2, Len);
279 if ((*Result == 0) && (Buf1Len != Buf2Len)) {
280 //
281 // In this case, means base on samll number buffer, the data is same
282 // So which value has more data, which value is bigger.
283 //
284 *Result = Buf1Len > Buf2Len ? 1 : -1;
285 }
286 return EFI_SUCCESS;
287 }
288
289 //
290 // Take remain types(integer, boolean, date/time) as integer
291 //
292 if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) {
293 Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2);
294 if (Temp64 > 0) {
295 *Result = 1;
296 } else if (Temp64 < 0) {
297 *Result = -1;
298 } else {
299 *Result = 0;
300 }
301 return EFI_SUCCESS;
302 }
303
304 return EFI_UNSUPPORTED;
305 }
306
307 /**
308 Search an Option of a Question by its value.
309
310 @param Question The Question
311 @param OptionValue Value for Option to be searched.
312
313 @retval Pointer Pointer to the found Option.
314 @retval NULL Option not found.
315
316 **/
317 DISPLAY_QUESTION_OPTION *
318 ValueToOption (
319 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
320 IN EFI_HII_VALUE *OptionValue
321 )
322 {
323 LIST_ENTRY *Link;
324 DISPLAY_QUESTION_OPTION *Option;
325 INTN Result;
326 EFI_HII_VALUE Value;
327
328 Link = GetFirstNode (&Question->OptionListHead);
329 while (!IsNull (&Question->OptionListHead, Link)) {
330 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
331
332 ZeroMem (&Value, sizeof (EFI_HII_VALUE));
333 Value.Type = Option->OptionOpCode->Type;
334 CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
335
336 if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
337 return Option;
338 }
339
340 Link = GetNextNode (&Question->OptionListHead, Link);
341 }
342
343 return NULL;
344 }
345
346
347 /**
348 Return data element in an Array by its Index.
349
350 @param Array The data array.
351 @param Type Type of the data in this array.
352 @param Index Zero based index for data in this array.
353
354 @retval Value The data to be returned
355
356 **/
357 UINT64
358 GetArrayData (
359 IN VOID *Array,
360 IN UINT8 Type,
361 IN UINTN Index
362 )
363 {
364 UINT64 Data;
365
366 ASSERT (Array != NULL);
367
368 Data = 0;
369 switch (Type) {
370 case EFI_IFR_TYPE_NUM_SIZE_8:
371 Data = (UINT64) *(((UINT8 *) Array) + Index);
372 break;
373
374 case EFI_IFR_TYPE_NUM_SIZE_16:
375 Data = (UINT64) *(((UINT16 *) Array) + Index);
376 break;
377
378 case EFI_IFR_TYPE_NUM_SIZE_32:
379 Data = (UINT64) *(((UINT32 *) Array) + Index);
380 break;
381
382 case EFI_IFR_TYPE_NUM_SIZE_64:
383 Data = (UINT64) *(((UINT64 *) Array) + Index);
384 break;
385
386 default:
387 break;
388 }
389
390 return Data;
391 }
392
393
394 /**
395 Set value of a data element in an Array by its Index.
396
397 @param Array The data array.
398 @param Type Type of the data in this array.
399 @param Index Zero based index for data in this array.
400 @param Value The value to be set.
401
402 **/
403 VOID
404 SetArrayData (
405 IN VOID *Array,
406 IN UINT8 Type,
407 IN UINTN Index,
408 IN UINT64 Value
409 )
410 {
411
412 ASSERT (Array != NULL);
413
414 switch (Type) {
415 case EFI_IFR_TYPE_NUM_SIZE_8:
416 *(((UINT8 *) Array) + Index) = (UINT8) Value;
417 break;
418
419 case EFI_IFR_TYPE_NUM_SIZE_16:
420 *(((UINT16 *) Array) + Index) = (UINT16) Value;
421 break;
422
423 case EFI_IFR_TYPE_NUM_SIZE_32:
424 *(((UINT32 *) Array) + Index) = (UINT32) Value;
425 break;
426
427 case EFI_IFR_TYPE_NUM_SIZE_64:
428 *(((UINT64 *) Array) + Index) = (UINT64) Value;
429 break;
430
431 default:
432 break;
433 }
434 }
435
436 /**
437 Check whether this value already in the array, if yes, return the index.
438
439 @param Array The data array.
440 @param Type Type of the data in this array.
441 @param Value The value to be find.
442 @param Index The index in the array which has same value with Value.
443
444 @retval TRUE Found the value in the array.
445 @retval FALSE Not found the value.
446
447 **/
448 BOOLEAN
449 FindArrayData (
450 IN VOID *Array,
451 IN UINT8 Type,
452 IN UINT64 Value,
453 OUT UINTN *Index OPTIONAL
454 )
455 {
456 UINTN Count;
457 UINT64 TmpValue;
458 UINT64 ValueComp;
459
460 ASSERT (Array != NULL);
461
462 Count = 0;
463 TmpValue = 0;
464
465 switch (Type) {
466 case EFI_IFR_TYPE_NUM_SIZE_8:
467 ValueComp = (UINT8) Value;
468 break;
469
470 case EFI_IFR_TYPE_NUM_SIZE_16:
471 ValueComp = (UINT16) Value;
472 break;
473
474 case EFI_IFR_TYPE_NUM_SIZE_32:
475 ValueComp = (UINT32) Value;
476 break;
477
478 case EFI_IFR_TYPE_NUM_SIZE_64:
479 ValueComp = (UINT64) Value;
480 break;
481
482 default:
483 ValueComp = 0;
484 break;
485 }
486
487 while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {
488 if (ValueComp == TmpValue) {
489 if (Index != NULL) {
490 *Index = Count;
491 }
492 return TRUE;
493 }
494
495 Count ++;
496 }
497
498 return FALSE;
499 }
500
501 /**
502 Print Question Value according to it's storage width and display attributes.
503
504 @param Question The Question to be printed.
505 @param FormattedNumber Buffer for output string.
506 @param BufferSize The FormattedNumber buffer size in bytes.
507
508 @retval EFI_SUCCESS Print success.
509 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
510
511 **/
512 EFI_STATUS
513 PrintFormattedNumber (
514 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
515 IN OUT CHAR16 *FormattedNumber,
516 IN UINTN BufferSize
517 )
518 {
519 INT64 Value;
520 CHAR16 *Format;
521 EFI_HII_VALUE *QuestionValue;
522 EFI_IFR_NUMERIC *NumericOp;
523
524 if (BufferSize < (21 * sizeof (CHAR16))) {
525 return EFI_BUFFER_TOO_SMALL;
526 }
527
528 QuestionValue = &Question->CurrentValue;
529 NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;
530
531 Value = (INT64) QuestionValue->Value.u64;
532 switch (NumericOp->Flags & EFI_IFR_DISPLAY) {
533 case EFI_IFR_DISPLAY_INT_DEC:
534 switch (QuestionValue->Type) {
535 case EFI_IFR_NUMERIC_SIZE_1:
536 Value = (INT64) ((INT8) QuestionValue->Value.u8);
537 break;
538
539 case EFI_IFR_NUMERIC_SIZE_2:
540 Value = (INT64) ((INT16) QuestionValue->Value.u16);
541 break;
542
543 case EFI_IFR_NUMERIC_SIZE_4:
544 Value = (INT64) ((INT32) QuestionValue->Value.u32);
545 break;
546
547 case EFI_IFR_NUMERIC_SIZE_8:
548 default:
549 break;
550 }
551
552 if (Value < 0) {
553 Value = -Value;
554 Format = L"-%ld";
555 } else {
556 Format = L"%ld";
557 }
558 break;
559
560 case EFI_IFR_DISPLAY_UINT_DEC:
561 Format = L"%ld";
562 break;
563
564 case EFI_IFR_DISPLAY_UINT_HEX:
565 Format = L"%lx";
566 break;
567
568 default:
569 return EFI_UNSUPPORTED;
570 break;
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 FreePool (StringPtr);
818 return EFI_SUCCESS;
819 }
820
821 if (EFI_ERROR (Status)) {
822 //
823 // Old password exist, ask user for the old password
824 //
825 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
826 if (EFI_ERROR (Status)) {
827 FreePool (StringPtr);
828 return Status;
829 }
830
831 //
832 // Check user input old password
833 //
834 Status = Question->PasswordCheck (gFormData, Question, StringPtr);
835 if (EFI_ERROR (Status)) {
836 if (Status == EFI_NOT_READY) {
837 //
838 // Typed in old password incorrect
839 //
840 PasswordInvalid ();
841 } else {
842 Status = EFI_SUCCESS;
843 }
844
845 FreePool (StringPtr);
846 return Status;
847 }
848 }
849
850 //
851 // Ask for new password
852 //
853 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
854 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
855 if (EFI_ERROR (Status)) {
856 //
857 // Reset state machine for password
858 //
859 Question->PasswordCheck (gFormData, Question, NULL);
860 FreePool (StringPtr);
861 return Status;
862 }
863
864 //
865 // Confirm new password
866 //
867 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
868 ASSERT (TempString);
869 Status = ReadString (MenuOption, gConfirmPassword, TempString);
870 if (EFI_ERROR (Status)) {
871 //
872 // Reset state machine for password
873 //
874 Question->PasswordCheck (gFormData, Question, NULL);
875 FreePool (StringPtr);
876 FreePool (TempString);
877 return Status;
878 }
879
880 //
881 // Compare two typed-in new passwords
882 //
883 if (StrCmp (StringPtr, TempString) == 0) {
884 gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
885 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
886 gUserInput->InputValue.Type = Question->CurrentValue.Type;
887 gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
888 FreePool (StringPtr);
889
890 Status = EFI_SUCCESS;
891
892 if (EFI_ERROR (Status)) {
893 //
894 // Reset state machine for password
895 //
896 Question->PasswordCheck (gFormData, Question, NULL);
897 }
898
899 return Status;
900 } else {
901 //
902 // Reset state machine for password
903 //
904 Question->PasswordCheck (gFormData, Question, NULL);
905
906 //
907 // Two password mismatch, prompt error message
908 //
909 do {
910 CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL);
911 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
912
913 Status = EFI_INVALID_PARAMETER;
914 }
915
916 FreePool (TempString);
917 FreePool (StringPtr);
918
919 return Status;
920 }
921
922 /**
923 Process a Question's Option (whether selected or un-selected).
924
925 @param MenuOption The MenuOption for this Question.
926 @param Selected TRUE: if Question is selected.
927 @param OptionString Pointer of the Option String to be displayed.
928 @param SkipErrorValue Whether need to return when value without option for it.
929
930 @retval EFI_SUCCESS Question Option process success.
931 @retval Other Question Option process fail.
932
933 **/
934 EFI_STATUS
935 ProcessOptions (
936 IN UI_MENU_OPTION *MenuOption,
937 IN BOOLEAN Selected,
938 OUT CHAR16 **OptionString,
939 IN BOOLEAN SkipErrorValue
940 )
941 {
942 EFI_STATUS Status;
943 CHAR16 *StringPtr;
944 UINTN Index;
945 FORM_DISPLAY_ENGINE_STATEMENT *Question;
946 CHAR16 FormattedNumber[21];
947 UINT16 Number;
948 CHAR16 Character[2];
949 EFI_INPUT_KEY Key;
950 UINTN BufferSize;
951 DISPLAY_QUESTION_OPTION *OneOfOption;
952 LIST_ENTRY *Link;
953 EFI_HII_VALUE HiiValue;
954 EFI_HII_VALUE *QuestionValue;
955 DISPLAY_QUESTION_OPTION *Option;
956 UINTN Index2;
957 UINT8 *ValueArray;
958 UINT8 ValueType;
959 EFI_IFR_ORDERED_LIST *OrderList;
960 BOOLEAN ValueInvalid;
961 UINTN MaxLen;
962
963 Status = EFI_SUCCESS;
964
965 StringPtr = NULL;
966 Character[1] = L'\0';
967 *OptionString = NULL;
968 ValueInvalid = FALSE;
969
970 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
971 BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow;
972
973 Question = MenuOption->ThisTag;
974 QuestionValue = &Question->CurrentValue;
975
976 switch (Question->OpCode->OpCode) {
977 case EFI_IFR_ORDERED_LIST_OP:
978
979 //
980 // Check whether there are Options of this OrderedList
981 //
982 if (IsListEmpty (&Question->OptionListHead)) {
983 break;
984 }
985
986 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
987
988 Link = GetFirstNode (&Question->OptionListHead);
989 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
990
991 ValueType = OneOfOption->OptionOpCode->Type;
992 ValueArray = Question->CurrentValue.Buffer;
993
994 if (Selected) {
995 //
996 // Go ask for input
997 //
998 Status = GetSelectionInputPopUp (MenuOption);
999 } else {
1000 //
1001 // We now know how many strings we will have, so we can allocate the
1002 // space required for the array or strings.
1003 //
1004 MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16);
1005 *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
1006 ASSERT (*OptionString);
1007
1008 HiiValue.Type = ValueType;
1009 HiiValue.Value.u64 = 0;
1010 for (Index = 0; Index < OrderList->MaxContainers; Index++) {
1011 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
1012 if (HiiValue.Value.u64 == 0) {
1013 //
1014 // Values for the options in ordered lists should never be a 0
1015 //
1016 break;
1017 }
1018
1019 OneOfOption = ValueToOption (Question, &HiiValue);
1020 if (OneOfOption == NULL) {
1021 if (SkipErrorValue) {
1022 //
1023 // Just try to get the option string, skip the value which not has option.
1024 //
1025 continue;
1026 }
1027
1028 //
1029 // Show error message
1030 //
1031 do {
1032 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
1033 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1034
1035 //
1036 // The initial value of the orderedlist is invalid, force to be valid value
1037 // Exit current DisplayForm with new value.
1038 //
1039 gUserInput->SelectedStatement = Question;
1040 gMisMatch = TRUE;
1041 ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen);
1042 ASSERT (ValueArray != NULL);
1043 gUserInput->InputValue.Buffer = ValueArray;
1044 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1045 gUserInput->InputValue.Type = Question->CurrentValue.Type;
1046
1047 Link = GetFirstNode (&Question->OptionListHead);
1048 Index2 = 0;
1049 while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) {
1050 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1051 Link = GetNextNode (&Question->OptionListHead, Link);
1052 SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64);
1053 Index2++;
1054 }
1055 SetArrayData (ValueArray, ValueType, Index2, 0);
1056
1057 FreePool (*OptionString);
1058 *OptionString = NULL;
1059 return EFI_NOT_FOUND;
1060 }
1061
1062 Character[0] = LEFT_ONEOF_DELIMITER;
1063 NewStrCat (OptionString[0], MaxLen, Character);
1064 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1065 ASSERT (StringPtr != NULL);
1066 NewStrCat (OptionString[0], MaxLen, StringPtr);
1067 Character[0] = RIGHT_ONEOF_DELIMITER;
1068 NewStrCat (OptionString[0], MaxLen, Character);
1069 Character[0] = CHAR_CARRIAGE_RETURN;
1070 NewStrCat (OptionString[0], MaxLen, Character);
1071 FreePool (StringPtr);
1072 }
1073
1074 //
1075 // If valid option more than the max container, skip these options.
1076 //
1077 if (Index >= OrderList->MaxContainers) {
1078 break;
1079 }
1080
1081 //
1082 // Search the other options, try to find the one not in the container.
1083 //
1084 Link = GetFirstNode (&Question->OptionListHead);
1085 while (!IsNull (&Question->OptionListHead, Link)) {
1086 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1087 Link = GetNextNode (&Question->OptionListHead, Link);
1088
1089 if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) {
1090 continue;
1091 }
1092
1093 if (SkipErrorValue) {
1094 //
1095 // Not report error, just get the correct option string info.
1096 //
1097 Character[0] = LEFT_ONEOF_DELIMITER;
1098 NewStrCat (OptionString[0], MaxLen, Character);
1099 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1100 ASSERT (StringPtr != NULL);
1101 NewStrCat (OptionString[0], MaxLen, StringPtr);
1102 Character[0] = RIGHT_ONEOF_DELIMITER;
1103 NewStrCat (OptionString[0], MaxLen, Character);
1104 Character[0] = CHAR_CARRIAGE_RETURN;
1105 NewStrCat (OptionString[0], MaxLen, Character);
1106 FreePool (StringPtr);
1107
1108 continue;
1109 }
1110
1111 if (!ValueInvalid) {
1112 ValueInvalid = TRUE;
1113 //
1114 // Show error message
1115 //
1116 do {
1117 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
1118 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1119
1120 //
1121 // The initial value of the orderedlist is invalid, force to be valid value
1122 // Exit current DisplayForm with new value.
1123 //
1124 gUserInput->SelectedStatement = Question;
1125 gMisMatch = TRUE;
1126 ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer);
1127 ASSERT (ValueArray != NULL);
1128 gUserInput->InputValue.Buffer = ValueArray;
1129 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1130 gUserInput->InputValue.Type = Question->CurrentValue.Type;
1131 }
1132
1133 SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64);
1134 }
1135
1136 if (ValueInvalid) {
1137 FreePool (*OptionString);
1138 *OptionString = NULL;
1139 return EFI_NOT_FOUND;
1140 }
1141 }
1142 break;
1143
1144 case EFI_IFR_ONE_OF_OP:
1145 //
1146 // Check whether there are Options of this OneOf
1147 //
1148 if (IsListEmpty (&Question->OptionListHead)) {
1149 break;
1150 }
1151 if (Selected) {
1152 //
1153 // Go ask for input
1154 //
1155 Status = GetSelectionInputPopUp (MenuOption);
1156 } else {
1157 MaxLen = BufferSize / sizeof(CHAR16);
1158 *OptionString = AllocateZeroPool (BufferSize);
1159 ASSERT (*OptionString);
1160
1161 OneOfOption = ValueToOption (Question, QuestionValue);
1162 if (OneOfOption == NULL) {
1163 if (SkipErrorValue) {
1164 //
1165 // Not report error, just get the correct option string info.
1166 //
1167 Link = GetFirstNode (&Question->OptionListHead);
1168 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1169 } else {
1170 //
1171 // Show error message
1172 //
1173 do {
1174 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
1175 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1176
1177 //
1178 // Force the Question value to be valid
1179 // Exit current DisplayForm with new value.
1180 //
1181 Link = GetFirstNode (&Question->OptionListHead);
1182 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1183
1184 gUserInput->InputValue.Type = Option->OptionOpCode->Type;
1185 switch (gUserInput->InputValue.Type) {
1186 case EFI_IFR_TYPE_NUM_SIZE_8:
1187 gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8;
1188 break;
1189 case EFI_IFR_TYPE_NUM_SIZE_16:
1190 CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16));
1191 break;
1192 case EFI_IFR_TYPE_NUM_SIZE_32:
1193 CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32));
1194 break;
1195 case EFI_IFR_TYPE_NUM_SIZE_64:
1196 CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64));
1197 break;
1198 default:
1199 ASSERT (FALSE);
1200 break;
1201 }
1202 gUserInput->SelectedStatement = Question;
1203 gMisMatch = TRUE;
1204 FreePool (*OptionString);
1205 *OptionString = NULL;
1206 return EFI_NOT_FOUND;
1207 }
1208 }
1209
1210 Character[0] = LEFT_ONEOF_DELIMITER;
1211 NewStrCat (OptionString[0], MaxLen, Character);
1212 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1213 ASSERT (StringPtr != NULL);
1214 NewStrCat (OptionString[0], MaxLen, StringPtr);
1215 Character[0] = RIGHT_ONEOF_DELIMITER;
1216 NewStrCat (OptionString[0], MaxLen, Character);
1217
1218 FreePool (StringPtr);
1219 }
1220 break;
1221
1222 case EFI_IFR_CHECKBOX_OP:
1223 if (Selected) {
1224 //
1225 // Since this is a BOOLEAN operation, flip it upon selection
1226 //
1227 gUserInput->InputValue.Type = QuestionValue->Type;
1228 gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
1229
1230 //
1231 // Perform inconsistent check
1232 //
1233 return EFI_SUCCESS;
1234 } else {
1235 *OptionString = AllocateZeroPool (BufferSize);
1236 ASSERT (*OptionString);
1237
1238 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
1239
1240 if (QuestionValue->Value.b) {
1241 *(OptionString[0] + 1) = CHECK_ON;
1242 } else {
1243 *(OptionString[0] + 1) = CHECK_OFF;
1244 }
1245 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
1246 }
1247 break;
1248
1249 case EFI_IFR_NUMERIC_OP:
1250 if (Selected) {
1251 //
1252 // Go ask for input
1253 //
1254 Status = GetNumericInput (MenuOption);
1255 } else {
1256 *OptionString = AllocateZeroPool (BufferSize);
1257 ASSERT (*OptionString);
1258
1259 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
1260
1261 //
1262 // Formatted print
1263 //
1264 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
1265 Number = (UINT16) GetStringWidth (FormattedNumber);
1266 CopyMem (OptionString[0] + 1, FormattedNumber, Number);
1267
1268 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
1269 }
1270 break;
1271
1272 case EFI_IFR_DATE_OP:
1273 if (Selected) {
1274 //
1275 // This is similar to numerics
1276 //
1277 Status = GetNumericInput (MenuOption);
1278 } else {
1279 *OptionString = AllocateZeroPool (BufferSize);
1280 ASSERT (*OptionString);
1281
1282 switch (MenuOption->Sequence) {
1283 case 0:
1284 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
1285 if (QuestionValue->Value.date.Month == 0xff){
1286 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
1287 } else {
1288 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
1289 }
1290 *(OptionString[0] + 3) = DATE_SEPARATOR;
1291 break;
1292
1293 case 1:
1294 SetUnicodeMem (OptionString[0], 4, L' ');
1295 if (QuestionValue->Value.date.Day == 0xff){
1296 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
1297 } else {
1298 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
1299 }
1300 *(OptionString[0] + 6) = DATE_SEPARATOR;
1301 break;
1302
1303 case 2:
1304 SetUnicodeMem (OptionString[0], 7, L' ');
1305 if (QuestionValue->Value.date.Year == 0xff){
1306 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????");
1307 } else {
1308 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year);
1309 }
1310 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
1311 break;
1312 }
1313 }
1314 break;
1315
1316 case EFI_IFR_TIME_OP:
1317 if (Selected) {
1318 //
1319 // This is similar to numerics
1320 //
1321 Status = GetNumericInput (MenuOption);
1322 } else {
1323 *OptionString = AllocateZeroPool (BufferSize);
1324 ASSERT (*OptionString);
1325
1326 switch (MenuOption->Sequence) {
1327 case 0:
1328 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
1329 if (QuestionValue->Value.time.Hour == 0xff){
1330 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
1331 } else {
1332 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
1333 }
1334 *(OptionString[0] + 3) = TIME_SEPARATOR;
1335 break;
1336
1337 case 1:
1338 SetUnicodeMem (OptionString[0], 4, L' ');
1339 if (QuestionValue->Value.time.Minute == 0xff){
1340 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
1341 } else {
1342 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
1343 }
1344 *(OptionString[0] + 6) = TIME_SEPARATOR;
1345 break;
1346
1347 case 2:
1348 SetUnicodeMem (OptionString[0], 7, L' ');
1349 if (QuestionValue->Value.time.Second == 0xff){
1350 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??");
1351 } else {
1352 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
1353 }
1354 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
1355 break;
1356 }
1357 }
1358 break;
1359
1360 case EFI_IFR_STRING_OP:
1361 if (Selected) {
1362 StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16));
1363 ASSERT (StringPtr);
1364 CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);
1365
1366 Status = ReadString (MenuOption, gPromptForData, StringPtr);
1367 if (EFI_ERROR (Status)) {
1368 FreePool (StringPtr);
1369 return Status;
1370 }
1371
1372 gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
1373 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1374 gUserInput->InputValue.Type = Question->CurrentValue.Type;
1375 gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
1376 FreePool (StringPtr);
1377 return EFI_SUCCESS;
1378 } else {
1379 *OptionString = AllocateZeroPool (BufferSize);
1380 ASSERT (*OptionString);
1381
1382 if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) {
1383 *(OptionString[0]) = '_';
1384 } else {
1385 if (Question->CurrentValue.BufferLen < BufferSize) {
1386 BufferSize = Question->CurrentValue.BufferLen;
1387 }
1388 CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize);
1389 }
1390 }
1391 break;
1392
1393 case EFI_IFR_PASSWORD_OP:
1394 if (Selected) {
1395 Status = PasswordProcess (MenuOption);
1396 }
1397 break;
1398
1399 default:
1400 break;
1401 }
1402
1403 return Status;
1404 }
1405
1406
1407 /**
1408 Process the help string: Split StringPtr to several lines of strings stored in
1409 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
1410
1411 @param StringPtr The entire help string.
1412 @param FormattedString The oupput formatted string.
1413 @param EachLineWidth The max string length of each line in the formatted string.
1414 @param RowCount TRUE: if Question is selected.
1415
1416 **/
1417 UINTN
1418 ProcessHelpString (
1419 IN CHAR16 *StringPtr,
1420 OUT CHAR16 **FormattedString,
1421 OUT UINT16 *EachLineWidth,
1422 IN UINTN RowCount
1423 )
1424 {
1425 UINTN Index;
1426 CHAR16 *OutputString;
1427 UINTN TotalRowNum;
1428 UINTN CheckedNum;
1429 UINT16 GlyphWidth;
1430 UINT16 LineWidth;
1431 UINT16 MaxStringLen;
1432 UINT16 StringLen;
1433
1434 TotalRowNum = 0;
1435 CheckedNum = 0;
1436 GlyphWidth = 1;
1437 Index = 0;
1438 MaxStringLen = 0;
1439 StringLen = 0;
1440
1441 //
1442 // Set default help string width.
1443 //
1444 LineWidth = (UINT16) (gHelpBlockWidth - 1);
1445
1446 //
1447 // Get row number of the String.
1448 //
1449 while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
1450 if (StringLen > MaxStringLen) {
1451 MaxStringLen = StringLen;
1452 }
1453
1454 TotalRowNum ++;
1455 FreePool (OutputString);
1456 }
1457 *EachLineWidth = MaxStringLen;
1458
1459 *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));
1460 ASSERT (*FormattedString != NULL);
1461
1462 //
1463 // Generate formatted help string array.
1464 //
1465 GlyphWidth = 1;
1466 Index = 0;
1467 while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
1468 CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));
1469 CheckedNum ++;
1470 FreePool (OutputString);
1471 }
1472
1473 return TotalRowNum;
1474 }