From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../MdeModulePkg/Universal/HiiDatabaseDxe/String.c | 2085 ++++++++++++++++++++ 1 file changed, 2085 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/String.c (limited to 'roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/String.c') diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/String.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/String.c new file mode 100644 index 000000000..2c7ecfea4 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/String.c @@ -0,0 +1,2085 @@ +/** @file +Implementation for EFI_HII_STRING_PROTOCOL. + + +Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "HiiDatabase.h" + +CHAR16 mLanguageWindow[16] = { + 0x0000, 0x0080, 0x0100, 0x0300, + 0x2000, 0x2080, 0x2100, 0x3000, + 0x0080, 0x00C0, 0x0400, 0x0600, + 0x0900, 0x3040, 0x30A0, 0xFF00 +}; + + +/** + This function checks whether a global font info is referred by local + font info list or not. (i.e. HII_FONT_INFO is generated.) If not, create + a HII_FONT_INFO to refer it locally. + + This is a internal function. + + + @param Private Hii database private structure. + @param StringPackage HII string package instance. + @param FontId Font identifer, which must be unique within the string package. + @param DuplicateEnable If true, duplicate HII_FONT_INFO which refers to + the same EFI_FONT_INFO is permitted. Otherwise it + is not allowed. + @param GlobalFontInfo Input a global font info which specify a + EFI_FONT_INFO. + @param LocalFontInfo Output a local font info which refers to a + EFI_FONT_INFO. + + @retval TRUE Already referred before calling this function. + @retval FALSE Not referred before calling this function. + +**/ +BOOLEAN +ReferFontInfoLocally ( + IN HII_DATABASE_PRIVATE_DATA *Private, + IN HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN UINT8 FontId, + IN BOOLEAN DuplicateEnable, + IN HII_GLOBAL_FONT_INFO *GlobalFontInfo, + OUT HII_FONT_INFO **LocalFontInfo + ) +{ + HII_FONT_INFO *LocalFont; + LIST_ENTRY *Link; + + ASSERT (Private != NULL && StringPackage != NULL && GlobalFontInfo != NULL && LocalFontInfo != NULL); + + if (!DuplicateEnable) { + for (Link = StringPackage->FontInfoList.ForwardLink; + Link != &StringPackage->FontInfoList; + Link = Link->ForwardLink + ) { + LocalFont = CR (Link, HII_FONT_INFO, Entry, HII_FONT_INFO_SIGNATURE); + if (LocalFont->GlobalEntry == &GlobalFontInfo->Entry) { + // + // Already referred by local font info list, return directly. + // + *LocalFontInfo = LocalFont; + return TRUE; + } + } + } + // FontId identifies EFI_FONT_INFO in local string package uniquely. + // GlobalEntry points to a HII_GLOBAL_FONT_INFO which identifies + // EFI_FONT_INFO uniquely in whole hii database. + // + LocalFont = (HII_FONT_INFO *) AllocateZeroPool (sizeof (HII_FONT_INFO)); + ASSERT (LocalFont != NULL); + + LocalFont->Signature = HII_FONT_INFO_SIGNATURE; + LocalFont->FontId = FontId; + LocalFont->GlobalEntry = &GlobalFontInfo->Entry; + InsertTailList (&StringPackage->FontInfoList, &LocalFont->Entry); + + *LocalFontInfo = LocalFont; + return FALSE; +} + + +/** + Convert Ascii string text to unicode string test. + + This is a internal function. + + + @param StringDest Buffer to store the string text. If it is NULL, + only the size will be returned. + @param StringSrc Points to current null-terminated string. + @param BufferSize Length of the buffer. + + @retval EFI_SUCCESS The string text was outputted successfully. + @retval EFI_BUFFER_TOO_SMALL Buffer is insufficient to store the found string + text. BufferSize is updated to the required buffer + size. + +**/ +EFI_STATUS +ConvertToUnicodeText ( + OUT EFI_STRING StringDest, + IN CHAR8 *StringSrc, + IN OUT UINTN *BufferSize + ) +{ + UINTN StringSize; + UINTN Index; + + ASSERT (StringSrc != NULL && BufferSize != NULL); + + StringSize = AsciiStrSize (StringSrc) * 2; + if (*BufferSize < StringSize || StringDest == NULL) { + *BufferSize = StringSize; + return EFI_BUFFER_TOO_SMALL; + } + + for (Index = 0; Index < AsciiStrLen (StringSrc); Index++) { + StringDest[Index] = (CHAR16) StringSrc[Index]; + } + + StringDest[Index] = 0; + return EFI_SUCCESS; +} + + +/** + Calculate the size of StringSrc and output it. If StringDest is not NULL, + copy string text from src to dest. + + This is a internal function. + + @param StringDest Buffer to store the string text. If it is NULL, + only the size will be returned. + @param StringSrc Points to current null-terminated string. + @param BufferSize Length of the buffer. + + @retval EFI_SUCCESS The string text was outputted successfully. + @retval EFI_BUFFER_TOO_SMALL Buffer is insufficient to store the found string + text. BufferSize is updated to the required buffer + size. + +**/ +EFI_STATUS +GetUnicodeStringTextOrSize ( + OUT EFI_STRING StringDest, OPTIONAL + IN UINT8 *StringSrc, + IN OUT UINTN *BufferSize + ) +{ + UINTN StringSize; + UINT8 *StringPtr; + + ASSERT (StringSrc != NULL && BufferSize != NULL); + + StringSize = sizeof (CHAR16); + StringPtr = StringSrc; + while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) { + StringSize += sizeof (CHAR16); + StringPtr += sizeof (CHAR16); + } + + if (*BufferSize < StringSize) { + *BufferSize = StringSize; + return EFI_BUFFER_TOO_SMALL; + } + if (StringDest != NULL) { + CopyMem (StringDest, StringSrc, StringSize); + } + + *BufferSize = StringSize; + return EFI_SUCCESS; +} + + +/** + Copy string font info to a buffer. + + This is a internal function. + + @param StringPackage Hii string package instance. + @param FontId Font identifier which is unique in a string + package. + @param StringFontInfo Buffer to record the output font info. It's + caller's responsibility to free this buffer. + + @retval EFI_SUCCESS The string font is outputted successfully. + @retval EFI_NOT_FOUND The specified font id does not exist. + +**/ +EFI_STATUS +GetStringFontInfo ( + IN HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN UINT8 FontId, + OUT EFI_FONT_INFO **StringFontInfo + ) +{ + LIST_ENTRY *Link; + HII_FONT_INFO *FontInfo; + HII_GLOBAL_FONT_INFO *GlobalFont; + + ASSERT (StringFontInfo != NULL && StringPackage != NULL); + + for (Link = StringPackage->FontInfoList.ForwardLink; Link != &StringPackage->FontInfoList; Link = Link->ForwardLink) { + FontInfo = CR (Link, HII_FONT_INFO, Entry, HII_FONT_INFO_SIGNATURE); + if (FontInfo->FontId == FontId) { + GlobalFont = CR (FontInfo->GlobalEntry, HII_GLOBAL_FONT_INFO, Entry, HII_GLOBAL_FONT_INFO_SIGNATURE); + *StringFontInfo = (EFI_FONT_INFO *) AllocateZeroPool (GlobalFont->FontInfoSize); + if (*StringFontInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (*StringFontInfo, GlobalFont->FontInfo, GlobalFont->FontInfoSize); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +/** + Parse all string blocks to find a String block specified by StringId. + If StringId = (EFI_STRING_ID) (-1), find out all EFI_HII_SIBT_FONT blocks + within this string package and backup its information. If LastStringId is + specified, the string id of last string block will also be output. + If StringId = 0, output the string id of last string block (EFI_HII_SIBT_STRING). + + @param Private Hii database private structure. + @param StringPackage Hii string package instance. + @param StringId The string's id, which is unique within + PackageList. + @param BlockType Output the block type of found string block. + @param StringBlockAddr Output the block address of found string block. + @param StringTextOffset Offset, relative to the found block address, of + the string text information. + @param LastStringId Output the last string id when StringId = 0 or StringId = -1. + @param StartStringId The first id in the skip block which StringId in the block. + + @retval EFI_SUCCESS The string text and font is retrieved + successfully. + @retval EFI_NOT_FOUND The specified text or font info can not be found + out. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. + +**/ +EFI_STATUS +FindStringBlock ( + IN HII_DATABASE_PRIVATE_DATA *Private, + IN HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN EFI_STRING_ID StringId, + OUT UINT8 *BlockType, OPTIONAL + OUT UINT8 **StringBlockAddr, OPTIONAL + OUT UINTN *StringTextOffset, OPTIONAL + OUT EFI_STRING_ID *LastStringId, OPTIONAL + OUT EFI_STRING_ID *StartStringId OPTIONAL + ) +{ + UINT8 *BlockHdr; + EFI_STRING_ID CurrentStringId; + UINTN BlockSize; + UINTN Index; + UINT8 *StringTextPtr; + UINTN Offset; + HII_FONT_INFO *LocalFont; + EFI_FONT_INFO *FontInfo; + HII_GLOBAL_FONT_INFO *GlobalFont; + UINTN FontInfoSize; + UINT16 StringCount; + UINT16 SkipCount; + EFI_HII_FONT_STYLE FontStyle; + UINT16 FontSize; + UINT8 Length8; + EFI_HII_SIBT_EXT2_BLOCK Ext2; + UINT8 FontId; + UINT32 Length32; + UINTN StringSize; + CHAR16 Zero; + + ASSERT (StringPackage != NULL); + ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE); + + CurrentStringId = 1; + StringSize = 0; + + if (StringId != (EFI_STRING_ID) (-1) && StringId != 0) { + ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL); + if (StringId > StringPackage->MaxStringId) { + return EFI_NOT_FOUND; + } + } else { + ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE); + if (StringId == 0 && LastStringId != NULL) { + *LastStringId = StringPackage->MaxStringId; + return EFI_SUCCESS; + } + } + + ZeroMem (&Zero, sizeof (CHAR16)); + + // + // Parse the string blocks to get the string text and font. + // + BlockHdr = StringPackage->StringBlock; + BlockSize = 0; + Offset = 0; + while (*BlockHdr != EFI_HII_SIBT_END) { + switch (*BlockHdr) { + case EFI_HII_SIBT_STRING_SCSU: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_SCSU_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_SCSU: + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8)); + BlockSize += StringTextPtr - BlockHdr; + + for (Index = 0; Index < StringCount; Index++) { + BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); + if (CurrentStringId == StringId) { + ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL); + *BlockType = *BlockHdr; + *StringBlockAddr = BlockHdr; + *StringTextOffset = StringTextPtr - BlockHdr; + return EFI_SUCCESS; + } + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_SCSU_FONT: + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8)); + BlockSize += StringTextPtr - BlockHdr; + + for (Index = 0; Index < StringCount; Index++) { + BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); + if (CurrentStringId == StringId) { + ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL); + *BlockType = *BlockHdr; + *StringBlockAddr = BlockHdr; + *StringTextOffset = StringTextPtr - BlockHdr; + return EFI_SUCCESS; + } + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRING_UCS2: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + // + // Use StringSize to store the size of the specified string, including the NULL + // terminator. + // + GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize); + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + // + // Use StrSize to store the size of the specified string, including the NULL + // terminator. + // + GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize); + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_UCS2: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + for (Index = 0; Index < StringCount; Index++) { + GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize); + BlockSize += StringSize; + if (CurrentStringId == StringId) { + ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL); + *BlockType = *BlockHdr; + *StringBlockAddr = BlockHdr; + *StringTextOffset = StringTextPtr - BlockHdr; + return EFI_SUCCESS; + } + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + for (Index = 0; Index < StringCount; Index++) { + GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize); + BlockSize += StringSize; + if (CurrentStringId == StringId) { + ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL); + *BlockType = *BlockHdr; + *StringBlockAddr = BlockHdr; + *StringTextOffset = StringTextPtr - BlockHdr; + return EFI_SUCCESS; + } + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_DUPLICATE: + if (CurrentStringId == StringId) { + // + // Incoming StringId is an id of a duplicate string block. + // Update the StringId to be the previous string block. + // Go back to the header of string block to search. + // + CopyMem ( + &StringId, + BlockHdr + sizeof (EFI_HII_STRING_BLOCK), + sizeof (EFI_STRING_ID) + ); + ASSERT (StringId != CurrentStringId); + CurrentStringId = 1; + BlockSize = 0; + } else { + BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_SKIP1: + SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK))); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK); + break; + + case EFI_HII_SIBT_SKIP2: + CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); + break; + + case EFI_HII_SIBT_EXT1: + CopyMem ( + &Length8, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT8) + ); + BlockSize += Length8; + break; + + case EFI_HII_SIBT_EXT2: + CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK)); + if (Ext2.BlockType2 == EFI_HII_SIBT_FONT && StringId == (EFI_STRING_ID) (-1)) { + // + // Find the relationship between global font info and the font info of + // this EFI_HII_SIBT_FONT block then backup its information in local package. + // + BlockHdr += sizeof (EFI_HII_SIBT_EXT2_BLOCK); + CopyMem (&FontId, BlockHdr, sizeof (UINT8)); + BlockHdr ++; + CopyMem (&FontSize, BlockHdr, sizeof (UINT16)); + BlockHdr += sizeof (UINT16); + CopyMem (&FontStyle, BlockHdr, sizeof (EFI_HII_FONT_STYLE)); + BlockHdr += sizeof (EFI_HII_FONT_STYLE); + GetUnicodeStringTextOrSize (NULL, BlockHdr, &StringSize); + + FontInfoSize = sizeof (EFI_FONT_INFO) - sizeof (CHAR16) + StringSize; + FontInfo = (EFI_FONT_INFO *) AllocateZeroPool (FontInfoSize); + if (FontInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + FontInfo->FontStyle = FontStyle; + FontInfo->FontSize = FontSize; + CopyMem (FontInfo->FontName, BlockHdr, StringSize); + + // + // If find the corresponding global font info, save the relationship. + // Otherwise ignore this EFI_HII_SIBT_FONT block. + // + if (IsFontInfoExisted (Private, FontInfo, NULL, NULL, &GlobalFont)) { + ReferFontInfoLocally (Private, StringPackage, FontId, TRUE, GlobalFont, &LocalFont); + } + + // + // Since string package tool set FontId initially to 0 and increases it + // progressively by one, StringPackage->FondId always represents an unique + // and available FontId. + // + StringPackage->FontId++; + + FreePool (FontInfo); + } + + BlockSize += Ext2.Length; + + break; + + case EFI_HII_SIBT_EXT4: + CopyMem ( + &Length32, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT32) + ); + + BlockSize += Length32; + break; + + default: + break; + } + + if (StringId > 0 && StringId != (EFI_STRING_ID)(-1)) { + ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL); + *BlockType = *BlockHdr; + *StringBlockAddr = BlockHdr; + *StringTextOffset = Offset; + + if (StringId == CurrentStringId - 1) { + // + // if only one skip item, return EFI_NOT_FOUND. + // + if(*BlockType == EFI_HII_SIBT_SKIP2 || *BlockType == EFI_HII_SIBT_SKIP1) { + return EFI_NOT_FOUND; + } else { + return EFI_SUCCESS; + } + } + + if (StringId < CurrentStringId - 1) { + return EFI_NOT_FOUND; + } + } + BlockHdr = StringPackage->StringBlock + BlockSize; + if (StartStringId != NULL) { + *StartStringId = CurrentStringId; + } + } + + // + // Get last string ID + // + if (StringId == (EFI_STRING_ID) (-1) && LastStringId != NULL) { + *LastStringId = (EFI_STRING_ID) (CurrentStringId - 1); + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + + +/** + Parse all string blocks to get a string specified by StringId. + + This is a internal function. + + @param Private Hii database private structure. + @param StringPackage Hii string package instance. + @param StringId The string's id, which is unique within + PackageList. + @param String Points to retrieved null-terminated string. + @param StringSize On entry, points to the size of the buffer pointed + to by String, in bytes. On return, points to the + length of the string, in bytes. + @param StringFontInfo If not NULL, allocate a buffer to record the + output font info. It's caller's responsibility to + free this buffer. + + @retval EFI_SUCCESS The string text and font is retrieved + successfully. + @retval EFI_NOT_FOUND The specified text or font info can not be found + out. + @retval EFI_BUFFER_TOO_SMALL The buffer specified by StringSize is too small to + hold the string. + +**/ +EFI_STATUS +GetStringWorker ( + IN HII_DATABASE_PRIVATE_DATA *Private, + IN HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN EFI_STRING_ID StringId, + OUT EFI_STRING String, + IN OUT UINTN *StringSize, OPTIONAL + OUT EFI_FONT_INFO **StringFontInfo OPTIONAL + ) +{ + UINT8 *StringTextPtr; + UINT8 BlockType; + UINT8 *StringBlockAddr; + UINTN StringTextOffset; + EFI_STATUS Status; + UINT8 FontId; + + ASSERT (StringPackage != NULL); + ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE); + + // + // Find the specified string block + // + Status = FindStringBlock ( + Private, + StringPackage, + StringId, + &BlockType, + &StringBlockAddr, + &StringTextOffset, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (StringSize == NULL) { + // + // String text buffer is not requested + // + return EFI_SUCCESS; + } + + // + // Get the string text. + // + StringTextPtr = StringBlockAddr + StringTextOffset; + switch (BlockType) { + case EFI_HII_SIBT_STRING_SCSU: + case EFI_HII_SIBT_STRING_SCSU_FONT: + case EFI_HII_SIBT_STRINGS_SCSU: + case EFI_HII_SIBT_STRINGS_SCSU_FONT: + Status = ConvertToUnicodeText (String, (CHAR8 *) StringTextPtr, StringSize); + break; + case EFI_HII_SIBT_STRING_UCS2: + case EFI_HII_SIBT_STRING_UCS2_FONT: + case EFI_HII_SIBT_STRINGS_UCS2: + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + Status = GetUnicodeStringTextOrSize (String, StringTextPtr, StringSize); + break; + default: + return EFI_NOT_FOUND; + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the string font. The FontId 0 is the default font for those string blocks which + // do not specify a font identifier. If default font is not specified, return NULL. + // + if (StringFontInfo != NULL) { + switch (BlockType) { + case EFI_HII_SIBT_STRING_SCSU_FONT: + case EFI_HII_SIBT_STRINGS_SCSU_FONT: + case EFI_HII_SIBT_STRING_UCS2_FONT: + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + FontId = *(StringBlockAddr + sizeof (EFI_HII_STRING_BLOCK)); + break; + default: + FontId = 0; + } + Status = GetStringFontInfo (StringPackage, FontId, StringFontInfo); + if (Status == EFI_NOT_FOUND) { + *StringFontInfo = NULL; + } + } + + return EFI_SUCCESS; +} + +/** + If GetStringBlock find the StringId's string is not saved in the exist string block, + this function will create the UCS2 string block to save the string; also split the + skip block into two or one skip block. + + This is a internal function. + + @param StringPackage Hii string package instance. + @param StartStringId The first id in the skip block which StringId in the block. + @param StringId The string's id, which is unique within + PackageList. + @param BlockType Output the block type of found string block. + @param StringBlockAddr Output the block address of found string block. + @param FontBlock whether this string block has font info. + + @retval EFI_SUCCESS The string font is outputted successfully. + @retval EFI_OUT_OF_RESOURCES NO resource for the memory to save the new string block. + +**/ +EFI_STATUS +InsertLackStringBlock ( + IN OUT HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN EFI_STRING_ID StartStringId, + IN EFI_STRING_ID StringId, + IN OUT UINT8 *BlockType, + IN OUT UINT8 **StringBlockAddr, + IN BOOLEAN FontBlock + ) +{ + UINT8 *BlockPtr; + UINT8 *StringBlock; + UINT32 SkipLen; + UINT32 OldBlockSize; + UINT32 NewBlockSize; + UINT32 FrontSkipNum; + UINT32 NewUCSBlockLen; + UINT8 *OldStringAddr; + UINT32 IdCount; + + FrontSkipNum = 0; + SkipLen = 0; + OldStringAddr = *StringBlockAddr; + + ASSERT (*BlockType == EFI_HII_SIBT_SKIP1 || *BlockType == EFI_HII_SIBT_SKIP2); + // + // Old skip block size. + // + if (*BlockType == EFI_HII_SIBT_SKIP1) { + SkipLen = sizeof (EFI_HII_SIBT_SKIP1_BLOCK); + IdCount = *(UINT8*)(OldStringAddr + sizeof (EFI_HII_STRING_BLOCK)); + } else { + SkipLen = sizeof (EFI_HII_SIBT_SKIP2_BLOCK); + IdCount = *(UINT16*)(OldStringAddr + sizeof (EFI_HII_STRING_BLOCK)); + } + + // + // New create UCS or UCS2 block size. + // + if (FontBlock) { + NewUCSBlockLen = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK); + } else { + NewUCSBlockLen = sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK); + } + + OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize; + + if (StartStringId == StringId) { + // + // New block + [Skip block] + // + if (IdCount > 1) { + NewBlockSize = OldBlockSize + NewUCSBlockLen; + } else { + NewBlockSize = OldBlockSize + NewUCSBlockLen - SkipLen; + } + } else if (StartStringId + IdCount - 1 == StringId){ + // + // Skip block + New block + // + NewBlockSize = OldBlockSize + NewUCSBlockLen; + FrontSkipNum = StringId - StartStringId; + } else { + // + // Skip block + New block + [Skip block] + // + NewBlockSize = OldBlockSize + NewUCSBlockLen + SkipLen; + FrontSkipNum = StringId - StartStringId; + } + + StringBlock = (UINT8 *) AllocateZeroPool (NewBlockSize); + if (StringBlock == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy old block in front of skip block. + // + CopyMem (StringBlock, StringPackage->StringBlock, OldStringAddr - StringPackage->StringBlock); + BlockPtr = StringBlock + (OldStringAddr - StringPackage->StringBlock); + + if (FrontSkipNum > 0) { + *BlockPtr = *BlockType; + if (*BlockType == EFI_HII_SIBT_SKIP1) { + *(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT8) FrontSkipNum; + } else { + *(UINT16 *)(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT16) FrontSkipNum; + } + BlockPtr += SkipLen; + } + + // + // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK + // + *StringBlockAddr = BlockPtr; + if (FontBlock) { + *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT; + } else { + *BlockPtr = EFI_HII_SIBT_STRING_UCS2; + } + BlockPtr += NewUCSBlockLen; + + if (IdCount > FrontSkipNum + 1) { + *BlockPtr = *BlockType; + if (*BlockType == EFI_HII_SIBT_SKIP1) { + *(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT8) (IdCount - FrontSkipNum - 1); + } else { + *(UINT16 *)(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT16) (IdCount - FrontSkipNum - 1); + } + BlockPtr += SkipLen; + } + + // + // Append a EFI_HII_SIBT_END block to the end. + // + CopyMem (BlockPtr, OldStringAddr + SkipLen, OldBlockSize - (OldStringAddr - StringPackage->StringBlock) - SkipLen); + + if (FontBlock) { + *BlockType = EFI_HII_SIBT_STRING_UCS2_FONT; + } else { + *BlockType = EFI_HII_SIBT_STRING_UCS2; + } + FreePool (StringPackage->StringBlock); + StringPackage->StringBlock = StringBlock; + StringPackage->StringPkgHdr->Header.Length += NewBlockSize - OldBlockSize; + + return EFI_SUCCESS; +} + +/** + Parse all string blocks to set a String specified by StringId. + + This is a internal function. + + @param Private HII database driver private structure. + @param StringPackage HII string package instance. + @param StringId The string's id, which is unique within + PackageList. + @param String Points to the new null-terminated string. + @param StringFontInfo Points to the input font info. + + @retval EFI_SUCCESS The string was updated successfully. + @retval EFI_NOT_FOUND The string specified by StringId is not in the + database. + @retval EFI_INVALID_PARAMETER The String or Language was NULL. + @retval EFI_INVALID_PARAMETER The specified StringFontInfo does not exist in + current database. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. + +**/ +EFI_STATUS +SetStringWorker ( + IN HII_DATABASE_PRIVATE_DATA *Private, + IN OUT HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN EFI_STRING_ID StringId, + IN EFI_STRING String, + IN EFI_FONT_INFO *StringFontInfo OPTIONAL + ) +{ + UINT8 *StringTextPtr; + UINT8 BlockType; + UINT8 *StringBlockAddr; + UINTN StringTextOffset; + EFI_STATUS Status; + UINT8 *Block; + UINT8 *BlockPtr; + UINTN BlockSize; + UINTN OldBlockSize; + HII_FONT_INFO *LocalFont; + HII_GLOBAL_FONT_INFO *GlobalFont; + BOOLEAN Referred; + EFI_HII_SIBT_EXT2_BLOCK Ext2; + UINTN StringSize; + UINTN TmpSize; + EFI_STRING_ID StartStringId; + + StartStringId = 0; + StringSize = 0; + ASSERT (Private != NULL && StringPackage != NULL && String != NULL); + ASSERT (Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE); + // + // Find the specified string block + // + Status = FindStringBlock ( + Private, + StringPackage, + StringId, + &BlockType, + &StringBlockAddr, + &StringTextOffset, + NULL, + &StartStringId + ); + if (EFI_ERROR (Status) && (BlockType == EFI_HII_SIBT_SKIP1 || BlockType == EFI_HII_SIBT_SKIP2)) { + Status = InsertLackStringBlock(StringPackage, + StartStringId, + StringId, + &BlockType, + &StringBlockAddr, + (BOOLEAN)(StringFontInfo != NULL) + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (StringFontInfo != NULL) { + StringTextOffset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16); + } else { + StringTextOffset = sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) - sizeof (CHAR16); + } + } + + LocalFont = NULL; + GlobalFont = NULL; + Referred = FALSE; + + // + // The input StringFontInfo should exist in current database if specified. + // + if (StringFontInfo != NULL) { + if (!IsFontInfoExisted (Private, StringFontInfo, NULL, NULL, &GlobalFont)) { + return EFI_INVALID_PARAMETER; + } else { + Referred = ReferFontInfoLocally ( + Private, + StringPackage, + StringPackage->FontId, + FALSE, + GlobalFont, + &LocalFont + ); + if (!Referred) { + StringPackage->FontId++; + } + } + // + // Update the FontId of the specified string block to input font info. + // + switch (BlockType) { + case EFI_HII_SIBT_STRING_SCSU_FONT: + case EFI_HII_SIBT_STRINGS_SCSU_FONT: + case EFI_HII_SIBT_STRING_UCS2_FONT: + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + *(StringBlockAddr + sizeof (EFI_HII_STRING_BLOCK)) = LocalFont->FontId; + break; + default: + // + // When modify the font info of these blocks, the block type should be updated + // to contain font info thus the whole structure should be revised. + // It is recommended to use tool to modify the block type not in the code. + // + return EFI_UNSUPPORTED; + } + } + + OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize; + + // + // Set the string text and font. + // + StringTextPtr = StringBlockAddr + StringTextOffset; + switch (BlockType) { + case EFI_HII_SIBT_STRING_SCSU: + case EFI_HII_SIBT_STRING_SCSU_FONT: + case EFI_HII_SIBT_STRINGS_SCSU: + case EFI_HII_SIBT_STRINGS_SCSU_FONT: + BlockSize = OldBlockSize + StrLen (String); + BlockSize -= AsciiStrSize ((CHAR8 *) StringTextPtr); + Block = AllocateZeroPool (BlockSize); + if (Block == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (Block, StringPackage->StringBlock, StringTextPtr - StringPackage->StringBlock); + BlockPtr = Block + (StringTextPtr - StringPackage->StringBlock); + + while (*String != 0) { + *BlockPtr++ = (CHAR8) *String++; + } + *BlockPtr++ = 0; + + + TmpSize = OldBlockSize - (StringTextPtr - StringPackage->StringBlock) - AsciiStrSize ((CHAR8 *) StringTextPtr); + CopyMem ( + BlockPtr, + StringTextPtr + AsciiStrSize ((CHAR8 *)StringTextPtr), + TmpSize + ); + + ZeroMem (StringPackage->StringBlock, OldBlockSize); + FreePool (StringPackage->StringBlock); + StringPackage->StringBlock = Block; + StringPackage->StringPkgHdr->Header.Length += (UINT32) (BlockSize - OldBlockSize); + break; + + case EFI_HII_SIBT_STRING_UCS2: + case EFI_HII_SIBT_STRING_UCS2_FONT: + case EFI_HII_SIBT_STRINGS_UCS2: + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + // + // Use StrSize to store the size of the specified string, including the NULL + // terminator. + // + GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize); + + BlockSize = OldBlockSize + StrSize (String) - StringSize; + Block = AllocateZeroPool (BlockSize); + if (Block == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (Block, StringPackage->StringBlock, StringTextPtr - StringPackage->StringBlock); + BlockPtr = Block + (StringTextPtr - StringPackage->StringBlock); + + CopyMem (BlockPtr, String, StrSize (String)); + BlockPtr += StrSize (String); + + CopyMem ( + BlockPtr, + StringTextPtr + StringSize, + OldBlockSize - (StringTextPtr - StringPackage->StringBlock) - StringSize + ); + + ZeroMem (StringPackage->StringBlock, OldBlockSize); + FreePool (StringPackage->StringBlock); + StringPackage->StringBlock = Block; + StringPackage->StringPkgHdr->Header.Length += (UINT32) (BlockSize - OldBlockSize); + break; + + default: + return EFI_NOT_FOUND; + } + + // + // Insert a new EFI_HII_SIBT_FONT_BLOCK to the header of string block, if incoming + // StringFontInfo does not exist in current string package. + // + // This new block does not impact on the value of StringId. + // + // + if (StringFontInfo == NULL || Referred) { + return EFI_SUCCESS; + } + + OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize; + BlockSize = OldBlockSize + sizeof (EFI_HII_SIBT_FONT_BLOCK) - sizeof (CHAR16) + + StrSize (GlobalFont->FontInfo->FontName); + + Block = AllocateZeroPool (BlockSize); + if (Block == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + BlockPtr = Block; + Ext2.Header.BlockType = EFI_HII_SIBT_EXT2; + Ext2.BlockType2 = EFI_HII_SIBT_FONT; + Ext2.Length = (UINT16) (BlockSize - OldBlockSize); + CopyMem (BlockPtr, &Ext2, sizeof (EFI_HII_SIBT_EXT2_BLOCK)); + BlockPtr += sizeof (EFI_HII_SIBT_EXT2_BLOCK); + + *BlockPtr = LocalFont->FontId; + BlockPtr ++; + CopyMem (BlockPtr, &GlobalFont->FontInfo->FontSize, sizeof (UINT16)); + BlockPtr += sizeof (UINT16); + CopyMem (BlockPtr, &GlobalFont->FontInfo->FontStyle, sizeof (UINT32)); + BlockPtr += sizeof (UINT32); + CopyMem ( + BlockPtr, + GlobalFont->FontInfo->FontName, + StrSize (GlobalFont->FontInfo->FontName) + ); + BlockPtr += StrSize (GlobalFont->FontInfo->FontName); + + CopyMem (BlockPtr, StringPackage->StringBlock, OldBlockSize); + + ZeroMem (StringPackage->StringBlock, OldBlockSize); + FreePool (StringPackage->StringBlock); + StringPackage->StringBlock = Block; + StringPackage->StringPkgHdr->Header.Length += Ext2.Length; + + return EFI_SUCCESS; + +} + + +/** + This function adds the string String to the group of strings owned by PackageList, with the + specified font information StringFontInfo and returns a new string id. + The new string identifier is guaranteed to be unique within the package list. + That new string identifier is reserved for all languages in the package list. + + + @param This A pointer to the EFI_HII_STRING_PROTOCOL instance. + @param PackageList Handle of the package list where this string will + be added. + @param StringId On return, contains the new strings id, which is + unique within PackageList. + @param Language Points to the language for the new string. + @param LanguageName Points to the printable language name to associate + with the passed in Language field.If LanguageName + is not NULL and the string package header's + LanguageName associated with a given Language is + not zero, the LanguageName being passed in will + be ignored. + @param String Points to the new null-terminated string. + @param StringFontInfo Points to the new string's font information or + NULL if the string should have the default system + font, size and style. + + @retval EFI_SUCCESS The new string was added successfully. + @retval EFI_NOT_FOUND The specified PackageList could not be found in + database. + @retval EFI_OUT_OF_RESOURCES Could not add the string due to lack of resources. + @retval EFI_INVALID_PARAMETER String is NULL or StringId is NULL or Language is + NULL. + @retval EFI_INVALID_PARAMETER The specified StringFontInfo does not exist in + current database. + +**/ +EFI_STATUS +EFIAPI +HiiNewString ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + OUT EFI_STRING_ID *StringId, + IN CONST CHAR8 *Language, + IN CONST CHAR16 *LanguageName, OPTIONAL + IN CONST EFI_STRING String, + IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + HII_DATABASE_PRIVATE_DATA *Private; + HII_DATABASE_RECORD *DatabaseRecord; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_STRING_PACKAGE_INSTANCE *StringPackage; + UINT32 HeaderSize; + UINT32 BlockSize; + UINT32 OldBlockSize; + UINT8 *StringBlock; + UINT8 *BlockPtr; + UINT32 Ucs2BlockSize; + UINT32 FontBlockSize; + UINT32 Ucs2FontBlockSize; + EFI_HII_SIBT_EXT2_BLOCK Ext2; + HII_FONT_INFO *LocalFont; + HII_GLOBAL_FONT_INFO *GlobalFont; + EFI_STRING_ID NewStringId; + EFI_STRING_ID NextStringId; + EFI_STRING_ID Index; + HII_STRING_PACKAGE_INSTANCE *MatchStringPackage; + BOOLEAN NewStringPackageCreated; + + + if (This == NULL || String == NULL || StringId == NULL || Language == NULL || PackageList == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!IsHiiHandleValid (PackageList)) { + return EFI_NOT_FOUND; + } + + Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This); + GlobalFont = NULL; + + // + // If StringFontInfo specify a paritcular font, it should exist in current database. + // + if (StringFontInfo != NULL) { + if (!IsFontInfoExisted (Private, (EFI_FONT_INFO *) StringFontInfo, NULL, NULL, &GlobalFont)) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Get the matching package list. + // + PackageListNode = NULL; + for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { + DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + if (DatabaseRecord->Handle == PackageList) { + PackageListNode = DatabaseRecord->PackageList; + break; + } + } + if (PackageListNode == NULL) { + return EFI_NOT_FOUND; + } + + EfiAcquireLock (&mHiiDatabaseLock); + + Status = EFI_SUCCESS; + NewStringPackageCreated = FALSE; + NewStringId = 0; + NextStringId = 0; + StringPackage = NULL; + MatchStringPackage = NULL; + for (Link = PackageListNode->StringPkgHdr.ForwardLink; + Link != &PackageListNode->StringPkgHdr; + Link = Link->ForwardLink + ) { + StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); + // + // Create a string block and corresponding font block if exists, then append them + // to the end of the string package. + // + Status = FindStringBlock ( + Private, + StringPackage, + 0, + NULL, + NULL, + NULL, + &NextStringId, + NULL + ); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Make sure that new StringId is same in all String Packages for the different language. + // + if (NewStringId != 0 && NewStringId != NextStringId) { + ASSERT (FALSE); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + NewStringId = NextStringId; + // + // Get the matched string package with language. + // + if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) { + MatchStringPackage = StringPackage; + } else { + OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize; + // + // Create a blank EFI_HII_SIBT_STRING_UCS2_BLOCK to reserve new string ID. + // + Ucs2BlockSize = (UINT32) sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK); + + StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2BlockSize); + if (StringBlock == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + // + // Copy original string blocks, except the EFI_HII_SIBT_END. + // + CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK)); + // + // Create a blank EFI_HII_SIBT_STRING_UCS2 block + // + BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK); + *BlockPtr = EFI_HII_SIBT_STRING_UCS2; + BlockPtr += sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK); + + // + // Append a EFI_HII_SIBT_END block to the end. + // + *BlockPtr = EFI_HII_SIBT_END; + ZeroMem (StringPackage->StringBlock, OldBlockSize); + FreePool (StringPackage->StringBlock); + StringPackage->StringBlock = StringBlock; + StringPackage->StringPkgHdr->Header.Length += Ucs2BlockSize; + PackageListNode->PackageListHdr.PackageLength += Ucs2BlockSize; + } + } + if (NewStringId == 0) { + // + // No string package is found. + // Create new string package. StringId 1 is reserved for Language Name string. + // + *StringId = 2; + } else { + // + // Set new StringId + // + *StringId = (EFI_STRING_ID) (NewStringId + 1); + } + + if (MatchStringPackage != NULL) { + StringPackage = MatchStringPackage; + } else { + // + // LanguageName is required to create a new string package. + // + if (LanguageName == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + StringPackage = AllocateZeroPool (sizeof (HII_STRING_PACKAGE_INSTANCE)); + if (StringPackage == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StringPackage->Signature = HII_STRING_PACKAGE_SIGNATURE; + StringPackage->MaxStringId = *StringId; + StringPackage->FontId = 0; + InitializeListHead (&StringPackage->FontInfoList); + + // + // Fill in the string package header + // + HeaderSize = (UINT32) (AsciiStrSize ((CHAR8 *) Language) - 1 + sizeof (EFI_HII_STRING_PACKAGE_HDR)); + StringPackage->StringPkgHdr = AllocateZeroPool (HeaderSize); + if (StringPackage->StringPkgHdr == NULL) { + FreePool (StringPackage); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + StringPackage->StringPkgHdr->Header.Type = EFI_HII_PACKAGE_STRINGS; + StringPackage->StringPkgHdr->HdrSize = HeaderSize; + StringPackage->StringPkgHdr->StringInfoOffset = HeaderSize; + CopyMem (StringPackage->StringPkgHdr->LanguageWindow, mLanguageWindow, 16 * sizeof (CHAR16)); + StringPackage->StringPkgHdr->LanguageName = 1; + AsciiStrCpyS (StringPackage->StringPkgHdr->Language, (HeaderSize - OFFSET_OF(EFI_HII_STRING_PACKAGE_HDR,Language)) / sizeof (CHAR8), (CHAR8 *) Language); + + // + // Calculate the length of the string blocks, including string block to record + // printable language full name and EFI_HII_SIBT_END_BLOCK. + // + Ucs2BlockSize = (UINT32) (StrSize ((CHAR16 *) LanguageName) + + (*StringId - 1) * sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) - sizeof (CHAR16)); + + BlockSize = Ucs2BlockSize + sizeof (EFI_HII_SIBT_END_BLOCK); + StringPackage->StringBlock = (UINT8 *) AllocateZeroPool (BlockSize); + if (StringPackage->StringBlock == NULL) { + FreePool (StringPackage->StringPkgHdr); + FreePool (StringPackage); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Insert the string block of printable language full name + // + BlockPtr = StringPackage->StringBlock; + *BlockPtr = EFI_HII_SIBT_STRING_UCS2; + BlockPtr += sizeof (EFI_HII_STRING_BLOCK); + CopyMem (BlockPtr, (EFI_STRING) LanguageName, StrSize ((EFI_STRING) LanguageName)); + BlockPtr += StrSize ((EFI_STRING) LanguageName); + for (Index = 2; Index <= *StringId - 1; Index ++) { + *BlockPtr = EFI_HII_SIBT_STRING_UCS2; + BlockPtr += sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK); + } + // + // Insert the end block + // + *BlockPtr = EFI_HII_SIBT_END; + + // + // Append this string package node to string package array in this package list. + // + StringPackage->StringPkgHdr->Header.Length = HeaderSize + BlockSize; + PackageListNode->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length; + InsertTailList (&PackageListNode->StringPkgHdr, &StringPackage->StringEntry); + NewStringPackageCreated = TRUE; + } + + OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize; + + if (StringFontInfo == NULL) { + // + // Create a EFI_HII_SIBT_STRING_UCS2_BLOCK since font info is not specified. + // + Ucs2BlockSize = (UINT32) (StrSize (String) + sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) + - sizeof (CHAR16)); + + StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2BlockSize); + if (StringBlock == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + // + // Copy original string blocks, except the EFI_HII_SIBT_END. + // + CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK)); + // + // Create a EFI_HII_SIBT_STRING_UCS2 block + // + BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK); + *BlockPtr = EFI_HII_SIBT_STRING_UCS2; + BlockPtr += sizeof (EFI_HII_STRING_BLOCK); + CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String)); + BlockPtr += StrSize ((EFI_STRING) String); + + // + // Append a EFI_HII_SIBT_END block to the end. + // + *BlockPtr = EFI_HII_SIBT_END; + ZeroMem (StringPackage->StringBlock, OldBlockSize); + FreePool (StringPackage->StringBlock); + StringPackage->StringBlock = StringBlock; + StringPackage->StringPkgHdr->Header.Length += Ucs2BlockSize; + PackageListNode->PackageListHdr.PackageLength += Ucs2BlockSize; + + } else { + // + // StringFontInfo is specified here. If there is a EFI_HII_SIBT_FONT_BLOCK + // which refers to this font info, create a EFI_HII_SIBT_STRING_UCS2_FONT block + // only. Otherwise create a EFI_HII_SIBT_FONT block with a EFI_HII_SIBT_STRING + // _UCS2_FONT block. + // + Ucs2FontBlockSize = (UINT32) (StrSize (String) + sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - + sizeof (CHAR16)); + if (ReferFontInfoLocally (Private, StringPackage, StringPackage->FontId, FALSE, GlobalFont, &LocalFont)) { + // + // Create a EFI_HII_SIBT_STRING_UCS2_FONT block only. + // + StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2FontBlockSize); + if (StringBlock == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + // + // Copy original string blocks, except the EFI_HII_SIBT_END. + // + CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK)); + // + // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK + // + BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK); + *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT; + BlockPtr += sizeof (EFI_HII_STRING_BLOCK); + *BlockPtr = LocalFont->FontId; + BlockPtr ++; + CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String)); + BlockPtr += StrSize ((EFI_STRING) String); + + // + // Append a EFI_HII_SIBT_END block to the end. + // + *BlockPtr = EFI_HII_SIBT_END; + ZeroMem (StringPackage->StringBlock, OldBlockSize); + FreePool (StringPackage->StringBlock); + StringPackage->StringBlock = StringBlock; + StringPackage->StringPkgHdr->Header.Length += Ucs2FontBlockSize; + PackageListNode->PackageListHdr.PackageLength += Ucs2FontBlockSize; + + } else { + // + // EFI_HII_SIBT_FONT_BLOCK does not exist in current string package, so + // create a EFI_HII_SIBT_FONT block to record the font info, then generate + // a EFI_HII_SIBT_STRING_UCS2_FONT block to record the incoming string. + // + FontBlockSize = (UINT32) (StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName) + + sizeof (EFI_HII_SIBT_FONT_BLOCK) - sizeof (CHAR16)); + StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + FontBlockSize + Ucs2FontBlockSize); + if (StringBlock == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + // + // Copy original string blocks, except the EFI_HII_SIBT_END. + // + CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK)); + + // + // Create a EFI_HII_SIBT_FONT block firstly and then backup its info in string + // package instance for future reference. + // + BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK); + + Ext2.Header.BlockType = EFI_HII_SIBT_EXT2; + Ext2.BlockType2 = EFI_HII_SIBT_FONT; + Ext2.Length = (UINT16) FontBlockSize; + CopyMem (BlockPtr, &Ext2, sizeof (EFI_HII_SIBT_EXT2_BLOCK)); + BlockPtr += sizeof (EFI_HII_SIBT_EXT2_BLOCK); + + *BlockPtr = LocalFont->FontId; + BlockPtr ++; + CopyMem (BlockPtr, &((EFI_FONT_INFO *) StringFontInfo)->FontSize, sizeof (UINT16)); + BlockPtr += sizeof (UINT16); + CopyMem (BlockPtr, &((EFI_FONT_INFO *) StringFontInfo)->FontStyle, sizeof (EFI_HII_FONT_STYLE)); + BlockPtr += sizeof (EFI_HII_FONT_STYLE); + CopyMem ( + BlockPtr, + &((EFI_FONT_INFO *) StringFontInfo)->FontName, + StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName) + ); + BlockPtr += StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName); + // + // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK + // + *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT; + BlockPtr += sizeof (EFI_HII_STRING_BLOCK); + *BlockPtr = LocalFont->FontId; + BlockPtr ++; + CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String)); + BlockPtr += StrSize ((EFI_STRING) String); + + // + // Append a EFI_HII_SIBT_END block to the end. + // + *BlockPtr = EFI_HII_SIBT_END; + ZeroMem (StringPackage->StringBlock, OldBlockSize); + FreePool (StringPackage->StringBlock); + StringPackage->StringBlock = StringBlock; + StringPackage->StringPkgHdr->Header.Length += FontBlockSize + Ucs2FontBlockSize; + PackageListNode->PackageListHdr.PackageLength += FontBlockSize + Ucs2FontBlockSize; + + // + // Increase the FontId to make it unique since we already add + // a EFI_HII_SIBT_FONT block to this string package. + // + StringPackage->FontId++; + } + } + +Done: + if (!EFI_ERROR (Status) && NewStringPackageCreated) { + // + // Trigger any registered notification function for new string package + // + Status = InvokeRegisteredFunction ( + Private, + EFI_HII_DATABASE_NOTIFY_NEW_PACK, + (VOID *) StringPackage, + EFI_HII_PACKAGE_STRINGS, + PackageList + ); + } + + if (!EFI_ERROR (Status)) { + // + // Update MaxString Id to new StringId + // + for (Link = PackageListNode->StringPkgHdr.ForwardLink; + Link != &PackageListNode->StringPkgHdr; + Link = Link->ForwardLink + ) { + StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); + StringPackage->MaxStringId = *StringId; + } + } else if (NewStringPackageCreated) { + // + // Free the allocated new string Package when new string can't be added. + // + RemoveEntryList (&StringPackage->StringEntry); + FreePool (StringPackage->StringBlock); + FreePool (StringPackage->StringPkgHdr); + FreePool (StringPackage); + } + // + // The contents of HiiDataBase may updated,need to check. + // + // + // Check whether need to get the contents of HiiDataBase. + // Only after ReadyToBoot to do the export. + // + if (gExportAfterReadyToBoot) { + if (!EFI_ERROR (Status)) { + HiiGetDatabaseInfo(&Private->HiiDatabase); + } + } + + EfiReleaseLock (&mHiiDatabaseLock); + + return Status; +} + + +/** + This function retrieves the string specified by StringId which is associated + with the specified PackageList in the language Language and copies it into + the buffer specified by String. + + @param This A pointer to the EFI_HII_STRING_PROTOCOL instance. + @param Language Points to the language for the retrieved string. + @param PackageList The package list in the HII database to search for + the specified string. + @param StringId The string's id, which is unique within + PackageList. + @param String Points to the new null-terminated string. + @param StringSize On entry, points to the size of the buffer pointed + to by String, in bytes. On return, points to the + length of the string, in bytes. + @param StringFontInfo If not NULL, points to the string's font + information. It's caller's responsibility to free + this buffer. + + @retval EFI_SUCCESS The string was returned successfully. + @retval EFI_NOT_FOUND The string specified by StringId is not available. + @retval EFI_NOT_FOUND The string specified by StringId is available but + not in the specified language. + The specified PackageList is not in the database. + @retval EFI_INVALID_LANGUAGE - The string specified by StringId is available but + @retval EFI_BUFFER_TOO_SMALL The buffer specified by StringSize is too small to + hold the string. + @retval EFI_INVALID_PARAMETER The Language or StringSize was NULL. + @retval EFI_INVALID_PARAMETER The value referenced by StringSize was not zero and String was NULL. + @retval EFI_OUT_OF_RESOURCES There were insufficient resources to complete the + request. + +**/ +EFI_STATUS +EFIAPI +HiiGetString ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN CONST CHAR8 *Language, + IN EFI_HII_HANDLE PackageList, + IN EFI_STRING_ID StringId, + OUT EFI_STRING String, + IN OUT UINTN *StringSize, + OUT EFI_FONT_INFO **StringFontInfo OPTIONAL + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + HII_DATABASE_PRIVATE_DATA *Private; + HII_DATABASE_RECORD *DatabaseRecord; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_STRING_PACKAGE_INSTANCE *StringPackage; + + if (This == NULL || Language == NULL || StringId < 1 || StringSize == NULL || PackageList == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (String == NULL && *StringSize != 0) { + return EFI_INVALID_PARAMETER; + } + + if (!IsHiiHandleValid (PackageList)) { + return EFI_NOT_FOUND; + } + + Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This); + PackageListNode = NULL; + + for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { + DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + if (DatabaseRecord->Handle == PackageList) { + PackageListNode = DatabaseRecord->PackageList; + break; + } + } + + if (PackageListNode != NULL) { + // + // First search: to match the StringId in the specified language. + // + for (Link = PackageListNode->StringPkgHdr.ForwardLink; + Link != &PackageListNode->StringPkgHdr; + Link = Link->ForwardLink + ) { + StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); + if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) { + Status = GetStringWorker (Private, StringPackage, StringId, String, StringSize, StringFontInfo); + if (Status != EFI_NOT_FOUND) { + return Status; + } + } + } + // + // Second search: to match the StringId in other available languages if exist. + // + for (Link = PackageListNode->StringPkgHdr.ForwardLink; + Link != &PackageListNode->StringPkgHdr; + Link = Link->ForwardLink + ) { + StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); + Status = GetStringWorker (Private, StringPackage, StringId, NULL, NULL, NULL); + if (!EFI_ERROR (Status)) { + return EFI_INVALID_LANGUAGE; + } + } + } + + return EFI_NOT_FOUND; +} + + + +/** + This function updates the string specified by StringId in the specified PackageList to the text + specified by String and, optionally, the font information specified by StringFontInfo. + + @param This A pointer to the EFI_HII_STRING_PROTOCOL instance. + @param PackageList The package list containing the strings. + @param StringId The string's id, which is unique within + PackageList. + @param Language Points to the language for the updated string. + @param String Points to the new null-terminated string. + @param StringFontInfo Points to the string's font information or NULL if + the string font information is not changed. + + @retval EFI_SUCCESS The string was updated successfully. + @retval EFI_NOT_FOUND The string specified by StringId is not in the + database. + @retval EFI_INVALID_PARAMETER The String or Language was NULL. + @retval EFI_INVALID_PARAMETER The specified StringFontInfo does not exist in + current database. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. + +**/ +EFI_STATUS +EFIAPI +HiiSetString ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + IN EFI_STRING_ID StringId, + IN CONST CHAR8 *Language, + IN CONST EFI_STRING String, + IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + HII_DATABASE_PRIVATE_DATA *Private; + HII_DATABASE_RECORD *DatabaseRecord; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_STRING_PACKAGE_INSTANCE *StringPackage; + UINT32 OldPackageLen; + + if (This == NULL || Language == NULL || StringId < 1 || String == NULL || PackageList == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!IsHiiHandleValid (PackageList)) { + return EFI_NOT_FOUND; + } + + EfiAcquireLock (&mHiiDatabaseLock); + + Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This); + PackageListNode = NULL; + + for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { + DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + if (DatabaseRecord->Handle == PackageList) { + PackageListNode = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (DatabaseRecord->PackageList); + } + } + + if (PackageListNode != NULL) { + for (Link = PackageListNode->StringPkgHdr.ForwardLink; + Link != &PackageListNode->StringPkgHdr; + Link = Link->ForwardLink + ) { + StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); + if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) { + OldPackageLen = StringPackage->StringPkgHdr->Header.Length; + Status = SetStringWorker ( + Private, + StringPackage, + StringId, + (EFI_STRING) String, + (EFI_FONT_INFO *) StringFontInfo + ); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&mHiiDatabaseLock); + return Status; + } + PackageListNode->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length - OldPackageLen; + // + // Check whether need to get the contents of HiiDataBase. + // Only after ReadyToBoot to do the export. + // + if (gExportAfterReadyToBoot) { + HiiGetDatabaseInfo(&Private->HiiDatabase); + } + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_SUCCESS; + } + } + } + + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_NOT_FOUND; +} + + + +/** + This function returns the list of supported languages, in the format specified + in Appendix M of UEFI 2.1 spec. + + @param This A pointer to the EFI_HII_STRING_PROTOCOL instance. + @param PackageList The package list to examine. + @param Languages Points to the buffer to hold the returned + null-terminated ASCII string. + @param LanguagesSize On entry, points to the size of the buffer pointed + to by Languages, in bytes. On return, points to + the length of Languages, in bytes. + + @retval EFI_SUCCESS The languages were returned successfully. + @retval EFI_INVALID_PARAMETER The LanguagesSize was NULL. + @retval EFI_INVALID_PARAMETER The value referenced by LanguagesSize is not zero and Languages is NULL. + @retval EFI_BUFFER_TOO_SMALL The LanguagesSize is too small to hold the list of + supported languages. LanguageSize is updated to + contain the required size. + @retval EFI_NOT_FOUND Could not find string package in specified + packagelist. + +**/ +EFI_STATUS +EFIAPI +HiiGetLanguages ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + IN OUT CHAR8 *Languages, + IN OUT UINTN *LanguagesSize + ) +{ + LIST_ENTRY *Link; + HII_DATABASE_PRIVATE_DATA *Private; + HII_DATABASE_RECORD *DatabaseRecord; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_STRING_PACKAGE_INSTANCE *StringPackage; + UINTN ResultSize; + + if (This == NULL || LanguagesSize == NULL || PackageList == NULL) { + return EFI_INVALID_PARAMETER; + } + if (*LanguagesSize != 0 && Languages == NULL) { + return EFI_INVALID_PARAMETER; + } + if (!IsHiiHandleValid (PackageList)) { + return EFI_NOT_FOUND; + } + + Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This); + + PackageListNode = NULL; + for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { + DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + if (DatabaseRecord->Handle == PackageList) { + PackageListNode = DatabaseRecord->PackageList; + break; + } + } + if (PackageListNode == NULL) { + return EFI_NOT_FOUND; + } + + // + // Search the languages in the specified packagelist. + // + ResultSize = 0; + for (Link = PackageListNode->StringPkgHdr.ForwardLink; + Link != &PackageListNode->StringPkgHdr; + Link = Link->ForwardLink + ) { + StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); + ResultSize += AsciiStrSize (StringPackage->StringPkgHdr->Language); + if (ResultSize <= *LanguagesSize) { + AsciiStrCpyS (Languages, *LanguagesSize / sizeof (CHAR8), StringPackage->StringPkgHdr->Language); + Languages += AsciiStrSize (StringPackage->StringPkgHdr->Language); + *(Languages - 1) = L';'; + } + } + if (ResultSize == 0) { + return EFI_NOT_FOUND; + } + + if (*LanguagesSize < ResultSize) { + *LanguagesSize = ResultSize; + return EFI_BUFFER_TOO_SMALL; + } + + *(Languages - 1) = 0; + return EFI_SUCCESS; +} + + +/** + Each string package has associated with it a single primary language and zero + or more secondary languages. This routine returns the secondary languages + associated with a package list. + + @param This A pointer to the EFI_HII_STRING_PROTOCOL instance. + @param PackageList The package list to examine. + @param PrimaryLanguage Points to the null-terminated ASCII string that specifies + the primary language. Languages are specified in the + format specified in Appendix M of the UEFI 2.0 specification. + @param SecondaryLanguages Points to the buffer to hold the returned null-terminated + ASCII string that describes the list of + secondary languages for the specified + PrimaryLanguage. If there are no secondary + languages, the function returns successfully, but + this is set to NULL. + @param SecondaryLanguagesSize On entry, points to the size of the buffer pointed + to by SecondaryLanguages, in bytes. On return, + points to the length of SecondaryLanguages in bytes. + + @retval EFI_SUCCESS Secondary languages were correctly returned. + @retval EFI_INVALID_PARAMETER PrimaryLanguage or SecondaryLanguagesSize was NULL. + @retval EFI_INVALID_PARAMETER The value referenced by SecondaryLanguagesSize is not + zero and SecondaryLanguages is NULL. + @retval EFI_BUFFER_TOO_SMALL The buffer specified by SecondaryLanguagesSize is + too small to hold the returned information. + SecondaryLanguageSize is updated to hold the size of + the buffer required. + @retval EFI_INVALID_LANGUAGE The language specified by PrimaryLanguage is not + present in the specified package list. + @retval EFI_NOT_FOUND The specified PackageList is not in the Database. + +**/ +EFI_STATUS +EFIAPI +HiiGetSecondaryLanguages ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + IN CONST CHAR8 *PrimaryLanguage, + IN OUT CHAR8 *SecondaryLanguages, + IN OUT UINTN *SecondaryLanguagesSize + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *Link1; + HII_DATABASE_PRIVATE_DATA *Private; + HII_DATABASE_RECORD *DatabaseRecord; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_STRING_PACKAGE_INSTANCE *StringPackage; + CHAR8 *Languages; + UINTN ResultSize; + + if (This == NULL || PackageList == NULL || PrimaryLanguage == NULL || SecondaryLanguagesSize == NULL) { + return EFI_INVALID_PARAMETER; + } + if (SecondaryLanguages == NULL && *SecondaryLanguagesSize != 0) { + return EFI_INVALID_PARAMETER; + } + if (!IsHiiHandleValid (PackageList)) { + return EFI_NOT_FOUND; + } + + Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This); + + PackageListNode = NULL; + for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { + DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + if (DatabaseRecord->Handle == PackageList) { + PackageListNode = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (DatabaseRecord->PackageList); + break; + } + } + if (PackageListNode == NULL) { + return EFI_NOT_FOUND; + } + + Languages = NULL; + ResultSize = 0; + for (Link1 = PackageListNode->StringPkgHdr.ForwardLink; + Link1 != &PackageListNode->StringPkgHdr; + Link1 = Link1->ForwardLink + ) { + StringPackage = CR (Link1, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); + if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) PrimaryLanguage)) { + Languages = StringPackage->StringPkgHdr->Language; + // + // Language is a series of ';' terminated strings, first one is primary + // language and following with other secondary languages or NULL if no + // secondary languages any more. + // + Languages = AsciiStrStr (Languages, ";"); + if (Languages == NULL) { + break; + } + Languages++; + + ResultSize = AsciiStrSize (Languages); + if (ResultSize <= *SecondaryLanguagesSize) { + AsciiStrCpyS (SecondaryLanguages, *SecondaryLanguagesSize / sizeof (CHAR8), Languages); + } else { + *SecondaryLanguagesSize = ResultSize; + return EFI_BUFFER_TOO_SMALL; + } + + return EFI_SUCCESS; + } + } + + return EFI_INVALID_LANGUAGE; +} + +/** + Converts the ascii character of the string from uppercase to lowercase. + This is a internal function. + + @param ConfigString String to be converted + +**/ +VOID +EFIAPI +AsciiHiiToLower ( + IN CHAR8 *ConfigString + ) +{ + ASSERT (ConfigString != NULL); + + // + // Convert all hex digits in range [A-F] in the configuration header to [a-f] + // + for (; *ConfigString != '\0'; ConfigString++) { + if ( *ConfigString >= 'A' && *ConfigString <= 'Z') { + *ConfigString = (CHAR8) (*ConfigString - 'A' + 'a'); + } + } +} + +/** + Compare whether two names of languages are identical. + + @param Language1 Name of language 1 from StringPackage + @param Language2 Name of language 2 to be compared with language 1. + + @retval TRUE same + @retval FALSE not same + +**/ +BOOLEAN +HiiCompareLanguage ( + IN CHAR8 *Language1, + IN CHAR8 *Language2 + ) +{ + UINTN Index; + UINTN StrLen; + CHAR8 *Lan1; + CHAR8 *Lan2; + + // + // Convert to lower to compare. + // + StrLen = AsciiStrSize (Language1); + Lan1 = AllocateZeroPool (StrLen); + ASSERT (Lan1 != NULL); + AsciiStrCpyS(Lan1, StrLen / sizeof (CHAR8), Language1); + AsciiHiiToLower (Lan1); + + StrLen = AsciiStrSize (Language2); + Lan2 = AllocateZeroPool (StrLen); + ASSERT (Lan2 != NULL); + AsciiStrCpyS(Lan2, StrLen / sizeof (CHAR8), Language2); + AsciiHiiToLower (Lan2); + + // + // Compare the Primary Language in Language1 to Language2 + // + for (Index = 0; Lan1[Index] != 0 && Lan1[Index] != ';'; Index++) { + if (Lan1[Index] != Lan2[Index]) { + // + // Return FALSE if any characters are different. + // + FreePool (Lan1); + FreePool (Lan2); + return FALSE; + } + } + + FreePool (Lan1); + FreePool (Lan2); + + // + // Only return TRUE if Language2[Index] is a Null-terminator which means + // the Primary Language in Language1 is the same length as Language2. If + // Language2[Index] is not a Null-terminator, then Language2 is longer than + // the Primary Language in Language1, and FALSE must be returned. + // + return (BOOLEAN) (Language2[Index] == 0); +} -- cgit 1.2.3-korg