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