Home | History | Annotate | Download | only in HiiDatabaseDxe
      1 /** @file
      2 Implementation for EFI_HII_STRING_PROTOCOL.
      3 
      4 
      5 Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 
     17 #include "HiiDatabase.h"
     18 
     19 CHAR16 mLanguageWindow[16] = {
     20   0x0000, 0x0080, 0x0100, 0x0300,
     21   0x2000, 0x2080, 0x2100, 0x3000,
     22   0x0080, 0x00C0, 0x0400, 0x0600,
     23   0x0900, 0x3040, 0x30A0, 0xFF00
     24 };
     25 
     26 
     27 /**
     28   This function checks whether a global font info is referred by local
     29   font info list or not. (i.e. HII_FONT_INFO is generated.) If not, create
     30   a HII_FONT_INFO to refer it locally.
     31 
     32   This is a internal function.
     33 
     34 
     35   @param  Private                Hii database private structure.
     36   @param  StringPackage          HII string package instance.
     37   @param  FontId                Font identifer, which must be unique within the string package.
     38   @param  DuplicateEnable        If true, duplicate HII_FONT_INFO which refers to
     39                                  the same EFI_FONT_INFO is permitted. Otherwise it
     40                                  is not allowed.
     41   @param  GlobalFontInfo         Input a global font info which specify a
     42                                  EFI_FONT_INFO.
     43   @param  LocalFontInfo          Output a local font info which refers to a
     44                                  EFI_FONT_INFO.
     45 
     46   @retval TRUE                   Already referred before calling this function.
     47   @retval FALSE                  Not referred before calling this function.
     48 
     49 **/
     50 BOOLEAN
     51 ReferFontInfoLocally (
     52   IN  HII_DATABASE_PRIVATE_DATA   *Private,
     53   IN  HII_STRING_PACKAGE_INSTANCE *StringPackage,
     54   IN  UINT8                       FontId,
     55   IN  BOOLEAN                     DuplicateEnable,
     56   IN  HII_GLOBAL_FONT_INFO        *GlobalFontInfo,
     57   OUT HII_FONT_INFO               **LocalFontInfo
     58   )
     59 {
     60   HII_FONT_INFO                 *LocalFont;
     61   LIST_ENTRY                    *Link;
     62 
     63   ASSERT (Private != NULL && StringPackage != NULL && GlobalFontInfo != NULL && LocalFontInfo != NULL);
     64 
     65   if (!DuplicateEnable) {
     66     for (Link = StringPackage->FontInfoList.ForwardLink;
     67          Link != &StringPackage->FontInfoList;
     68          Link = Link->ForwardLink
     69         ) {
     70       LocalFont = CR (Link, HII_FONT_INFO, Entry, HII_FONT_INFO_SIGNATURE);
     71       if (LocalFont->GlobalEntry == &GlobalFontInfo->Entry) {
     72         //
     73         // Already referred by local font info list, return directly.
     74         //
     75         *LocalFontInfo = LocalFont;
     76         return TRUE;
     77       }
     78     }
     79   }
     80   // FontId identifies EFI_FONT_INFO in local string package uniquely.
     81   // GlobalEntry points to a HII_GLOBAL_FONT_INFO which identifies
     82   // EFI_FONT_INFO uniquely in whole hii database.
     83   //
     84   LocalFont = (HII_FONT_INFO *) AllocateZeroPool (sizeof (HII_FONT_INFO));
     85   ASSERT (LocalFont != NULL);
     86 
     87   LocalFont->Signature   = HII_FONT_INFO_SIGNATURE;
     88   LocalFont->FontId      = FontId;
     89   LocalFont->GlobalEntry = &GlobalFontInfo->Entry;
     90   InsertTailList (&StringPackage->FontInfoList, &LocalFont->Entry);
     91 
     92   *LocalFontInfo = LocalFont;
     93   return FALSE;
     94 }
     95 
     96 
     97 /**
     98   Convert Ascii string text to unicode string test.
     99 
    100   This is a internal function.
    101 
    102 
    103   @param  StringDest             Buffer to store the string text. If it is NULL,
    104                                  only the size will be returned.
    105   @param  StringSrc              Points to current null-terminated string.
    106   @param  BufferSize             Length of the buffer.
    107 
    108   @retval EFI_SUCCESS            The string text was outputed successfully.
    109   @retval EFI_BUFFER_TOO_SMALL   Buffer is insufficient to store the found string
    110                                  text. BufferSize is updated to the required buffer
    111                                  size.
    112 
    113 **/
    114 EFI_STATUS
    115 ConvertToUnicodeText (
    116   OUT EFI_STRING       StringDest,
    117   IN  CHAR8            *StringSrc,
    118   IN  OUT UINTN        *BufferSize
    119   )
    120 {
    121   UINTN  StringSize;
    122   UINTN  Index;
    123 
    124   ASSERT (StringSrc != NULL && BufferSize != NULL);
    125 
    126   StringSize = AsciiStrSize (StringSrc) * 2;
    127   if (*BufferSize < StringSize || StringDest == NULL) {
    128     *BufferSize = StringSize;
    129     return EFI_BUFFER_TOO_SMALL;
    130   }
    131 
    132   for (Index = 0; Index < AsciiStrLen (StringSrc); Index++) {
    133     StringDest[Index] = (CHAR16) StringSrc[Index];
    134   }
    135 
    136   StringDest[Index] = 0;
    137   return EFI_SUCCESS;
    138 }
    139 
    140 
    141 /**
    142   Calculate the size of StringSrc and output it. If StringDest is not NULL,
    143   copy string text from src to dest.
    144 
    145   This is a internal function.
    146 
    147   @param  StringDest             Buffer to store the string text. If it is NULL,
    148                                  only the size will be returned.
    149   @param  StringSrc              Points to current null-terminated string.
    150   @param  BufferSize             Length of the buffer.
    151 
    152   @retval EFI_SUCCESS            The string text was outputed successfully.
    153   @retval EFI_BUFFER_TOO_SMALL   Buffer is insufficient to store the found string
    154                                  text. BufferSize is updated to the required buffer
    155                                  size.
    156 
    157 **/
    158 EFI_STATUS
    159 GetUnicodeStringTextOrSize (
    160   OUT EFI_STRING       StringDest, OPTIONAL
    161   IN  UINT8            *StringSrc,
    162   IN  OUT UINTN        *BufferSize
    163   )
    164 {
    165   UINTN  StringSize;
    166   UINT8  *StringPtr;
    167 
    168   ASSERT (StringSrc != NULL && BufferSize != NULL);
    169 
    170   StringSize = sizeof (CHAR16);
    171   StringPtr  = StringSrc;
    172   while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) {
    173     StringSize += sizeof (CHAR16);
    174     StringPtr += sizeof (CHAR16);
    175   }
    176 
    177   if (*BufferSize < StringSize) {
    178     *BufferSize = StringSize;
    179     return EFI_BUFFER_TOO_SMALL;
    180   }
    181   if (StringDest != NULL) {
    182     CopyMem (StringDest, StringSrc, StringSize);
    183   }
    184 
    185   *BufferSize = StringSize;
    186   return EFI_SUCCESS;
    187 }
    188 
    189 
    190 /**
    191   Copy string font info to a buffer.
    192 
    193   This is a internal function.
    194 
    195   @param  StringPackage          Hii string package instance.
    196   @param  FontId                 Font identifier which is unique in a string
    197                                  package.
    198   @param  StringFontInfo         Buffer to record the output font info. It's
    199                                  caller's responsibility to free this buffer.
    200 
    201   @retval EFI_SUCCESS            The string font is outputed successfully.
    202   @retval EFI_NOT_FOUND          The specified font id does not exist.
    203 
    204 **/
    205 EFI_STATUS
    206 GetStringFontInfo (
    207   IN  HII_STRING_PACKAGE_INSTANCE     *StringPackage,
    208   IN  UINT8                           FontId,
    209   OUT EFI_FONT_INFO                   **StringFontInfo
    210   )
    211 {
    212   LIST_ENTRY                           *Link;
    213   HII_FONT_INFO                        *FontInfo;
    214   HII_GLOBAL_FONT_INFO                 *GlobalFont;
    215 
    216   ASSERT (StringFontInfo != NULL && StringPackage != NULL);
    217 
    218   for (Link = StringPackage->FontInfoList.ForwardLink; Link != &StringPackage->FontInfoList; Link = Link->ForwardLink) {
    219     FontInfo = CR (Link, HII_FONT_INFO, Entry, HII_FONT_INFO_SIGNATURE);
    220     if (FontInfo->FontId == FontId) {
    221       GlobalFont = CR (FontInfo->GlobalEntry, HII_GLOBAL_FONT_INFO, Entry, HII_GLOBAL_FONT_INFO_SIGNATURE);
    222       *StringFontInfo = (EFI_FONT_INFO *) AllocateZeroPool (GlobalFont->FontInfoSize);
    223       if (*StringFontInfo == NULL) {
    224         return EFI_OUT_OF_RESOURCES;
    225       }
    226       CopyMem (*StringFontInfo, GlobalFont->FontInfo, GlobalFont->FontInfoSize);
    227       return EFI_SUCCESS;
    228     }
    229   }
    230 
    231   return EFI_NOT_FOUND;
    232 }
    233 
    234 
    235 /**
    236   Parse all string blocks to find a String block specified by StringId.
    237   If StringId = (EFI_STRING_ID) (-1), find out all EFI_HII_SIBT_FONT blocks
    238   within this string package and backup its information. If LastStringId is
    239   specified, the string id of last string block will also be output.
    240   If StringId = 0, output the string id of last string block (EFI_HII_SIBT_STRING).
    241 
    242   @param  Private                 Hii database private structure.
    243   @param  StringPackage           Hii string package instance.
    244   @param  StringId                The string's id, which is unique within
    245                                   PackageList.
    246   @param  BlockType               Output the block type of found string block.
    247   @param  StringBlockAddr         Output the block address of found string block.
    248   @param  StringTextOffset        Offset, relative to the found block address, of
    249                                   the  string text information.
    250   @param  LastStringId            Output the last string id when StringId = 0 or StringId = -1.
    251   @param  StartStringId           The first id in the skip block which StringId in the block.
    252 
    253   @retval EFI_SUCCESS             The string text and font is retrieved
    254                                   successfully.
    255   @retval EFI_NOT_FOUND           The specified text or font info can not be found
    256                                   out.
    257   @retval EFI_OUT_OF_RESOURCES    The system is out of resources to accomplish the
    258                                   task.
    259 
    260 **/
    261 EFI_STATUS
    262 FindStringBlock (
    263   IN HII_DATABASE_PRIVATE_DATA        *Private,
    264   IN  HII_STRING_PACKAGE_INSTANCE     *StringPackage,
    265   IN  EFI_STRING_ID                   StringId,
    266   OUT UINT8                           *BlockType, OPTIONAL
    267   OUT UINT8                           **StringBlockAddr, OPTIONAL
    268   OUT UINTN                           *StringTextOffset, OPTIONAL
    269   OUT EFI_STRING_ID                   *LastStringId, OPTIONAL
    270   OUT EFI_STRING_ID                   *StartStringId OPTIONAL
    271   )
    272 {
    273   UINT8                                *BlockHdr;
    274   EFI_STRING_ID                        CurrentStringId;
    275   UINTN                                BlockSize;
    276   UINTN                                Index;
    277   UINT8                                *StringTextPtr;
    278   UINTN                                Offset;
    279   HII_FONT_INFO                        *LocalFont;
    280   EFI_FONT_INFO                        *FontInfo;
    281   HII_GLOBAL_FONT_INFO                 *GlobalFont;
    282   UINTN                                FontInfoSize;
    283   UINT16                               StringCount;
    284   UINT16                               SkipCount;
    285   EFI_HII_FONT_STYLE                   FontStyle;
    286   UINT16                               FontSize;
    287   UINT8                                Length8;
    288   EFI_HII_SIBT_EXT2_BLOCK              Ext2;
    289   UINT8                                FontId;
    290   UINT32                               Length32;
    291   UINTN                                StringSize;
    292   CHAR16                               Zero;
    293 
    294   ASSERT (StringPackage != NULL);
    295   ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
    296 
    297   CurrentStringId = 1;
    298 
    299   if (StringId != (EFI_STRING_ID) (-1) && StringId != 0) {
    300     ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
    301     if (StringId > StringPackage->MaxStringId) {
    302       return EFI_NOT_FOUND;
    303     }
    304   } else {
    305     ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
    306     if (StringId == 0 && LastStringId != NULL) {
    307       *LastStringId = StringPackage->MaxStringId;
    308       return EFI_SUCCESS;
    309     }
    310   }
    311 
    312   ZeroMem (&Zero, sizeof (CHAR16));
    313 
    314   //
    315   // Parse the string blocks to get the string text and font.
    316   //
    317   BlockHdr  = StringPackage->StringBlock;
    318   BlockSize = 0;
    319   Offset    = 0;
    320   while (*BlockHdr != EFI_HII_SIBT_END) {
    321     switch (*BlockHdr) {
    322     case EFI_HII_SIBT_STRING_SCSU:
    323       Offset = sizeof (EFI_HII_STRING_BLOCK);
    324       StringTextPtr = BlockHdr + Offset;
    325       BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
    326       CurrentStringId++;
    327       break;
    328 
    329     case EFI_HII_SIBT_STRING_SCSU_FONT:
    330       Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
    331       StringTextPtr = BlockHdr + Offset;
    332       BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
    333       CurrentStringId++;
    334       break;
    335 
    336     case EFI_HII_SIBT_STRINGS_SCSU:
    337       CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
    338       StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8));
    339       BlockSize += StringTextPtr - BlockHdr;
    340 
    341       for (Index = 0; Index < StringCount; Index++) {
    342         BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
    343         if (CurrentStringId == StringId) {
    344           ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
    345           *BlockType        = *BlockHdr;
    346           *StringBlockAddr  = BlockHdr;
    347           *StringTextOffset = StringTextPtr - BlockHdr;
    348           return EFI_SUCCESS;
    349         }
    350         StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
    351         CurrentStringId++;
    352       }
    353       break;
    354 
    355     case EFI_HII_SIBT_STRINGS_SCSU_FONT:
    356       CopyMem (
    357         &StringCount,
    358         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
    359         sizeof (UINT16)
    360         );
    361       StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8));
    362       BlockSize += StringTextPtr - BlockHdr;
    363 
    364       for (Index = 0; Index < StringCount; Index++) {
    365         BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
    366         if (CurrentStringId == StringId) {
    367           ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
    368           *BlockType        = *BlockHdr;
    369           *StringBlockAddr  = BlockHdr;
    370           *StringTextOffset = StringTextPtr - BlockHdr;
    371           return EFI_SUCCESS;
    372         }
    373         StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
    374         CurrentStringId++;
    375       }
    376       break;
    377 
    378     case EFI_HII_SIBT_STRING_UCS2:
    379       Offset        = sizeof (EFI_HII_STRING_BLOCK);
    380       StringTextPtr = BlockHdr + Offset;
    381       //
    382       // Use StringSize to store the size of the specified string, including the NULL
    383       // terminator.
    384       //
    385       GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
    386       BlockSize += Offset + StringSize;
    387       CurrentStringId++;
    388       break;
    389 
    390     case EFI_HII_SIBT_STRING_UCS2_FONT:
    391       Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK)  - sizeof (CHAR16);
    392       StringTextPtr = BlockHdr + Offset;
    393       //
    394       // Use StrSize to store the size of the specified string, including the NULL
    395       // terminator.
    396       //
    397       GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
    398       BlockSize += Offset + StringSize;
    399       CurrentStringId++;
    400       break;
    401 
    402     case EFI_HII_SIBT_STRINGS_UCS2:
    403       Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
    404       StringTextPtr = BlockHdr + Offset;
    405       BlockSize += Offset;
    406       CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
    407       for (Index = 0; Index < StringCount; Index++) {
    408         GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
    409         BlockSize += StringSize;
    410         if (CurrentStringId == StringId) {
    411           ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
    412           *BlockType        = *BlockHdr;
    413           *StringBlockAddr  = BlockHdr;
    414           *StringTextOffset = StringTextPtr - BlockHdr;
    415           return EFI_SUCCESS;
    416         }
    417         StringTextPtr = StringTextPtr + StringSize;
    418         CurrentStringId++;
    419       }
    420       break;
    421 
    422     case EFI_HII_SIBT_STRINGS_UCS2_FONT:
    423       Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
    424       StringTextPtr = BlockHdr + Offset;
    425       BlockSize += Offset;
    426       CopyMem (
    427         &StringCount,
    428         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
    429         sizeof (UINT16)
    430         );
    431       for (Index = 0; Index < StringCount; Index++) {
    432         GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
    433         BlockSize += StringSize;
    434         if (CurrentStringId == StringId) {
    435           ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
    436           *BlockType        = *BlockHdr;
    437           *StringBlockAddr  = BlockHdr;
    438           *StringTextOffset = StringTextPtr - BlockHdr;
    439           return EFI_SUCCESS;
    440         }
    441         StringTextPtr = StringTextPtr + StringSize;
    442         CurrentStringId++;
    443       }
    444       break;
    445 
    446     case EFI_HII_SIBT_DUPLICATE:
    447       if (CurrentStringId == StringId) {
    448         //
    449         // Incoming StringId is an id of a duplicate string block.
    450         // Update the StringId to be the previous string block.
    451         // Go back to the header of string block to search.
    452         //
    453         CopyMem (
    454           &StringId,
    455           BlockHdr + sizeof (EFI_HII_STRING_BLOCK),
    456           sizeof (EFI_STRING_ID)
    457           );
    458         ASSERT (StringId != CurrentStringId);
    459         CurrentStringId = 1;
    460         BlockSize       = 0;
    461       } else {
    462         BlockSize       += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
    463         CurrentStringId++;
    464       }
    465       break;
    466 
    467     case EFI_HII_SIBT_SKIP1:
    468       SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
    469       CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
    470       BlockSize       +=  sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
    471       break;
    472 
    473     case EFI_HII_SIBT_SKIP2:
    474       CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
    475       CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
    476       BlockSize       +=  sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
    477       break;
    478 
    479     case EFI_HII_SIBT_EXT1:
    480       CopyMem (
    481         &Length8,
    482         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
    483         sizeof (UINT8)
    484         );
    485       BlockSize += Length8;
    486       break;
    487 
    488     case EFI_HII_SIBT_EXT2:
    489       CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
    490       if (Ext2.BlockType2 == EFI_HII_SIBT_FONT && StringId == (EFI_STRING_ID) (-1)) {
    491         //
    492         // Find the relationship between global font info and the font info of
    493         // this EFI_HII_SIBT_FONT block then backup its information in local package.
    494         //
    495         BlockHdr += sizeof (EFI_HII_SIBT_EXT2_BLOCK);
    496         CopyMem (&FontId, BlockHdr, sizeof (UINT8));
    497         BlockHdr ++;
    498         CopyMem (&FontSize, BlockHdr, sizeof (UINT16));
    499         BlockHdr += sizeof (UINT16);
    500         CopyMem (&FontStyle, BlockHdr, sizeof (EFI_HII_FONT_STYLE));
    501         BlockHdr += sizeof (EFI_HII_FONT_STYLE);
    502         GetUnicodeStringTextOrSize (NULL, BlockHdr, &StringSize);
    503 
    504         FontInfoSize = sizeof (EFI_FONT_INFO) - sizeof (CHAR16) + StringSize;
    505         FontInfo = (EFI_FONT_INFO *) AllocateZeroPool (FontInfoSize);
    506         if (FontInfo == NULL) {
    507           return EFI_OUT_OF_RESOURCES;
    508         }
    509         FontInfo->FontStyle = FontStyle;
    510         FontInfo->FontSize  = FontSize;
    511         CopyMem (FontInfo->FontName, BlockHdr, StringSize);
    512 
    513         //
    514         // If find the corresponding global font info, save the relationship.
    515         // Otherwise ignore this EFI_HII_SIBT_FONT block.
    516         //
    517         if (IsFontInfoExisted (Private, FontInfo, NULL, NULL, &GlobalFont)) {
    518           ReferFontInfoLocally (Private, StringPackage, FontId, TRUE, GlobalFont, &LocalFont);
    519         }
    520 
    521         //
    522         // Since string package tool set FontId initially to 0 and increases it
    523         // progressively by one, StringPackage->FondId always represents an unique
    524         // and available FontId.
    525         //
    526         StringPackage->FontId++;
    527 
    528         FreePool (FontInfo);
    529       }
    530 
    531       BlockSize += Ext2.Length;
    532 
    533       break;
    534 
    535     case EFI_HII_SIBT_EXT4:
    536       CopyMem (
    537         &Length32,
    538         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
    539         sizeof (UINT32)
    540         );
    541 
    542       BlockSize += Length32;
    543       break;
    544 
    545     default:
    546       break;
    547     }
    548 
    549     if (StringId > 0 && StringId != (EFI_STRING_ID)(-1)) {
    550       ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
    551       *BlockType        = *BlockHdr;
    552       *StringBlockAddr  = BlockHdr;
    553       *StringTextOffset = Offset;
    554 
    555       if (StringId == CurrentStringId - 1) {
    556         //
    557         // if only one skip item, return EFI_NOT_FOUND.
    558         //
    559         if(*BlockType == EFI_HII_SIBT_SKIP2 || *BlockType == EFI_HII_SIBT_SKIP1) {
    560           return EFI_NOT_FOUND;
    561         } else {
    562           return EFI_SUCCESS;
    563         }
    564       }
    565 
    566       if (StringId < CurrentStringId - 1) {
    567         return EFI_NOT_FOUND;
    568       }
    569     }
    570     BlockHdr  = StringPackage->StringBlock + BlockSize;
    571     if (StartStringId != NULL) {
    572         *StartStringId  = CurrentStringId;
    573     }
    574   }
    575 
    576   //
    577   // Get last string ID
    578   //
    579   if (StringId == (EFI_STRING_ID) (-1) && LastStringId != NULL) {
    580     *LastStringId = (EFI_STRING_ID) (CurrentStringId - 1);
    581     return EFI_SUCCESS;
    582   }
    583 
    584   return EFI_NOT_FOUND;
    585 }
    586 
    587 
    588 /**
    589   Parse all string blocks to get a string specified by StringId.
    590 
    591   This is a internal function.
    592 
    593   @param  Private                Hii database private structure.
    594   @param  StringPackage          Hii string package instance.
    595   @param  StringId               The string's id, which is unique within
    596                                  PackageList.
    597   @param  String                 Points to retrieved null-terminated string.
    598   @param  StringSize             On entry, points to the size of the buffer pointed
    599                                  to by String, in bytes. On return, points to the
    600                                  length of the string, in bytes.
    601   @param  StringFontInfo         If not NULL, allocate a buffer to record the
    602                                  output font info. It's caller's responsibility to
    603                                  free this buffer.
    604 
    605   @retval EFI_SUCCESS            The string text and font is retrieved
    606                                  successfully.
    607   @retval EFI_NOT_FOUND          The specified text or font info can not be found
    608                                  out.
    609   @retval EFI_BUFFER_TOO_SMALL   The buffer specified by StringSize is too small to
    610                                  hold the string.
    611 
    612 **/
    613 EFI_STATUS
    614 GetStringWorker (
    615   IN HII_DATABASE_PRIVATE_DATA        *Private,
    616   IN  HII_STRING_PACKAGE_INSTANCE     *StringPackage,
    617   IN  EFI_STRING_ID                   StringId,
    618   OUT EFI_STRING                      String,
    619   IN  OUT UINTN                       *StringSize, OPTIONAL
    620   OUT EFI_FONT_INFO                   **StringFontInfo OPTIONAL
    621   )
    622 {
    623   UINT8                                *StringTextPtr;
    624   UINT8                                BlockType;
    625   UINT8                                *StringBlockAddr;
    626   UINTN                                StringTextOffset;
    627   EFI_STATUS                           Status;
    628   UINT8                                FontId;
    629 
    630   ASSERT (StringPackage != NULL);
    631   ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
    632 
    633   //
    634   // Find the specified string block
    635   //
    636   Status = FindStringBlock (
    637              Private,
    638              StringPackage,
    639              StringId,
    640              &BlockType,
    641              &StringBlockAddr,
    642              &StringTextOffset,
    643              NULL,
    644              NULL
    645              );
    646   if (EFI_ERROR (Status)) {
    647     return Status;
    648   }
    649 
    650   if (StringSize == NULL) {
    651     //
    652     // String text buffer is not requested
    653     //
    654     return EFI_SUCCESS;
    655   }
    656 
    657   //
    658   // Get the string text.
    659   //
    660   StringTextPtr = StringBlockAddr + StringTextOffset;
    661   switch (BlockType) {
    662   case EFI_HII_SIBT_STRING_SCSU:
    663   case EFI_HII_SIBT_STRING_SCSU_FONT:
    664   case EFI_HII_SIBT_STRINGS_SCSU:
    665   case EFI_HII_SIBT_STRINGS_SCSU_FONT:
    666     Status = ConvertToUnicodeText (String, (CHAR8 *) StringTextPtr, StringSize);
    667     break;
    668   case EFI_HII_SIBT_STRING_UCS2:
    669   case EFI_HII_SIBT_STRING_UCS2_FONT:
    670   case EFI_HII_SIBT_STRINGS_UCS2:
    671   case EFI_HII_SIBT_STRINGS_UCS2_FONT:
    672     Status = GetUnicodeStringTextOrSize (String, StringTextPtr, StringSize);
    673     break;
    674   default:
    675     return EFI_NOT_FOUND;
    676   }
    677   if (EFI_ERROR (Status)) {
    678     return Status;
    679   }
    680 
    681   //
    682   // Get the string font. The FontId 0 is the default font for those string blocks which
    683   // do not specify a font identifier. If default font is not specified, return NULL.
    684   //
    685   if (StringFontInfo != NULL) {
    686     switch (BlockType) {
    687     case EFI_HII_SIBT_STRING_SCSU_FONT:
    688     case EFI_HII_SIBT_STRINGS_SCSU_FONT:
    689     case EFI_HII_SIBT_STRING_UCS2_FONT:
    690     case EFI_HII_SIBT_STRINGS_UCS2_FONT:
    691       FontId = *(StringBlockAddr + sizeof (EFI_HII_STRING_BLOCK));
    692       break;
    693     default:
    694       FontId = 0;
    695     }
    696     Status = GetStringFontInfo (StringPackage, FontId, StringFontInfo);
    697     if (Status == EFI_NOT_FOUND) {
    698         *StringFontInfo = NULL;
    699     }
    700   }
    701 
    702   return EFI_SUCCESS;
    703 }
    704 
    705 /**
    706   If GetStringBlock find the StringId's string is not saved in the exist string block,
    707   this function will create the UCS2 string block to save the string; also split the
    708   skip block into two or one skip block.
    709 
    710   This is a internal function.
    711 
    712   @param  StringPackage           Hii string package instance.
    713   @param  StartStringId           The first id in the skip block which StringId in the block.
    714   @param  StringId                The string's id, which is unique within
    715                                   PackageList.
    716   @param  BlockType               Output the block type of found string block.
    717   @param  StringBlockAddr         Output the block address of found string block.
    718   @param  FontBlock               whether this string block has font info.
    719 
    720   @retval EFI_SUCCESS            The string font is outputed successfully.
    721   @retval EFI_OUT_OF_RESOURCES   NO resource for the memory to save the new string block.
    722 
    723 **/
    724 EFI_STATUS
    725 InsertLackStringBlock (
    726   IN OUT HII_STRING_PACKAGE_INSTANCE         *StringPackage,
    727   IN EFI_STRING_ID                           StartStringId,
    728   IN EFI_STRING_ID                           StringId,
    729   IN OUT UINT8                               *BlockType,
    730   IN OUT UINT8                               **StringBlockAddr,
    731   IN BOOLEAN                                 FontBlock
    732   )
    733 {
    734   UINT8                                *BlockPtr;
    735   UINT8                                *StringBlock;
    736   UINT32                               SkipLen;
    737   UINT32                               OldBlockSize;
    738   UINT32                               NewBlockSize;
    739   UINT32                               FrontSkipNum;
    740   UINT32                               NewUCSBlockLen;
    741   UINT8                                *OldStringAddr;
    742   UINT32                               IdCount;
    743 
    744   FrontSkipNum  = 0;
    745   SkipLen       = 0;
    746   OldStringAddr = *StringBlockAddr;
    747 
    748   ASSERT (*BlockType == EFI_HII_SIBT_SKIP1 || *BlockType == EFI_HII_SIBT_SKIP2);
    749   //
    750   // Old skip block size.
    751   //
    752   if (*BlockType == EFI_HII_SIBT_SKIP1) {
    753     SkipLen = sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
    754     IdCount = *(UINT8*)(OldStringAddr + sizeof (EFI_HII_STRING_BLOCK));
    755   } else {
    756     SkipLen = sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
    757     IdCount = *(UINT16*)(OldStringAddr + sizeof (EFI_HII_STRING_BLOCK));
    758   }
    759 
    760   //
    761   // New create UCS or UCS2 block size.
    762   //
    763   if (FontBlock) {
    764     NewUCSBlockLen = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK);
    765   } else {
    766     NewUCSBlockLen = sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK);
    767   }
    768 
    769   OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
    770 
    771   if (StartStringId == StringId) {
    772     //
    773     // New block + [Skip block]
    774     //
    775     if (IdCount > 1) {
    776       NewBlockSize = OldBlockSize + NewUCSBlockLen;
    777     } else {
    778       NewBlockSize = OldBlockSize + NewUCSBlockLen - SkipLen;
    779     }
    780   } else if (StartStringId + IdCount - 1 == StringId){
    781     //
    782     // Skip block + New block
    783     //
    784     NewBlockSize = OldBlockSize + NewUCSBlockLen;
    785     FrontSkipNum = StringId - StartStringId;
    786   } else {
    787     //
    788     // Skip block + New block + [Skip block]
    789     //
    790     NewBlockSize = OldBlockSize + NewUCSBlockLen + SkipLen;
    791     FrontSkipNum = StringId - StartStringId;
    792   }
    793 
    794   StringBlock = (UINT8 *) AllocateZeroPool (NewBlockSize);
    795   if (StringBlock == NULL) {
    796     return EFI_OUT_OF_RESOURCES;
    797   }
    798 
    799   //
    800   // Copy old block in front of skip block.
    801   //
    802   CopyMem (StringBlock, StringPackage->StringBlock, OldStringAddr - StringPackage->StringBlock);
    803   BlockPtr = StringBlock + (OldStringAddr - StringPackage->StringBlock);
    804 
    805   if (FrontSkipNum > 0) {
    806     *BlockPtr = *BlockType;
    807     if (*BlockType == EFI_HII_SIBT_SKIP1) {
    808       *(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT8) FrontSkipNum;
    809     } else {
    810       *(UINT16 *)(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT16) FrontSkipNum;
    811     }
    812     BlockPtr += SkipLen;
    813   }
    814 
    815   //
    816   // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK
    817   //
    818   *StringBlockAddr = BlockPtr;
    819   if (FontBlock) {
    820     *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT;
    821   } else {
    822     *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
    823   }
    824   BlockPtr += NewUCSBlockLen;
    825 
    826   if (IdCount > FrontSkipNum + 1) {
    827     *BlockPtr = *BlockType;
    828     if (*BlockType == EFI_HII_SIBT_SKIP1) {
    829       *(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT8) (IdCount - FrontSkipNum - 1);
    830     } else {
    831       *(UINT16 *)(BlockPtr + sizeof (EFI_HII_STRING_BLOCK)) = (UINT16) (IdCount - FrontSkipNum - 1);
    832     }
    833     BlockPtr += SkipLen;
    834   }
    835 
    836   //
    837   // Append a EFI_HII_SIBT_END block to the end.
    838   //
    839   CopyMem (BlockPtr, OldStringAddr + SkipLen, OldBlockSize - (OldStringAddr - StringPackage->StringBlock) - SkipLen);
    840 
    841   if (FontBlock) {
    842     *BlockType = EFI_HII_SIBT_STRING_UCS2_FONT;
    843   } else {
    844     *BlockType = EFI_HII_SIBT_STRING_UCS2;
    845   }
    846   FreePool (StringPackage->StringBlock);
    847   StringPackage->StringBlock = StringBlock;
    848   StringPackage->StringPkgHdr->Header.Length += NewBlockSize - OldBlockSize;
    849 
    850   return EFI_SUCCESS;
    851 }
    852 
    853 /**
    854   Parse all string blocks to set a String specified by StringId.
    855 
    856   This is a internal function.
    857 
    858   @param  Private                HII database driver private structure.
    859   @param  StringPackage          HII string package instance.
    860   @param  StringId               The string's id, which is unique within
    861                                  PackageList.
    862   @param  String                 Points to the new null-terminated string.
    863   @param  StringFontInfo         Points to the input font info.
    864 
    865   @retval EFI_SUCCESS            The string was updated successfully.
    866   @retval EFI_NOT_FOUND          The string specified by StringId is not in the
    867                                  database.
    868   @retval EFI_INVALID_PARAMETER  The String or Language was NULL.
    869   @retval EFI_INVALID_PARAMETER  The specified StringFontInfo does not exist in
    870                                  current database.
    871   @retval EFI_OUT_OF_RESOURCES   The system is out of resources to accomplish the
    872                                  task.
    873 
    874 **/
    875 EFI_STATUS
    876 SetStringWorker (
    877   IN  HII_DATABASE_PRIVATE_DATA       *Private,
    878   IN OUT HII_STRING_PACKAGE_INSTANCE  *StringPackage,
    879   IN  EFI_STRING_ID                   StringId,
    880   IN  EFI_STRING                      String,
    881   IN  EFI_FONT_INFO                   *StringFontInfo OPTIONAL
    882   )
    883 {
    884   UINT8                                *StringTextPtr;
    885   UINT8                                BlockType;
    886   UINT8                                *StringBlockAddr;
    887   UINTN                                StringTextOffset;
    888   EFI_STATUS                           Status;
    889   UINT8                                *Block;
    890   UINT8                                *BlockPtr;
    891   UINTN                                BlockSize;
    892   UINTN                                OldBlockSize;
    893   HII_FONT_INFO                        *LocalFont;
    894   HII_GLOBAL_FONT_INFO                 *GlobalFont;
    895   BOOLEAN                              Referred;
    896   EFI_HII_SIBT_EXT2_BLOCK              Ext2;
    897   UINTN                                StringSize;
    898   UINTN                                TmpSize;
    899   EFI_STRING_ID                        StartStringId;
    900 
    901   StartStringId = 0;
    902   StringSize    = 0;
    903   ASSERT (Private != NULL && StringPackage != NULL && String != NULL);
    904   ASSERT (Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
    905   //
    906   // Find the specified string block
    907   //
    908   Status = FindStringBlock (
    909              Private,
    910              StringPackage,
    911              StringId,
    912              &BlockType,
    913              &StringBlockAddr,
    914              &StringTextOffset,
    915              NULL,
    916              &StartStringId
    917              );
    918   if (EFI_ERROR (Status) && (BlockType == EFI_HII_SIBT_SKIP1 || BlockType == EFI_HII_SIBT_SKIP2)) {
    919     Status = InsertLackStringBlock(StringPackage,
    920                           StartStringId,
    921                           StringId,
    922                           &BlockType,
    923                           &StringBlockAddr,
    924                           (BOOLEAN)(StringFontInfo != NULL)
    925                           );
    926     if (EFI_ERROR (Status)) {
    927       return Status;
    928     }
    929     if (StringFontInfo != NULL) {
    930       StringTextOffset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16);
    931     } else {
    932       StringTextOffset = sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) - sizeof (CHAR16);
    933     }
    934   }
    935 
    936   LocalFont  = NULL;
    937   GlobalFont = NULL;
    938   Referred   = FALSE;
    939 
    940   //
    941   // The input StringFontInfo should exist in current database if specified.
    942   //
    943   if (StringFontInfo != NULL) {
    944     if (!IsFontInfoExisted (Private, StringFontInfo, NULL, NULL, &GlobalFont)) {
    945       return EFI_INVALID_PARAMETER;
    946     } else {
    947       Referred = ReferFontInfoLocally (
    948                    Private,
    949                    StringPackage,
    950                    StringPackage->FontId,
    951                    FALSE,
    952                    GlobalFont,
    953                    &LocalFont
    954                    );
    955       if (!Referred) {
    956         StringPackage->FontId++;
    957       }
    958     }
    959     //
    960     // Update the FontId of the specified string block to input font info.
    961     //
    962     switch (BlockType) {
    963     case EFI_HII_SIBT_STRING_SCSU_FONT:
    964     case EFI_HII_SIBT_STRINGS_SCSU_FONT:
    965     case EFI_HII_SIBT_STRING_UCS2_FONT:
    966     case EFI_HII_SIBT_STRINGS_UCS2_FONT:
    967       *(StringBlockAddr + sizeof (EFI_HII_STRING_BLOCK)) = LocalFont->FontId;
    968       break;
    969     default:
    970       //
    971       // When modify the font info of these blocks, the block type should be updated
    972       // to contain font info thus the whole structure should be revised.
    973       // It is recommended to use tool to modify the block type not in the code.
    974       //
    975       return EFI_UNSUPPORTED;
    976     }
    977   }
    978 
    979   OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
    980 
    981   //
    982   // Set the string text and font.
    983   //
    984   StringTextPtr = StringBlockAddr + StringTextOffset;
    985   switch (BlockType) {
    986   case EFI_HII_SIBT_STRING_SCSU:
    987   case EFI_HII_SIBT_STRING_SCSU_FONT:
    988   case EFI_HII_SIBT_STRINGS_SCSU:
    989   case EFI_HII_SIBT_STRINGS_SCSU_FONT:
    990     BlockSize = OldBlockSize + StrLen (String);
    991     BlockSize -= AsciiStrSize ((CHAR8 *) StringTextPtr);
    992     Block = AllocateZeroPool (BlockSize);
    993     if (Block == NULL) {
    994       return EFI_OUT_OF_RESOURCES;
    995     }
    996 
    997     CopyMem (Block, StringPackage->StringBlock, StringTextPtr - StringPackage->StringBlock);
    998     BlockPtr = Block + (StringTextPtr - StringPackage->StringBlock);
    999 
   1000     while (*String != 0) {
   1001       *BlockPtr++ = (CHAR8) *String++;
   1002     }
   1003     *BlockPtr++ = 0;
   1004 
   1005 
   1006     TmpSize = OldBlockSize - (StringTextPtr - StringPackage->StringBlock) - AsciiStrSize ((CHAR8 *) StringTextPtr);
   1007     CopyMem (
   1008       BlockPtr,
   1009       StringTextPtr + AsciiStrSize ((CHAR8 *)StringTextPtr),
   1010       TmpSize
   1011       );
   1012 
   1013     FreePool (StringPackage->StringBlock);
   1014     StringPackage->StringBlock = Block;
   1015     StringPackage->StringPkgHdr->Header.Length += (UINT32) (BlockSize - OldBlockSize);
   1016     break;
   1017 
   1018   case EFI_HII_SIBT_STRING_UCS2:
   1019   case EFI_HII_SIBT_STRING_UCS2_FONT:
   1020   case EFI_HII_SIBT_STRINGS_UCS2:
   1021   case EFI_HII_SIBT_STRINGS_UCS2_FONT:
   1022     //
   1023     // Use StrSize to store the size of the specified string, including the NULL
   1024     // terminator.
   1025     //
   1026     GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
   1027 
   1028     BlockSize = OldBlockSize + StrSize (String) - StringSize;
   1029     Block = AllocateZeroPool (BlockSize);
   1030     if (Block == NULL) {
   1031       return EFI_OUT_OF_RESOURCES;
   1032     }
   1033 
   1034     CopyMem (Block, StringPackage->StringBlock, StringTextPtr - StringPackage->StringBlock);
   1035     BlockPtr = Block + (StringTextPtr - StringPackage->StringBlock);
   1036 
   1037     CopyMem (BlockPtr, String, StrSize (String));
   1038     BlockPtr += StrSize (String);
   1039 
   1040     CopyMem (
   1041       BlockPtr,
   1042       StringTextPtr + StringSize,
   1043       OldBlockSize - (StringTextPtr - StringPackage->StringBlock) - StringSize
   1044       );
   1045 
   1046     FreePool (StringPackage->StringBlock);
   1047     StringPackage->StringBlock = Block;
   1048     StringPackage->StringPkgHdr->Header.Length += (UINT32) (BlockSize - OldBlockSize);
   1049     break;
   1050 
   1051   default:
   1052     return EFI_NOT_FOUND;
   1053   }
   1054 
   1055   //
   1056   // Insert a new EFI_HII_SIBT_FONT_BLOCK to the header of string block, if incoming
   1057   // StringFontInfo does not exist in current string package.
   1058   //
   1059   // This new block does not impact on the value of StringId.
   1060   //
   1061   //
   1062   if (StringFontInfo == NULL || Referred) {
   1063     return EFI_SUCCESS;
   1064   }
   1065 
   1066   OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
   1067   BlockSize = OldBlockSize + sizeof (EFI_HII_SIBT_FONT_BLOCK) - sizeof (CHAR16) +
   1068               StrSize (GlobalFont->FontInfo->FontName);
   1069 
   1070   Block = AllocateZeroPool (BlockSize);
   1071   if (Block == NULL) {
   1072     return EFI_OUT_OF_RESOURCES;
   1073   }
   1074 
   1075   BlockPtr = Block;
   1076   Ext2.Header.BlockType = EFI_HII_SIBT_EXT2;
   1077   Ext2.BlockType2       = EFI_HII_SIBT_FONT;
   1078   Ext2.Length           = (UINT16) (BlockSize - OldBlockSize);
   1079   CopyMem (BlockPtr, &Ext2, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
   1080   BlockPtr += sizeof (EFI_HII_SIBT_EXT2_BLOCK);
   1081 
   1082   *BlockPtr = LocalFont->FontId;
   1083   BlockPtr ++;
   1084   CopyMem (BlockPtr, &GlobalFont->FontInfo->FontSize, sizeof (UINT16));
   1085   BlockPtr += sizeof (UINT16);
   1086   CopyMem (BlockPtr, &GlobalFont->FontInfo->FontStyle, sizeof (UINT32));
   1087   BlockPtr += sizeof (UINT32);
   1088   CopyMem (
   1089     BlockPtr,
   1090     GlobalFont->FontInfo->FontName,
   1091     StrSize (GlobalFont->FontInfo->FontName)
   1092     );
   1093   BlockPtr += StrSize (GlobalFont->FontInfo->FontName);
   1094 
   1095   CopyMem (BlockPtr, StringPackage->StringBlock, OldBlockSize);
   1096 
   1097   FreePool (StringPackage->StringBlock);
   1098   StringPackage->StringBlock = Block;
   1099   StringPackage->StringPkgHdr->Header.Length += Ext2.Length;
   1100 
   1101   return EFI_SUCCESS;
   1102 
   1103 }
   1104 
   1105 
   1106 /**
   1107   This function adds the string String to the group of strings owned by PackageList, with the
   1108   specified font information StringFontInfo and returns a new string id.
   1109   The new string identifier is guaranteed to be unique within the package list.
   1110   That new string identifier is reserved for all languages in the package list.
   1111 
   1112 
   1113   @param  This                   A pointer to the EFI_HII_STRING_PROTOCOL instance.
   1114   @param  PackageList            Handle of the package list where this string will
   1115                                  be added.
   1116   @param  StringId               On return, contains the new strings id, which is
   1117                                  unique within PackageList.
   1118   @param  Language               Points to the language for the new string.
   1119   @param  LanguageName           Points to the printable language name to associate
   1120                                  with the passed in  Language field.If LanguageName
   1121                                  is not NULL and the string package header's
   1122                                  LanguageName  associated with a given Language is
   1123                                  not zero, the LanguageName being passed  in will
   1124                                  be ignored.
   1125   @param  String                 Points to the new null-terminated string.
   1126   @param  StringFontInfo         Points to the new string's font information or
   1127                                  NULL if the string should have the default system
   1128                                  font, size and style.
   1129 
   1130   @retval EFI_SUCCESS            The new string was added successfully.
   1131   @retval EFI_NOT_FOUND          The specified PackageList could not be found in
   1132                                  database.
   1133   @retval EFI_OUT_OF_RESOURCES   Could not add the string due to lack of resources.
   1134   @retval EFI_INVALID_PARAMETER  String is NULL or StringId is NULL or Language is
   1135                                  NULL.
   1136   @retval EFI_INVALID_PARAMETER  The specified StringFontInfo does not exist in
   1137                                  current database.
   1138 
   1139 **/
   1140 EFI_STATUS
   1141 EFIAPI
   1142 HiiNewString (
   1143   IN  CONST EFI_HII_STRING_PROTOCOL   *This,
   1144   IN  EFI_HII_HANDLE                  PackageList,
   1145   OUT EFI_STRING_ID                   *StringId,
   1146   IN  CONST CHAR8                     *Language,
   1147   IN  CONST CHAR16                    *LanguageName, OPTIONAL
   1148   IN  CONST EFI_STRING                String,
   1149   IN  CONST EFI_FONT_INFO             *StringFontInfo OPTIONAL
   1150   )
   1151 {
   1152   EFI_STATUS                          Status;
   1153   LIST_ENTRY                          *Link;
   1154   HII_DATABASE_PRIVATE_DATA           *Private;
   1155   HII_DATABASE_RECORD                 *DatabaseRecord;
   1156   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
   1157   HII_STRING_PACKAGE_INSTANCE         *StringPackage;
   1158   UINT32                              HeaderSize;
   1159   UINT32                              BlockSize;
   1160   UINT32                              OldBlockSize;
   1161   UINT8                               *StringBlock;
   1162   UINT8                               *BlockPtr;
   1163   UINT32                              Ucs2BlockSize;
   1164   UINT32                              FontBlockSize;
   1165   UINT32                              Ucs2FontBlockSize;
   1166   EFI_HII_SIBT_EXT2_BLOCK             Ext2;
   1167   HII_FONT_INFO                       *LocalFont;
   1168   HII_GLOBAL_FONT_INFO                *GlobalFont;
   1169   EFI_STRING_ID                       NewStringId;
   1170   EFI_STRING_ID                       NextStringId;
   1171   EFI_STRING_ID                       Index;
   1172   HII_STRING_PACKAGE_INSTANCE         *MatchStringPackage;
   1173   BOOLEAN                             NewStringPackageCreated;
   1174 
   1175 
   1176   if (This == NULL || String == NULL || StringId == NULL || Language == NULL || PackageList == NULL) {
   1177     return EFI_INVALID_PARAMETER;
   1178   }
   1179 
   1180   if (!IsHiiHandleValid (PackageList)) {
   1181     return EFI_NOT_FOUND;
   1182   }
   1183 
   1184   Private    = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
   1185   GlobalFont = NULL;
   1186 
   1187   //
   1188   // If StringFontInfo specify a paritcular font, it should exist in current database.
   1189   //
   1190   if (StringFontInfo != NULL) {
   1191     if (!IsFontInfoExisted (Private, (EFI_FONT_INFO *) StringFontInfo, NULL, NULL, &GlobalFont)) {
   1192       return EFI_INVALID_PARAMETER;
   1193     }
   1194   }
   1195 
   1196   //
   1197   // Get the matching package list.
   1198   //
   1199   PackageListNode = NULL;
   1200   for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
   1201     DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
   1202     if (DatabaseRecord->Handle == PackageList) {
   1203       PackageListNode = DatabaseRecord->PackageList;
   1204       break;
   1205     }
   1206   }
   1207   if (PackageListNode == NULL) {
   1208     return EFI_NOT_FOUND;
   1209   }
   1210 
   1211   Status = EFI_SUCCESS;
   1212   NewStringPackageCreated = FALSE;
   1213   NewStringId   = 0;
   1214   NextStringId  = 0;
   1215   StringPackage = NULL;
   1216   MatchStringPackage = NULL;
   1217   for (Link = PackageListNode->StringPkgHdr.ForwardLink;
   1218        Link != &PackageListNode->StringPkgHdr;
   1219        Link = Link->ForwardLink
   1220       ) {
   1221     StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
   1222     //
   1223     // Create a string block and corresponding font block if exists, then append them
   1224     // to the end of the string package.
   1225     //
   1226     Status = FindStringBlock (
   1227                Private,
   1228                StringPackage,
   1229                0,
   1230                NULL,
   1231                NULL,
   1232                NULL,
   1233                &NextStringId,
   1234                NULL
   1235                );
   1236     if (EFI_ERROR (Status)) {
   1237       goto Done;
   1238     }
   1239     //
   1240     // Make sure that new StringId is same in all String Packages for the different language.
   1241     //
   1242     if (NewStringId != 0 && NewStringId != NextStringId) {
   1243       ASSERT (FALSE);
   1244       Status = EFI_INVALID_PARAMETER;
   1245       goto Done;
   1246     }
   1247     NewStringId = NextStringId;
   1248     //
   1249     // Get the matched string package with language.
   1250     //
   1251     if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) {
   1252       MatchStringPackage = StringPackage;
   1253     } else {
   1254       OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
   1255       //
   1256       // Create a blank EFI_HII_SIBT_STRING_UCS2_BLOCK to reserve new string ID.
   1257       //
   1258       Ucs2BlockSize = (UINT32) sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK);
   1259 
   1260       StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2BlockSize);
   1261       if (StringBlock == NULL) {
   1262         Status = EFI_OUT_OF_RESOURCES;
   1263         goto Done;
   1264       }
   1265       //
   1266       // Copy original string blocks, except the EFI_HII_SIBT_END.
   1267       //
   1268       CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
   1269       //
   1270       // Create a blank EFI_HII_SIBT_STRING_UCS2 block
   1271       //
   1272       BlockPtr  = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
   1273       *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
   1274       BlockPtr  += sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK);
   1275 
   1276       //
   1277       // Append a EFI_HII_SIBT_END block to the end.
   1278       //
   1279       *BlockPtr = EFI_HII_SIBT_END;
   1280       FreePool (StringPackage->StringBlock);
   1281       StringPackage->StringBlock = StringBlock;
   1282       StringPackage->StringPkgHdr->Header.Length += Ucs2BlockSize;
   1283       PackageListNode->PackageListHdr.PackageLength += Ucs2BlockSize;
   1284     }
   1285   }
   1286   if (NewStringId == 0) {
   1287     //
   1288     // No string package is found.
   1289     // Create new string package. StringId 1 is reserved for Language Name string.
   1290     //
   1291     *StringId = 2;
   1292   } else {
   1293     //
   1294     // Set new StringId
   1295     //
   1296     *StringId = (EFI_STRING_ID) (NewStringId + 1);
   1297   }
   1298 
   1299   if (MatchStringPackage != NULL) {
   1300     StringPackage = MatchStringPackage;
   1301   } else {
   1302     //
   1303     // LanguageName is required to create a new string package.
   1304     //
   1305     if (LanguageName == NULL) {
   1306       Status = EFI_INVALID_PARAMETER;
   1307       goto Done;
   1308     }
   1309 
   1310     StringPackage = AllocateZeroPool (sizeof (HII_STRING_PACKAGE_INSTANCE));
   1311     if (StringPackage == NULL) {
   1312       Status = EFI_OUT_OF_RESOURCES;
   1313       goto Done;
   1314     }
   1315 
   1316     StringPackage->Signature   = HII_STRING_PACKAGE_SIGNATURE;
   1317     StringPackage->MaxStringId = *StringId;
   1318     StringPackage->FontId      = 0;
   1319     InitializeListHead (&StringPackage->FontInfoList);
   1320 
   1321     //
   1322     // Fill in the string package header
   1323     //
   1324     HeaderSize = (UINT32) (AsciiStrSize ((CHAR8 *) Language) - 1 + sizeof (EFI_HII_STRING_PACKAGE_HDR));
   1325     StringPackage->StringPkgHdr = AllocateZeroPool (HeaderSize);
   1326     if (StringPackage->StringPkgHdr == NULL) {
   1327       FreePool (StringPackage);
   1328       Status = EFI_OUT_OF_RESOURCES;
   1329       goto Done;
   1330     }
   1331     StringPackage->StringPkgHdr->Header.Type      = EFI_HII_PACKAGE_STRINGS;
   1332     StringPackage->StringPkgHdr->HdrSize          = HeaderSize;
   1333     StringPackage->StringPkgHdr->StringInfoOffset = HeaderSize;
   1334     CopyMem (StringPackage->StringPkgHdr->LanguageWindow, mLanguageWindow, 16 * sizeof (CHAR16));
   1335     StringPackage->StringPkgHdr->LanguageName     = 1;
   1336     AsciiStrCpyS (StringPackage->StringPkgHdr->Language, (HeaderSize - OFFSET_OF(EFI_HII_STRING_PACKAGE_HDR,Language)) / sizeof (CHAR8), (CHAR8 *) Language);
   1337 
   1338     //
   1339     // Calculate the length of the string blocks, including string block to record
   1340     // printable language full name and EFI_HII_SIBT_END_BLOCK.
   1341     //
   1342     Ucs2BlockSize = (UINT32) (StrSize ((CHAR16 *) LanguageName) +
   1343                               (*StringId - 1) * sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) - sizeof (CHAR16));
   1344 
   1345     BlockSize     = Ucs2BlockSize + sizeof (EFI_HII_SIBT_END_BLOCK);
   1346     StringPackage->StringBlock = (UINT8 *) AllocateZeroPool (BlockSize);
   1347     if (StringPackage->StringBlock == NULL) {
   1348       FreePool (StringPackage->StringPkgHdr);
   1349       FreePool (StringPackage);
   1350       Status = EFI_OUT_OF_RESOURCES;
   1351       goto Done;
   1352     }
   1353 
   1354     //
   1355     // Insert the string block of printable language full name
   1356     //
   1357     BlockPtr  = StringPackage->StringBlock;
   1358     *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
   1359     BlockPtr  += sizeof (EFI_HII_STRING_BLOCK);
   1360     CopyMem (BlockPtr, (EFI_STRING) LanguageName, StrSize ((EFI_STRING) LanguageName));
   1361     BlockPtr += StrSize ((EFI_STRING) LanguageName);
   1362     for (Index = 2; Index <= *StringId - 1; Index ++) {
   1363       *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
   1364       BlockPtr += sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK);
   1365     }
   1366     //
   1367     // Insert the end block
   1368     //
   1369     *BlockPtr = EFI_HII_SIBT_END;
   1370 
   1371     //
   1372     // Append this string package node to string package array in this package list.
   1373     //
   1374     StringPackage->StringPkgHdr->Header.Length    = HeaderSize + BlockSize;
   1375     PackageListNode->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length;
   1376     InsertTailList (&PackageListNode->StringPkgHdr, &StringPackage->StringEntry);
   1377     NewStringPackageCreated = TRUE;
   1378   }
   1379 
   1380   OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
   1381 
   1382   if (StringFontInfo == NULL) {
   1383     //
   1384     // Create a EFI_HII_SIBT_STRING_UCS2_BLOCK since font info is not specified.
   1385     //
   1386     Ucs2BlockSize = (UINT32) (StrSize (String) + sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK)
   1387                               - sizeof (CHAR16));
   1388 
   1389     StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2BlockSize);
   1390     if (StringBlock == NULL) {
   1391       Status = EFI_OUT_OF_RESOURCES;
   1392       goto Done;
   1393     }
   1394     //
   1395     // Copy original string blocks, except the EFI_HII_SIBT_END.
   1396     //
   1397     CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
   1398     //
   1399     // Create a EFI_HII_SIBT_STRING_UCS2 block
   1400     //
   1401     BlockPtr  = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
   1402     *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
   1403     BlockPtr  += sizeof (EFI_HII_STRING_BLOCK);
   1404     CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String));
   1405     BlockPtr += StrSize ((EFI_STRING) String);
   1406 
   1407     //
   1408     // Append a EFI_HII_SIBT_END block to the end.
   1409     //
   1410     *BlockPtr = EFI_HII_SIBT_END;
   1411     FreePool (StringPackage->StringBlock);
   1412     StringPackage->StringBlock = StringBlock;
   1413     StringPackage->StringPkgHdr->Header.Length += Ucs2BlockSize;
   1414     PackageListNode->PackageListHdr.PackageLength += Ucs2BlockSize;
   1415 
   1416   } else {
   1417     //
   1418     // StringFontInfo is specified here. If there is a EFI_HII_SIBT_FONT_BLOCK
   1419     // which refers to this font info, create a EFI_HII_SIBT_STRING_UCS2_FONT block
   1420     // only. Otherwise create a EFI_HII_SIBT_FONT block with a EFI_HII_SIBT_STRING
   1421     // _UCS2_FONT block.
   1422     //
   1423     Ucs2FontBlockSize = (UINT32) (StrSize (String) + sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) -
   1424                                   sizeof (CHAR16));
   1425     if (ReferFontInfoLocally (Private, StringPackage, StringPackage->FontId, FALSE, GlobalFont, &LocalFont)) {
   1426       //
   1427       // Create a EFI_HII_SIBT_STRING_UCS2_FONT block only.
   1428       //
   1429       StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2FontBlockSize);
   1430       if (StringBlock == NULL) {
   1431         Status = EFI_OUT_OF_RESOURCES;
   1432         goto Done;
   1433       }
   1434       //
   1435       // Copy original string blocks, except the EFI_HII_SIBT_END.
   1436       //
   1437       CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
   1438       //
   1439       // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK
   1440       //
   1441       BlockPtr  = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
   1442       *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT;
   1443       BlockPtr  += sizeof (EFI_HII_STRING_BLOCK);
   1444       *BlockPtr = LocalFont->FontId;
   1445       BlockPtr ++;
   1446       CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String));
   1447       BlockPtr += StrSize ((EFI_STRING) String);
   1448 
   1449       //
   1450       // Append a EFI_HII_SIBT_END block to the end.
   1451       //
   1452       *BlockPtr = EFI_HII_SIBT_END;
   1453       FreePool (StringPackage->StringBlock);
   1454       StringPackage->StringBlock = StringBlock;
   1455       StringPackage->StringPkgHdr->Header.Length += Ucs2FontBlockSize;
   1456       PackageListNode->PackageListHdr.PackageLength += Ucs2FontBlockSize;
   1457 
   1458     } else {
   1459       //
   1460       // EFI_HII_SIBT_FONT_BLOCK does not exist in current string package, so
   1461       // create a EFI_HII_SIBT_FONT block to record the font info, then generate
   1462       // a EFI_HII_SIBT_STRING_UCS2_FONT block to record the incoming string.
   1463       //
   1464       FontBlockSize = (UINT32) (StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName) +
   1465                                 sizeof (EFI_HII_SIBT_FONT_BLOCK) - sizeof (CHAR16));
   1466       StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + FontBlockSize + Ucs2FontBlockSize);
   1467       if (StringBlock == NULL) {
   1468         Status = EFI_OUT_OF_RESOURCES;
   1469         goto Done;
   1470       }
   1471       //
   1472       // Copy original string blocks, except the EFI_HII_SIBT_END.
   1473       //
   1474       CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
   1475 
   1476       //
   1477       // Create a EFI_HII_SIBT_FONT block firstly and then backup its info in string
   1478       // package instance for future reference.
   1479       //
   1480       BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
   1481 
   1482       Ext2.Header.BlockType = EFI_HII_SIBT_EXT2;
   1483       Ext2.BlockType2       = EFI_HII_SIBT_FONT;
   1484       Ext2.Length           = (UINT16) FontBlockSize;
   1485       CopyMem (BlockPtr, &Ext2, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
   1486       BlockPtr += sizeof (EFI_HII_SIBT_EXT2_BLOCK);
   1487 
   1488       *BlockPtr = LocalFont->FontId;
   1489       BlockPtr ++;
   1490       CopyMem (BlockPtr, &((EFI_FONT_INFO *) StringFontInfo)->FontSize, sizeof (UINT16));
   1491       BlockPtr += sizeof (UINT16);
   1492       CopyMem (BlockPtr, &((EFI_FONT_INFO *) StringFontInfo)->FontStyle, sizeof (EFI_HII_FONT_STYLE));
   1493       BlockPtr += sizeof (EFI_HII_FONT_STYLE);
   1494       CopyMem (
   1495         BlockPtr,
   1496         &((EFI_FONT_INFO *) StringFontInfo)->FontName,
   1497         StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName)
   1498         );
   1499       BlockPtr += StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName);
   1500       //
   1501       // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK
   1502       //
   1503       *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT;
   1504       BlockPtr  += sizeof (EFI_HII_STRING_BLOCK);
   1505       *BlockPtr = LocalFont->FontId;
   1506       BlockPtr  ++;
   1507       CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String));
   1508       BlockPtr += StrSize ((EFI_STRING) String);
   1509 
   1510       //
   1511       // Append a EFI_HII_SIBT_END block to the end.
   1512       //
   1513       *BlockPtr = EFI_HII_SIBT_END;
   1514       FreePool (StringPackage->StringBlock);
   1515       StringPackage->StringBlock = StringBlock;
   1516       StringPackage->StringPkgHdr->Header.Length += FontBlockSize + Ucs2FontBlockSize;
   1517       PackageListNode->PackageListHdr.PackageLength += FontBlockSize + Ucs2FontBlockSize;
   1518 
   1519       //
   1520       // Increase the FontId to make it unique since we already add
   1521       // a EFI_HII_SIBT_FONT block to this string package.
   1522       //
   1523       StringPackage->FontId++;
   1524     }
   1525   }
   1526 
   1527 Done:
   1528   if (!EFI_ERROR (Status) && NewStringPackageCreated) {
   1529     //
   1530     // Trigger any registered notification function for new string package
   1531     //
   1532     Status = InvokeRegisteredFunction (
   1533       Private,
   1534       EFI_HII_DATABASE_NOTIFY_NEW_PACK,
   1535       (VOID *) StringPackage,
   1536       EFI_HII_PACKAGE_STRINGS,
   1537       PackageList
   1538       );
   1539   }
   1540 
   1541   if (!EFI_ERROR (Status)) {
   1542     //
   1543     // Update MaxString Id to new StringId
   1544     //
   1545     for (Link = PackageListNode->StringPkgHdr.ForwardLink;
   1546       Link != &PackageListNode->StringPkgHdr;
   1547       Link = Link->ForwardLink
   1548       ) {
   1549         StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
   1550         StringPackage->MaxStringId = *StringId;
   1551     }
   1552   } else if (NewStringPackageCreated) {
   1553     //
   1554     // Free the allocated new string Package when new string can't be added.
   1555     //
   1556     RemoveEntryList (&StringPackage->StringEntry);
   1557     FreePool (StringPackage->StringBlock);
   1558     FreePool (StringPackage->StringPkgHdr);
   1559     FreePool (StringPackage);
   1560   }
   1561 
   1562   return Status;
   1563 }
   1564 
   1565 
   1566 /**
   1567   This function retrieves the string specified by StringId which is associated
   1568   with the specified PackageList in the language Language and copies it into
   1569   the buffer specified by String.
   1570 
   1571   @param  This                   A pointer to the EFI_HII_STRING_PROTOCOL instance.
   1572   @param  Language               Points to the language for the retrieved string.
   1573   @param  PackageList            The package list in the HII database to search for
   1574                                  the  specified string.
   1575   @param  StringId               The string's id, which is unique within
   1576                                  PackageList.
   1577   @param  String                 Points to the new null-terminated string.
   1578   @param  StringSize             On entry, points to the size of the buffer pointed
   1579                                  to by  String, in bytes. On return, points to the
   1580                                  length of the string, in bytes.
   1581   @param  StringFontInfo         If not NULL, points to the string's font
   1582                                  information.  It's caller's responsibility to free
   1583                                  this buffer.
   1584 
   1585   @retval EFI_SUCCESS            The string was returned successfully.
   1586   @retval EFI_NOT_FOUND          The string specified by StringId is not available.
   1587   @retval EFI_NOT_FOUND          The string specified by StringId is available but
   1588                                                 not in the specified language.
   1589                                                 The specified PackageList is not in the database.
   1590   @retval EFI_INVALID_LANGUAGE   - The string specified by StringId is available but
   1591   @retval EFI_BUFFER_TOO_SMALL   The buffer specified by StringSize is too small to
   1592                                   hold the string.
   1593   @retval EFI_INVALID_PARAMETER  The Language or StringSize was NULL.
   1594   @retval EFI_INVALID_PARAMETER  The value referenced by StringSize was not zero and String was NULL.
   1595   @retval EFI_OUT_OF_RESOURCES   There were insufficient resources to complete the
   1596                                  request.
   1597 
   1598 **/
   1599 EFI_STATUS
   1600 EFIAPI
   1601 HiiGetString (
   1602   IN  CONST EFI_HII_STRING_PROTOCOL   *This,
   1603   IN  CONST CHAR8                     *Language,
   1604   IN  EFI_HII_HANDLE                  PackageList,
   1605   IN  EFI_STRING_ID                   StringId,
   1606   OUT EFI_STRING                      String,
   1607   IN  OUT UINTN                       *StringSize,
   1608   OUT EFI_FONT_INFO                   **StringFontInfo OPTIONAL
   1609   )
   1610 {
   1611   EFI_STATUS                          Status;
   1612   LIST_ENTRY                          *Link;
   1613   HII_DATABASE_PRIVATE_DATA           *Private;
   1614   HII_DATABASE_RECORD                 *DatabaseRecord;
   1615   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
   1616   HII_STRING_PACKAGE_INSTANCE         *StringPackage;
   1617 
   1618   if (This == NULL || Language == NULL || StringId < 1 || StringSize == NULL || PackageList == NULL) {
   1619     return EFI_INVALID_PARAMETER;
   1620   }
   1621 
   1622   if (String == NULL && *StringSize != 0) {
   1623     return EFI_INVALID_PARAMETER;
   1624   }
   1625 
   1626   if (!IsHiiHandleValid (PackageList)) {
   1627     return EFI_NOT_FOUND;
   1628   }
   1629 
   1630   Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
   1631   PackageListNode = NULL;
   1632 
   1633   for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
   1634     DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
   1635     if (DatabaseRecord->Handle == PackageList) {
   1636       PackageListNode = DatabaseRecord->PackageList;
   1637       break;
   1638     }
   1639   }
   1640 
   1641   if (PackageListNode != NULL) {
   1642     //
   1643     // First search: to match the StringId in the specified language.
   1644     //
   1645     for (Link =  PackageListNode->StringPkgHdr.ForwardLink;
   1646          Link != &PackageListNode->StringPkgHdr;
   1647          Link =  Link->ForwardLink
   1648         ) {
   1649         StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
   1650         if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) {
   1651           Status = GetStringWorker (Private, StringPackage, StringId, String, StringSize, StringFontInfo);
   1652           if (Status != EFI_NOT_FOUND) {
   1653             return Status;
   1654           }
   1655         }
   1656       }
   1657       //
   1658       // Second search: to match the StringId in other available languages if exist.
   1659       //
   1660       for (Link =  PackageListNode->StringPkgHdr.ForwardLink;
   1661            Link != &PackageListNode->StringPkgHdr;
   1662            Link =  Link->ForwardLink
   1663           ) {
   1664       StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
   1665       Status = GetStringWorker (Private, StringPackage, StringId, NULL, NULL, NULL);
   1666       if (!EFI_ERROR (Status)) {
   1667         return EFI_INVALID_LANGUAGE;
   1668       }
   1669     }
   1670   }
   1671 
   1672   return EFI_NOT_FOUND;
   1673 }
   1674 
   1675 
   1676 
   1677 /**
   1678   This function updates the string specified by StringId in the specified PackageList to the text
   1679   specified by String and, optionally, the font information specified by StringFontInfo.
   1680 
   1681   @param  This                   A pointer to the EFI_HII_STRING_PROTOCOL instance.
   1682   @param  PackageList            The package list containing the strings.
   1683   @param  StringId               The string's id, which is unique within
   1684                                  PackageList.
   1685   @param  Language               Points to the language for the updated string.
   1686   @param  String                 Points to the new null-terminated string.
   1687   @param  StringFontInfo         Points to the string's font information or NULL if
   1688                                  the  string font information is not changed.
   1689 
   1690   @retval EFI_SUCCESS            The string was updated successfully.
   1691   @retval EFI_NOT_FOUND          The string specified by StringId is not in the
   1692                                  database.
   1693   @retval EFI_INVALID_PARAMETER  The String or Language was NULL.
   1694   @retval EFI_INVALID_PARAMETER  The specified StringFontInfo does not exist in
   1695                                  current database.
   1696   @retval EFI_OUT_OF_RESOURCES   The system is out of resources to accomplish the
   1697                                  task.
   1698 
   1699 **/
   1700 EFI_STATUS
   1701 EFIAPI
   1702 HiiSetString (
   1703   IN CONST EFI_HII_STRING_PROTOCOL    *This,
   1704   IN EFI_HII_HANDLE                   PackageList,
   1705   IN EFI_STRING_ID                    StringId,
   1706   IN CONST CHAR8                      *Language,
   1707   IN CONST EFI_STRING                 String,
   1708   IN CONST EFI_FONT_INFO              *StringFontInfo OPTIONAL
   1709   )
   1710 {
   1711   EFI_STATUS                          Status;
   1712   LIST_ENTRY                          *Link;
   1713   HII_DATABASE_PRIVATE_DATA           *Private;
   1714   HII_DATABASE_RECORD                 *DatabaseRecord;
   1715   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
   1716   HII_STRING_PACKAGE_INSTANCE         *StringPackage;
   1717   UINT32                              OldPackageLen;
   1718 
   1719   if (This == NULL || Language == NULL || StringId < 1 || String == NULL || PackageList == NULL) {
   1720     return EFI_INVALID_PARAMETER;
   1721   }
   1722 
   1723   if (!IsHiiHandleValid (PackageList)) {
   1724     return EFI_NOT_FOUND;
   1725   }
   1726 
   1727   Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
   1728   PackageListNode = NULL;
   1729 
   1730   for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
   1731     DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
   1732     if (DatabaseRecord->Handle == PackageList) {
   1733       PackageListNode = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (DatabaseRecord->PackageList);
   1734     }
   1735   }
   1736 
   1737   if (PackageListNode != NULL) {
   1738     for (Link =  PackageListNode->StringPkgHdr.ForwardLink;
   1739          Link != &PackageListNode->StringPkgHdr;
   1740          Link =  Link->ForwardLink
   1741         ) {
   1742       StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
   1743       if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) {
   1744         OldPackageLen = StringPackage->StringPkgHdr->Header.Length;
   1745         Status = SetStringWorker (
   1746                    Private,
   1747                    StringPackage,
   1748                    StringId,
   1749                    (EFI_STRING) String,
   1750                    (EFI_FONT_INFO *) StringFontInfo
   1751                    );
   1752         if (EFI_ERROR (Status)) {
   1753           return Status;
   1754         }
   1755         PackageListNode->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length - OldPackageLen;
   1756         return EFI_SUCCESS;
   1757       }
   1758     }
   1759   }
   1760 
   1761   return EFI_NOT_FOUND;
   1762 }
   1763 
   1764 
   1765 
   1766 /**
   1767   This function returns the list of supported languages, in the format specified
   1768   in Appendix M of UEFI 2.1 spec.
   1769 
   1770   @param  This                   A pointer to the EFI_HII_STRING_PROTOCOL instance.
   1771   @param  PackageList            The package list to examine.
   1772   @param  Languages              Points to the buffer to hold the returned
   1773                                  null-terminated ASCII string.
   1774   @param  LanguagesSize          On entry, points to the size of the buffer pointed
   1775                                  to by  Languages, in bytes. On  return, points to
   1776                                  the length of Languages, in bytes.
   1777 
   1778   @retval EFI_SUCCESS            The languages were returned successfully.
   1779   @retval EFI_INVALID_PARAMETER  The LanguagesSize was NULL.
   1780   @retval EFI_INVALID_PARAMETER  The value referenced by LanguagesSize is not zero and Languages is NULL.
   1781   @retval EFI_BUFFER_TOO_SMALL   The LanguagesSize is too small to hold the list of
   1782                                   supported languages. LanguageSize is updated to
   1783                                  contain the required size.
   1784   @retval EFI_NOT_FOUND          Could not find string package in specified
   1785                                  packagelist.
   1786 
   1787 **/
   1788 EFI_STATUS
   1789 EFIAPI
   1790 HiiGetLanguages (
   1791   IN CONST EFI_HII_STRING_PROTOCOL    *This,
   1792   IN EFI_HII_HANDLE                   PackageList,
   1793   IN OUT CHAR8                        *Languages,
   1794   IN OUT UINTN                        *LanguagesSize
   1795   )
   1796 {
   1797   LIST_ENTRY                          *Link;
   1798   HII_DATABASE_PRIVATE_DATA           *Private;
   1799   HII_DATABASE_RECORD                 *DatabaseRecord;
   1800   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
   1801   HII_STRING_PACKAGE_INSTANCE         *StringPackage;
   1802   UINTN                               ResultSize;
   1803 
   1804   if (This == NULL || LanguagesSize == NULL || PackageList == NULL) {
   1805     return EFI_INVALID_PARAMETER;
   1806   }
   1807   if (*LanguagesSize != 0 && Languages == NULL) {
   1808     return EFI_INVALID_PARAMETER;
   1809   }
   1810   if (!IsHiiHandleValid (PackageList)) {
   1811     return EFI_NOT_FOUND;
   1812   }
   1813 
   1814   Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
   1815 
   1816   PackageListNode = NULL;
   1817   for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
   1818     DatabaseRecord  = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
   1819     if (DatabaseRecord->Handle == PackageList) {
   1820       PackageListNode = DatabaseRecord->PackageList;
   1821       break;
   1822     }
   1823   }
   1824   if (PackageListNode == NULL) {
   1825     return EFI_NOT_FOUND;
   1826   }
   1827 
   1828   //
   1829   // Search the languages in the specified packagelist.
   1830   //
   1831   ResultSize = 0;
   1832   for (Link = PackageListNode->StringPkgHdr.ForwardLink;
   1833        Link != &PackageListNode->StringPkgHdr;
   1834        Link = Link->ForwardLink
   1835       ) {
   1836     StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
   1837     ResultSize += AsciiStrSize (StringPackage->StringPkgHdr->Language);
   1838     if (ResultSize <= *LanguagesSize) {
   1839       AsciiStrCpyS (Languages, *LanguagesSize / sizeof (CHAR8), StringPackage->StringPkgHdr->Language);
   1840       Languages += AsciiStrSize (StringPackage->StringPkgHdr->Language);
   1841       *(Languages - 1) = L';';
   1842     }
   1843   }
   1844   if (ResultSize == 0) {
   1845     return EFI_NOT_FOUND;
   1846   }
   1847 
   1848   if (*LanguagesSize < ResultSize) {
   1849     *LanguagesSize = ResultSize;
   1850     return EFI_BUFFER_TOO_SMALL;
   1851   }
   1852 
   1853   *(Languages - 1) = 0;
   1854   return EFI_SUCCESS;
   1855 }
   1856 
   1857 
   1858 /**
   1859   Each string package has associated with it a single primary language and zero
   1860   or more secondary languages. This routine returns the secondary languages
   1861   associated with a package list.
   1862 
   1863   @param  This                   A pointer to the EFI_HII_STRING_PROTOCOL instance.
   1864   @param  PackageList            The package list to examine.
   1865   @param  PrimaryLanguage        Points to the null-terminated ASCII string that specifies
   1866                                  the primary language. Languages are specified in the
   1867                                  format specified in Appendix M of the UEFI 2.0 specification.
   1868   @param  SecondaryLanguages     Points to the buffer to hold the returned null-terminated
   1869                                  ASCII string that describes the list of
   1870                                  secondary languages for the specified
   1871                                  PrimaryLanguage. If there are no secondary
   1872                                  languages, the function returns successfully, but
   1873                                  this is set to NULL.
   1874   @param  SecondaryLanguagesSize On entry, points to the size of the buffer pointed
   1875                                  to by SecondaryLanguages, in bytes. On return,
   1876                                  points to the length of SecondaryLanguages in bytes.
   1877 
   1878   @retval EFI_SUCCESS            Secondary languages were correctly returned.
   1879   @retval EFI_INVALID_PARAMETER  PrimaryLanguage or SecondaryLanguagesSize was NULL.
   1880   @retval EFI_INVALID_PARAMETER  The value referenced by SecondaryLanguagesSize is not
   1881                                  zero and SecondaryLanguages is NULL.
   1882   @retval EFI_BUFFER_TOO_SMALL   The buffer specified by SecondaryLanguagesSize is
   1883                                  too small to hold the returned information.
   1884                                  SecondaryLanguageSize is updated to hold the size of
   1885                                  the buffer required.
   1886   @retval EFI_INVALID_LANGUAGE   The language specified by PrimaryLanguage is not
   1887                                  present in the specified package list.
   1888   @retval EFI_NOT_FOUND          The specified PackageList is not in the Database.
   1889 
   1890 **/
   1891 EFI_STATUS
   1892 EFIAPI
   1893 HiiGetSecondaryLanguages (
   1894   IN CONST EFI_HII_STRING_PROTOCOL   *This,
   1895   IN EFI_HII_HANDLE                  PackageList,
   1896   IN CONST CHAR8                     *PrimaryLanguage,
   1897   IN OUT CHAR8                       *SecondaryLanguages,
   1898   IN OUT UINTN                       *SecondaryLanguagesSize
   1899   )
   1900 {
   1901   LIST_ENTRY                          *Link;
   1902   LIST_ENTRY                          *Link1;
   1903   HII_DATABASE_PRIVATE_DATA           *Private;
   1904   HII_DATABASE_RECORD                 *DatabaseRecord;
   1905   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
   1906   HII_STRING_PACKAGE_INSTANCE         *StringPackage;
   1907   CHAR8                               *Languages;
   1908   UINTN                               ResultSize;
   1909 
   1910   if (This == NULL || PackageList == NULL || PrimaryLanguage == NULL || SecondaryLanguagesSize == NULL) {
   1911     return EFI_INVALID_PARAMETER;
   1912   }
   1913   if (SecondaryLanguages == NULL && *SecondaryLanguagesSize != 0) {
   1914     return EFI_INVALID_PARAMETER;
   1915   }
   1916   if (!IsHiiHandleValid (PackageList)) {
   1917     return EFI_NOT_FOUND;
   1918   }
   1919 
   1920   Private    = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
   1921 
   1922   PackageListNode = NULL;
   1923   for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
   1924     DatabaseRecord  = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
   1925     if (DatabaseRecord->Handle == PackageList) {
   1926       PackageListNode = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (DatabaseRecord->PackageList);
   1927         break;
   1928       }
   1929     }
   1930     if (PackageListNode == NULL) {
   1931       return EFI_NOT_FOUND;
   1932     }
   1933 
   1934     Languages  = NULL;
   1935     ResultSize = 0;
   1936     for (Link1 = PackageListNode->StringPkgHdr.ForwardLink;
   1937          Link1 != &PackageListNode->StringPkgHdr;
   1938          Link1 = Link1->ForwardLink
   1939         ) {
   1940     StringPackage = CR (Link1, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
   1941     if (HiiCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) PrimaryLanguage)) {
   1942       Languages = StringPackage->StringPkgHdr->Language;
   1943       //
   1944       // Language is a series of ';' terminated strings, first one is primary
   1945       // language and following with other secondary languages or NULL if no
   1946       // secondary languages any more.
   1947       //
   1948       Languages = AsciiStrStr (Languages, ";");
   1949       if (Languages == NULL) {
   1950         break;
   1951       }
   1952       Languages++;
   1953 
   1954       ResultSize = AsciiStrSize (Languages);
   1955       if (ResultSize <= *SecondaryLanguagesSize) {
   1956         AsciiStrCpyS (SecondaryLanguages, *SecondaryLanguagesSize / sizeof (CHAR8), Languages);
   1957       } else {
   1958         *SecondaryLanguagesSize = ResultSize;
   1959         return EFI_BUFFER_TOO_SMALL;
   1960       }
   1961 
   1962       return EFI_SUCCESS;
   1963     }
   1964   }
   1965 
   1966   return EFI_INVALID_LANGUAGE;
   1967 }
   1968 
   1969 /**
   1970   Converts the ascii character of the string from uppercase to lowercase.
   1971   This is a internal function.
   1972 
   1973   @param ConfigString  String to be converted
   1974 
   1975 **/
   1976 VOID
   1977 EFIAPI
   1978 AsciiHiiToLower (
   1979   IN CHAR8  *ConfigString
   1980   )
   1981 {
   1982   ASSERT (ConfigString != NULL);
   1983 
   1984   //
   1985   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
   1986   //
   1987   for (; *ConfigString != '\0'; ConfigString++) {
   1988     if ( *ConfigString >= 'A' && *ConfigString <= 'Z') {
   1989       *ConfigString = (CHAR8) (*ConfigString - 'A' + 'a');
   1990     }
   1991   }
   1992 }
   1993 
   1994 /**
   1995   Compare whether two names of languages are identical.
   1996 
   1997   @param  Language1              Name of language 1 from StringPackage
   1998   @param  Language2              Name of language 2 to be compared with language 1.
   1999 
   2000   @retval TRUE                   same
   2001   @retval FALSE                  not same
   2002 
   2003 **/
   2004 BOOLEAN
   2005 HiiCompareLanguage (
   2006   IN  CHAR8  *Language1,
   2007   IN  CHAR8  *Language2
   2008   )
   2009 {
   2010   UINTN  Index;
   2011   UINTN  StrLen;
   2012   CHAR8  *Lan1;
   2013   CHAR8  *Lan2;
   2014 
   2015   //
   2016   // Convert to lower to compare.
   2017   //
   2018   StrLen = AsciiStrSize (Language1);
   2019   Lan1   = AllocateZeroPool (StrLen);
   2020   ASSERT (Lan1 != NULL);
   2021   AsciiStrCpyS(Lan1, StrLen / sizeof (CHAR8), Language1);
   2022   AsciiHiiToLower (Lan1);
   2023 
   2024   StrLen = AsciiStrSize (Language2);
   2025   Lan2   = AllocateZeroPool (StrLen);
   2026   ASSERT (Lan2 != NULL);
   2027   AsciiStrCpyS(Lan2, StrLen / sizeof (CHAR8), Language2);
   2028   AsciiHiiToLower (Lan2);
   2029 
   2030   //
   2031   // Compare the Primary Language in Language1 to Language2
   2032   //
   2033   for (Index = 0; Lan1[Index] != 0 && Lan1[Index] != ';'; Index++) {
   2034     if (Lan1[Index] != Lan2[Index]) {
   2035       //
   2036       // Return FALSE if any characters are different.
   2037       //
   2038       FreePool (Lan1);
   2039       FreePool (Lan2);
   2040       return FALSE;
   2041     }
   2042   }
   2043 
   2044   FreePool (Lan1);
   2045   FreePool (Lan2);
   2046 
   2047   //
   2048   // Only return TRUE if Language2[Index] is a Null-terminator which means
   2049   // the Primary Language in Language1 is the same length as Language2.  If
   2050   // Language2[Index] is not a Null-terminator, then Language2 is longer than
   2051   // the Primary Language in Language1, and FALSE must be returned.
   2052   //
   2053   return (BOOLEAN) (Language2[Index] == 0);
   2054 }
   2055