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