VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c@ 77662

Last change on this file since 77662 was 77662, checked in by vboxsync, 6 years ago

EFI: First step in UDK2018 merge. Does not build yet.

  • Property svn:eol-style set to native
File size: 40.0 KB
Line 
1/** @file
2Implementation for handling the User Interface option processing.
3
4
5Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution. The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT 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**/
29VOID
30NewStrCat (
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**/
61UINT64
62HiiValueToUINT64 (
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**/
115BOOLEAN
116IsTypeInBuffer (
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**/
141BOOLEAN
142IsTypeInUINT64 (
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**/
170VOID
171GetBufAndLenForValue (
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**/
219EFI_STATUS
220CompareHiiValue (
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**/
318DISPLAY_QUESTION_OPTION *
319ValueToOption (
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**/
358UINT64
359GetArrayData (
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**/
404VOID
405SetArrayData (
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**/
449BOOLEAN
450FindArrayData (
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**/
513EFI_STATUS
514PrintFormattedNumber (
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**/
588VOID
589CreateSharedPopUp (
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**/
693VOID
694EFIAPI
695CreateMultiStringPopUp (
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**/
717VOID
718EFIAPI
719EmptyEventProcess (
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**/
733VOID
734EFIAPI
735RefreshTimeOutProcess (
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**/
763VOID
764PasswordInvalid (
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**/
787EFI_STATUS
788PasswordProcess (
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**/
930EFI_STATUS
931ProcessOptions (
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**/
1413UINTN
1414ProcessHelpString (
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}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette