EFI_STATUS ProcessOptions ( IN UI_MENU_SELECTION *Selection, IN UI_MENU_OPTION *MenuOption, IN BOOLEAN Selected, OUT CHAR16 **OptionString ) /*++ Routine Description: Process a Question's Option (whether selected or un-selected). Arguments: Selection - Pointer to UI_MENU_SELECTION. MenuOption - The MenuOption for this Question. Selected - TRUE: if Question is selected. OptionString - Pointer of the Option String to be displayed. Returns: EFI_SUCCESS - Question Option process success. Other - Question Option process fail. --*/ { EFI_STATUS Status; CHAR16 *StringPtr; CHAR16 *TempString; UINTN Index; FORM_BROWSER_STATEMENT *Question; CHAR16 FormattedNumber[21]; UINT16 Number; CHAR16 Character[2]; EFI_INPUT_KEY Key; UINTN BufferSize; QUESTION_OPTION *OneOfOption; EFI_LIST_ENTRY *Link; EFI_HII_VALUE HiiValue; EFI_HII_VALUE *QuestionValue; BOOLEAN Suppress; UINT16 Minimum; UINT16 Maximum; QUESTION_OPTION *Option; UINTN Index2; UINT8 *ValueArray; UINT8 ValueType; Status = EFI_SUCCESS; StringPtr = NULL; Character[1] = L'\0'; *OptionString = NULL; EfiZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow; Question = MenuOption->ThisTag; QuestionValue = &Question->HiiValue; Minimum = (UINT16) Question->Minimum; Maximum = (UINT16) Question->Maximum; ValueArray = Question->BufferValue; ValueType = Question->ValueType; switch (Question->Operand) { case EFI_IFR_ORDERED_LIST_OP: // // Check whether there are Options of this OrderedList // if (IsListEmpty (&Question->OptionListHead)) { break; } // // Initialize Option value array // if (GetArrayData (ValueArray, ValueType, 0) == 0) { GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0); } if (Selected) { // // Go ask for input // Status = GetSelectionInputPopUp (Selection, MenuOption); } else { // // We now know how many strings we will have, so we can allocate the // space required for the array or strings. // *OptionString = EfiLibAllocateZeroPool (Question->MaxContainers * BufferSize); ASSERT (*OptionString); HiiValue.Type = ValueType; HiiValue.Value.u64 = 0; for (Index = 0; Index < Question->MaxContainers; Index++) { HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index); if (HiiValue.Value.u64 == 0) { // // Values for the options in ordered lists should never be a 0 // break; } OneOfOption = ValueToOption (Question, &HiiValue); if (OneOfOption == NULL) { // // Show error message // do { CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); // // The initial value of the orderedlist is invalid, force to be valid value // Link = GetFirstNode (&Question->OptionListHead); Index2 = 0; while (!IsNull (&Question->OptionListHead, Link) && Index2 < Question->MaxContainers) { Option = QUESTION_OPTION_FROM_LINK (Link); SetArrayData (ValueArray, ValueType, Index2, Option->Value.Value.u64); Index2++; Link = GetNextNode (&Question->OptionListHead, Link); } SetArrayData (ValueArray, ValueType, Index2, 0); Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); gBS->FreePool (*OptionString); *OptionString = NULL; return EFI_NOT_FOUND; } Suppress = FALSE; if ((OneOfOption->SuppressExpression != NULL) && (OneOfOption->SuppressExpression->Result.Value.b)) { // // This option is suppressed // Suppress = TRUE; } if (!Suppress) { Character[0] = LEFT_ONEOF_DELIMITER; NewStrCat (OptionString[0], Character); StringPtr = GetToken (OneOfOption->Text, Selection->Handle); NewStrCat (OptionString[0], StringPtr); Character[0] = RIGHT_ONEOF_DELIMITER; NewStrCat (OptionString[0], Character); Character[0] = CHAR_CARRIAGE_RETURN; NewStrCat (OptionString[0], Character); gBS->FreePool (StringPtr); } } } break; case EFI_IFR_ONE_OF_OP: // // Check whether there are Options of this OneOf // if (IsListEmpty (&Question->OptionListHead)) { break; } if (Selected) { // // Go ask for input // Status = GetSelectionInputPopUp (Selection, MenuOption); } else { *OptionString = EfiLibAllocateZeroPool (BufferSize); ASSERT (*OptionString); OneOfOption = ValueToOption (Question, QuestionValue); if (OneOfOption == NULL) { // // Show error message // do { CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); // // Force the Question value to be valid // Link = GetFirstNode (&Question->OptionListHead); while (!IsNull (&Question->OptionListHead, Link)) { Option = QUESTION_OPTION_FROM_LINK (Link); if ((Option->SuppressExpression == NULL) || !Option->SuppressExpression->Result.Value.b) { EfiCopyMem (QuestionValue, &Option->Value, sizeof (EFI_HII_VALUE)); SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); break; } Link = GetNextNode (&Question->OptionListHead, Link); } gBS->FreePool (*OptionString); *OptionString = NULL; return EFI_NOT_FOUND; } if ((OneOfOption->SuppressExpression != NULL) && (OneOfOption->SuppressExpression->Result.Value.b)) { // // This option is suppressed // Suppress = TRUE; } else { Suppress = FALSE; } if (Suppress) { // // Current selected option happen to be suppressed, // enforce to select on a non-suppressed option // Link = GetFirstNode (&Question->OptionListHead); while (!IsNull (&Question->OptionListHead, Link)) { OneOfOption = QUESTION_OPTION_FROM_LINK (Link); if ((OneOfOption->SuppressExpression == NULL) || !OneOfOption->SuppressExpression->Result.Value.b) { Suppress = FALSE; EfiCopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE)); SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); break; } Link = GetNextNode (&Question->OptionListHead, Link); } } if (!Suppress) { Character[0] = LEFT_ONEOF_DELIMITER; NewStrCat (OptionString[0], Character); StringPtr = GetToken (OneOfOption->Text, Selection->Handle); NewStrCat (OptionString[0], StringPtr); Character[0] = RIGHT_ONEOF_DELIMITER; NewStrCat (OptionString[0], Character); gBS->FreePool (StringPtr); } } break; case EFI_IFR_CHECKBOX_OP: *OptionString = EfiLibAllocateZeroPool (BufferSize); ASSERT (*OptionString); *OptionString[0] = LEFT_CHECKBOX_DELIMITER; if (Selected) { // // Since this is a BOOLEAN operation, flip it upon selection // QuestionValue->Value.b = QuestionValue->Value.b ? FALSE : TRUE; // // Perform inconsistent check // Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); if (EFI_ERROR (Status)) { // // Inconsistent check fail, restore Question Value // QuestionValue->Value.b = QuestionValue->Value.b ? FALSE : TRUE; gBS->FreePool (*OptionString); *OptionString = NULL; return Status; } // // Save Question value // Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); } if (QuestionValue->Value.b) { *(OptionString[0] + 1) = CHECK_ON; } else { *(OptionString[0] + 1) = CHECK_OFF; } *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER; break; case EFI_IFR_NUMERIC_OP: if (Selected) { // // Go ask for input // Status = GetNumericInput (Selection, MenuOption); } else { *OptionString = EfiLibAllocateZeroPool (BufferSize); ASSERT (*OptionString); *OptionString[0] = LEFT_NUMERIC_DELIMITER; // // Formatted print // PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); Number = (UINT16) GetStringWidth (FormattedNumber); EfiCopyMem (OptionString[0] + 1, FormattedNumber, Number); *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER; } break; case EFI_IFR_DATE_OP: if (Selected) { // // This is similar to numerics // Status = GetNumericInput (Selection, MenuOption); } else { *OptionString = EfiLibAllocateZeroPool (BufferSize); ASSERT (*OptionString); switch (MenuOption->Sequence) { case 0: *OptionString[0] = LEFT_NUMERIC_DELIMITER; SPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", (UINTN) QuestionValue->Value.date.Month); *(OptionString[0] + 3) = DATE_SEPARATOR; break; case 1: SetUnicodeMem (OptionString[0], 4, L' '); SPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", (UINTN) QuestionValue->Value.date.Day); *(OptionString[0] + 6) = DATE_SEPARATOR; break; case 2: SetUnicodeMem (OptionString[0], 7, L' '); SPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", (UINTN) QuestionValue->Value.date.Year); *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER; break; } } break; case EFI_IFR_TIME_OP: if (Selected) { // // This is similar to numerics // Status = GetNumericInput (Selection, MenuOption); } else { *OptionString = EfiLibAllocateZeroPool (BufferSize); ASSERT (*OptionString); switch (MenuOption->Sequence) { case 0: *OptionString[0] = LEFT_NUMERIC_DELIMITER; SPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", (UINTN) QuestionValue->Value.time.Hour); *(OptionString[0] + 3) = TIME_SEPARATOR; break; case 1: SetUnicodeMem (OptionString[0], 4, L' '); SPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", (UINTN) QuestionValue->Value.time.Minute); *(OptionString[0] + 6) = TIME_SEPARATOR; break; case 2: SetUnicodeMem (OptionString[0], 7, L' '); SPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", (UINTN) QuestionValue->Value.time.Second); *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER; break; } } break; case EFI_IFR_STRING_OP: if (Selected) { StringPtr = EfiLibAllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); ASSERT (StringPtr); Status = ReadString (MenuOption, gPromptForData, StringPtr); if (!EFI_ERROR (Status)) { EfiCopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); } gBS->FreePool (StringPtr); } else { *OptionString = EfiLibAllocateZeroPool (BufferSize); ASSERT (*OptionString); if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) { *(OptionString[0]) = '_'; } else { if ((Maximum * sizeof (CHAR16)) < BufferSize) { BufferSize = Maximum * sizeof (CHAR16); } EfiCopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize); } } break; case EFI_IFR_PASSWORD_OP: if (Selected) { StringPtr = EfiLibAllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); ASSERT (StringPtr); // // For interactive passwords, old password is validated by callback // if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { // // Use a NULL password to test whether old password is required // *StringPtr = 0; Status = PasswordCallback (Selection, MenuOption, StringPtr); if (Status == EFI_NOT_AVAILABLE_YET) { // // Callback request to terminate password input // gBS->FreePool (StringPtr); return EFI_SUCCESS; } if (EFI_ERROR (Status)) { // // Old password exist, ask user for the old password // Status = ReadString (MenuOption, gPromptForPassword, StringPtr); if (EFI_ERROR (Status)) { gBS->FreePool (StringPtr); return Status; } // // Check user input old password // Status = PasswordCallback (Selection, MenuOption, StringPtr); if (EFI_ERROR (Status)) { if (Status == EFI_NOT_READY) { // // Typed in old password incorrect // PasswordInvalid (); } else { Status = EFI_SUCCESS; } gBS->FreePool (StringPtr); return Status; } } } else { // // For non-interactive password, validate old password in local // if (*((CHAR16 *) Question->BufferValue) != 0) { // // There is something there! Prompt for password // Status = ReadString (MenuOption, gPromptForPassword, StringPtr); if (EFI_ERROR (Status)) { gBS->FreePool (StringPtr); return Status; } TempString = EfiLibAllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue); TempString[Maximum] = L'\0'; if (EfiStrCmp (StringPtr, TempString) != 0) { // // Typed in old password incorrect // PasswordInvalid (); gBS->FreePool (StringPtr); gBS->FreePool (TempString); return Status; } gBS->FreePool (TempString); } } // // Ask for new password // EfiZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr); if (EFI_ERROR (Status)) { // // Reset state machine for interactive password // if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { PasswordCallback (Selection, MenuOption, NULL); } gBS->FreePool (StringPtr); return Status; } // // Confirm new password // TempString = EfiLibAllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); ASSERT (TempString); Status = ReadString (MenuOption, gConfirmPassword, TempString); if (EFI_ERROR (Status)) { // // Reset state machine for interactive password // if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { PasswordCallback (Selection, MenuOption, NULL); } gBS->FreePool (StringPtr); gBS->FreePool (TempString); return Status; } // // Compare two typed-in new passwords // if (EfiStrCmp (StringPtr, TempString) == 0) { // // Two password match, send it to Configuration Driver // if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { PasswordCallback (Selection, MenuOption, StringPtr); } else { EfiCopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE); } } else { // // Reset state machine for interactive password // if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { PasswordCallback (Selection, MenuOption, NULL); } // // Two password mismatch, prompt error message // do { CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString); } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); } gBS->FreePool (TempString); gBS->FreePool (StringPtr); } break; default: break; } return Status; }
EFI_STATUS EfiLibAddUnicodeString ( IN CHAR8 *Language, IN CHAR8 *SupportedLanguages, IN OUT EFI_UNICODE_STRING_TABLE **UnicodeStringTable, IN CHAR16 *UnicodeString ) /*++ Routine Description: Add an translation to the dictionary if this language if supported. Arguments: Language - The name of language to translate to SupportedLanguages - Supported languages set UnicodeStringTable - Translation dictionary UnicodeString - The corresponding string for the language to be translated to Returns: EFI_INVALID_PARAMETER - Invalid parameter EFI_UNSUPPORTED - System not supported this language EFI_ALREADY_STARTED - Already has a translation item of this language EFI_OUT_OF_RESOURCES - No enough buffer to be allocated EFI_SUCCESS - String successfully translated --*/ { UINTN NumberOfEntries; EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable; EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable; UINTN UnicodeStringLength; // // Make sure the parameter are valid // if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) { return EFI_INVALID_PARAMETER; } // // If there are no supported languages, then a Unicode String can not be added // if (SupportedLanguages == NULL) { return EFI_UNSUPPORTED; } // // If the Unicode String is empty, then a Unicode String can not be added // if (UnicodeString[0] == 0) { return EFI_INVALID_PARAMETER; } // // Make sure Language is a member of SupportedLanguages // while (*SupportedLanguages != 0) { if (EfiLibCompareLanguage (Language, SupportedLanguages)) { // // Determine the size of the Unicode String Table by looking for a NULL Language entry // NumberOfEntries = 0; if (*UnicodeStringTable != NULL) { OldUnicodeStringTable = *UnicodeStringTable; while (OldUnicodeStringTable->Language != NULL) { if (EfiLibCompareLanguage (Language, OldUnicodeStringTable->Language)) { return EFI_ALREADY_STARTED; } OldUnicodeStringTable++; NumberOfEntries++; } } // // Allocate space for a new Unicode String Table. It must hold the current number of // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table // marker // NewUnicodeStringTable = EfiLibAllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE)); if (NewUnicodeStringTable == NULL) { return EFI_OUT_OF_RESOURCES; } // // If the current Unicode String Table contains any entries, then copy them to the // newly allocated Unicode String Table. // if (*UnicodeStringTable != NULL) { EfiCopyMem ( NewUnicodeStringTable, *UnicodeStringTable, NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE) ); } // // Allocate space for a copy of the Language specifier // NewUnicodeStringTable[NumberOfEntries].Language = EfiLibAllocateCopyPool (EfiAsciiStrLen(Language) + 1, Language); if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) { gBS->FreePool (NewUnicodeStringTable); return EFI_OUT_OF_RESOURCES; } // // Compute the length of the Unicode String // for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++) ; // // Allocate space for a copy of the Unicode String // NewUnicodeStringTable[NumberOfEntries].UnicodeString = EfiLibAllocateCopyPool ( (UnicodeStringLength + 1) * sizeof (CHAR16), UnicodeString ); if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) { gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language); gBS->FreePool (NewUnicodeStringTable); return EFI_OUT_OF_RESOURCES; } // // Mark the end of the Unicode String Table // NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL; NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL; // // Free the old Unicode String Table // if (*UnicodeStringTable != NULL) { gBS->FreePool (*UnicodeStringTable); } // // Point UnicodeStringTable at the newly allocated Unicode String Table // *UnicodeStringTable = NewUnicodeStringTable; return EFI_SUCCESS; } SupportedLanguages = NextSupportedLanguage(SupportedLanguages); } return EFI_UNSUPPORTED; }