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