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