]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/UserInterface/HiiDataBase/Dxe/Strings.c
1. Fix an issue about the calculation of GlyphBufferSize
[mirror_edk2.git] / EdkModulePkg / Universal / UserInterface / HiiDataBase / Dxe / Strings.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Strings.c
15
16 Abstract:
17
18 This file contains the string processing code to the HII database.
19
20 --*/
21
22
23 #include "HiiDatabase.h"
24
25 STATIC
26 VOID
27 AsciiToUnicode (
28 IN UINT8 *Lang,
29 IN UINT16 *Language
30 )
31 {
32 UINT8 Count;
33
34 //
35 // Convert the ASCII Lang variable to a Unicode Language variable
36 //
37 for (Count = 0; Count < 3; Count++) {
38 Language[Count] = (CHAR16) Lang[Count];
39 }
40 }
41
42 EFI_STATUS
43 EFIAPI
44 HiiTestString (
45 IN EFI_HII_PROTOCOL *This,
46 IN CHAR16 *StringToTest,
47 IN OUT UINT32 *FirstMissing,
48 OUT UINT32 *GlyphBufferSize
49 )
50 /*++
51
52 Routine Description:
53 Test if all of the characters in a string have corresponding font characters.
54
55 Arguments:
56
57 Returns:
58
59 --*/
60 {
61 EFI_HII_GLOBAL_DATA *GlobalData;
62 EFI_HII_DATA *HiiData;
63 BOOLEAN WideChar;
64 INT32 Location;
65
66 if (This == NULL) {
67 return EFI_INVALID_PARAMETER;
68 }
69
70 HiiData = EFI_HII_DATA_FROM_THIS (This);
71 GlobalData = HiiData->GlobalData;
72
73
74 //
75 // Rewind through the string looking for a glyph width identifier
76 // If no width identifier exists, we assume string has narrow width identifier
77 //
78 for (WideChar = FALSE, Location = (INT32) *FirstMissing; Location >= 0; Location--) {
79 if ((StringToTest[Location] == NARROW_CHAR) || (StringToTest[Location] == WIDE_CHAR)) {
80 //
81 // We found something that identifies what glyph database to look in
82 //
83 WideChar = (BOOLEAN) (StringToTest[Location] == WIDE_CHAR);
84 break;
85 }
86 }
87
88 //
89 // Walk through the string until you hit the null terminator
90 //
91 for (*GlyphBufferSize = 0; StringToTest[*FirstMissing] != CHAR_NULL; (*FirstMissing)++) {
92 //
93 // We found something that identifies what glyph database to look in
94 //
95 if ((StringToTest[*FirstMissing] == NARROW_CHAR) || (StringToTest[*FirstMissing] == WIDE_CHAR)) {
96 WideChar = (BOOLEAN) (StringToTest[*FirstMissing] == WIDE_CHAR);
97 continue;
98 }
99
100 if (!WideChar) {
101 if (CompareMem (
102 GlobalData->NarrowGlyphs[StringToTest[*FirstMissing]].GlyphCol1,
103 &mUnknownGlyph,
104 NARROW_GLYPH_ARRAY_SIZE
105 ) == 0
106 ) {
107 //
108 // Break since this glyph isn't defined
109 //
110 return EFI_NOT_FOUND;
111 }
112 } else {
113 //
114 // Can compare wide glyph against only GlyphCol1 since GlyphCol1 and GlyphCol2 are contiguous - just give correct size
115 //
116 if (CompareMem (
117 GlobalData->WideGlyphs[StringToTest[*FirstMissing]].GlyphCol1,
118 &mUnknownGlyph,
119 WIDE_GLYPH_ARRAY_SIZE
120 ) == 0
121 ) {
122 //
123 // Break since this glyph isn't defined
124 //
125 return EFI_NOT_FOUND;
126 }
127 }
128
129 *GlyphBufferSize += (WideChar ? sizeof (EFI_WIDE_GLYPH) : sizeof (EFI_NARROW_GLYPH));
130 }
131
132 return EFI_SUCCESS;
133 }
134
135 STATIC
136 EFI_STATUS
137 HiiNewString2 (
138 IN EFI_HII_PROTOCOL *This,
139 IN CHAR16 *Language,
140 IN EFI_HII_HANDLE Handle,
141 IN OUT STRING_REF *Reference,
142 IN CHAR16 *NewString,
143 IN BOOLEAN ResetStrings
144 )
145 /*++
146
147 Routine Description:
148
149 This function allows a new String to be added to an already existing String Package.
150 We will make a buffer the size of the package + EfiStrSize of the new string. We will
151 copy the string package that first gets changed and the following language packages until
152 we encounter the NULL string package. All this time we will ensure that the offsets have
153 been adjusted.
154
155 Arguments:
156
157 This - Pointer to the HII protocol.
158 Language - Pointer to buffer which contains the language code of this NewString.
159 Handle - Handle of the package instance to be processed.
160 Reference - The token number for the string. If 0, new string token to be returned through this parameter.
161 NewString - Buffer pointer for the new string.
162 ResetStrings - Indicate if we are resetting a string.
163
164 Returns:
165
166 EFI_SUCCESS - The string has been added or reset to Hii database.
167 EFI_INVALID_PARAMETER - Some parameter passed in is invalid.
168
169 --*/
170 {
171 EFI_HII_PACKAGE_INSTANCE *PackageInstance;
172 EFI_HII_PACKAGE_INSTANCE *StringPackageInstance;
173 EFI_HII_DATA *HiiData;
174 EFI_HII_STRING_PACK *StringPack;
175 EFI_HII_STRING_PACK *NewStringPack;
176 EFI_HII_HANDLE_DATABASE *HandleDatabase;
177 EFI_HII_PACKAGE_INSTANCE *NewBuffer;
178 UINT8 *Location;
179 UINT8 *StringLocation;
180 RELOFST *StringPointer;
181 UINTN Count;
182 UINTN Size;
183 UINTN Index;
184 UINTN SecondIndex;
185 BOOLEAN AddString;
186 EFI_STATUS Status;
187 UINTN Increment;
188 UINTN StringCount;
189 UINT32 TotalStringCount;
190 UINT32 OriginalStringCount;
191 RELOFST StringSize;
192 UINT32 Length;
193 RELOFST Offset;
194
195 if (This == NULL) {
196 return EFI_INVALID_PARAMETER;
197 }
198
199 HiiData = EFI_HII_DATA_FROM_THIS (This);
200
201 HandleDatabase = HiiData->DatabaseHead;
202 PackageInstance = NULL;
203 AddString = FALSE;
204 Increment = 0;
205 StringCount = 0;
206 TotalStringCount = 0;
207 OriginalStringCount = 0;
208
209 //
210 // Check numeric value against the head of the database
211 //
212 for (; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) {
213 //
214 // Match the numeric value with the database entry - if matched, extract PackageInstance
215 //
216 if (Handle == HandleDatabase->Handle) {
217 PackageInstance = HandleDatabase->Buffer;
218 if (ResetStrings) {
219 TotalStringCount = HandleDatabase->NumberOfTokens;
220 }
221 break;
222 }
223 }
224 //
225 // No handle was found - error condition
226 //
227 if (PackageInstance == NULL) {
228 return EFI_INVALID_PARAMETER;
229 }
230
231 Status = ValidatePack (This, PackageInstance, &StringPackageInstance, &TotalStringCount);
232
233 //
234 // This sets Count to 0 or the size of the IfrData. We intend to use Count as an offset value
235 //
236 Count = StringPackageInstance->IfrSize;
237
238 //
239 // This is the size of the complete series of string packs
240 //
241 Size = StringPackageInstance->StringSize;
242
243 //
244 // Based on if there is IFR data in this package instance, determine
245 // what the location is of the beginning of the string data.
246 //
247 if (StringPackageInstance->IfrSize > 0) {
248 Location = (UINT8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize;
249 } else {
250 Location = (UINT8 *) (&StringPackageInstance->IfrData);
251 }
252 //
253 // We allocate a buffer which is big enough for both adding and resetting string.
254 // The size is slightly larger than the real size of the packages when we are resetting a string.
255 //
256 NewBuffer = AllocateZeroPool (
257 sizeof (EFI_HII_PACKAGE_INSTANCE) -
258 2 * sizeof (VOID *) +
259 StringPackageInstance->IfrSize +
260 StringPackageInstance->StringSize +
261 sizeof (RELOFST) +
262 StrSize (NewString)
263 );
264 ASSERT (NewBuffer);
265
266 //
267 // Copy data to new buffer
268 //
269 NewBuffer->Handle = StringPackageInstance->Handle;
270 NewBuffer->IfrSize = StringPackageInstance->IfrSize;
271
272 //
273 // The worst case scenario for sizing is that we are adding a new string (not replacing one) and there was not a string
274 // package to begin with.
275 //
276 NewBuffer->StringSize = StringPackageInstance->StringSize + StrSize (NewString) + sizeof (EFI_HII_STRING_PACK);
277
278 if (StringPackageInstance->IfrSize > 0) {
279 CopyMem (&NewBuffer->IfrData, &StringPackageInstance->IfrData, StringPackageInstance->IfrSize);
280 }
281
282 StringPack = (EFI_HII_STRING_PACK *) Location;
283
284 //
285 // There may be multiple instances packed together of strings
286 // so we must walk the self describing structures until we encounter
287 // what we are looking for. In the meantime, copy everything we encounter
288 // to the new buffer.
289 //
290 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
291 for (; Length != 0;) {
292 //
293 // If passed in Language ISO value is in this string pack's language string
294 // then we are dealing with the strings we want.
295 //
296 CopyMem (&Offset, &StringPack->LanguageNameString, sizeof (RELOFST));
297 Status = HiiCompareLanguage ((CHAR16 *) ((CHAR8 *) (StringPack) + Offset), Language);
298
299 if (!EFI_ERROR (Status)) {
300 break;
301 }
302
303 CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), StringPack, Length);
304
305 Count = Count + Length;
306 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Length);
307 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
308 }
309 //
310 // Found the language pack to update on a particular handle
311 // We need to Copy the Contents of this pack and adjust the offset values associated
312 // with adding/changing a string. This is a particular piece of code that screams for
313 // it being prone to programming error.
314 //
315 //
316 // Copy the string package up to the string data
317 //
318 StringPointer = (RELOFST *) (StringPack + 1);
319 CopyMem (
320 ((CHAR8 *) (&NewBuffer->IfrData) + Count),
321 StringPack,
322 (UINTN) ((UINTN) (StringPointer) - (UINTN) (StringPack))
323 );
324
325 //
326 // Determine the number of StringPointers
327 //
328 if (!ResetStrings) {
329 CopyMem (&TotalStringCount, &StringPack->NumStringPointers, sizeof (RELOFST));
330 } else {
331 //
332 // If we are resetting the strings, use the original value when exported
333 //
334 CopyMem (&OriginalStringCount, &StringPack->NumStringPointers, sizeof (RELOFST));
335 ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->LanguageNameString -=
336 (
337 (RELOFST) (OriginalStringCount - TotalStringCount) *
338 sizeof (RELOFST)
339 );
340 ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->PrintableLanguageName -=
341 (
342 (RELOFST) (OriginalStringCount - TotalStringCount) *
343 sizeof (RELOFST)
344 );
345 ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->NumStringPointers = TotalStringCount;
346 *Reference = (STRING_REF) (TotalStringCount);
347 }
348 //
349 // If the token value is not valid, error out
350 //
351 if ((*Reference >= TotalStringCount) && !ResetStrings) {
352 gBS->FreePool (NewBuffer);
353 return EFI_INVALID_PARAMETER;
354 }
355 //
356 // If Reference is 0, update it with what the new token reference will be and turn the AddString flag on
357 //
358 if (*Reference == 0) {
359 *Reference = (STRING_REF) (TotalStringCount);
360 AddString = TRUE;
361 }
362
363 if (AddString) {
364 ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->LanguageNameString += sizeof (RELOFST);
365 ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->PrintableLanguageName += sizeof (RELOFST);
366 ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->NumStringPointers++;
367 }
368 //
369 // Increment offset by amount of copied data
370 //
371 Count = Count + ((UINTN) (StringPointer) - (UINTN) StringPack);
372
373 for (Index = 0; Index < TotalStringCount; Index++) {
374 //
375 // If we are pointing to the size of the changing string value
376 // then cache the old string value so you know what the difference is
377 //
378 if (Index == *Reference) {
379 CopyMem (&Offset, &StringPointer[Index], sizeof (RELOFST));
380
381 StringLocation = ((UINT8 *) (StringPack) + Offset);
382 for (SecondIndex = 0;
383 (StringLocation[SecondIndex] != 0) || (StringLocation[SecondIndex + 1] != 0);
384 SecondIndex = SecondIndex + 2
385 )
386 ;
387 SecondIndex = SecondIndex + 2;
388
389 Size = SecondIndex;
390
391 //
392 // NewString is a passed in local string which is assumed to be aligned
393 //
394 Size = StrSize (NewString) - Size;
395 }
396 //
397 // If we are about to copy the offset of the string that follows the changed string make
398 // sure that the offsets are adjusted accordingly
399 //
400 if ((Index > *Reference) && !ResetStrings) {
401 CopyMem (&Offset, &StringPointer[Index], sizeof (RELOFST));
402 Offset = (RELOFST) (Offset + Size);
403 CopyMem (&StringPointer[Index], &Offset, sizeof (RELOFST));
404 }
405 //
406 // If we are adding a string that means we will have an extra string pointer that will affect all string offsets
407 //
408 if (AddString) {
409 CopyMem (&Offset, &StringPointer[Index], sizeof (RELOFST));
410 Offset = (UINT32) (Offset + sizeof (RELOFST));
411 CopyMem (&StringPointer[Index], &Offset, sizeof (RELOFST));
412 }
413 //
414 // If resetting the strings, we need to reduce the offset by the difference in the strings
415 //
416 if (ResetStrings) {
417 CopyMem (&Length, &StringPointer[Index], sizeof (RELOFST));
418 Length = Length - ((RELOFST) (OriginalStringCount - TotalStringCount) * sizeof (RELOFST));
419 CopyMem (&StringPointer[Index], &Length, sizeof (RELOFST));
420 }
421 //
422 // Notice that if the string was being added as a new token, we don't have to worry about the
423 // offsets changing in the other indexes
424 //
425 CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), &StringPointer[Index], sizeof (RELOFST));
426 Count = Count + sizeof (RELOFST);
427 StringCount++;
428 }
429 //
430 // If we are adding a new string the above for loop did not copy the offset for us
431 //
432 if (AddString) {
433 //
434 // Since the Index is pointing to the beginning of the first string, we need to gather the size of the previous
435 // offset's string and create an offset to our new string.
436 //
437 CopyMem (&Offset, &StringPointer[Index - 1], sizeof (RELOFST));
438 StringLocation = (UINT8 *) StringPack;
439 StringLocation = StringLocation + Offset - sizeof (RELOFST);
440
441 //
442 // Since StringPack is a packed structure, we need to size it carefully (byte-wise) to avoid alignment issues
443 //
444 for (Length = 0;
445 (StringLocation[Length] != 0) || (StringLocation[Length + 1] != 0);
446 Length = (RELOFST) (Length + 2)
447 )
448 ;
449 Length = (RELOFST) (Length + 2);
450
451 StringSize = (RELOFST) (Offset + Length);
452
453 //
454 // Copy the new string offset
455 //
456 CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), &StringSize, sizeof (RELOFST));
457 Count = Count + sizeof (RELOFST);
458
459 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
460 Length = Length + sizeof (RELOFST);
461 CopyMem (&StringPack->Header.Length, &Length, sizeof (UINT32));
462 }
463 //
464 // Set Location to the First String
465 //
466 if (ResetStrings) {
467 Index = OriginalStringCount;
468 }
469 //
470 // Set Location to the First String
471 //
472 Location = (UINT8 *) &StringPointer[Index];
473 Index = 0;
474
475 //
476 // Keep copying strings until you run into two CHAR16's in a row that are NULL
477 //
478 do {
479 if ((*Reference == Increment) && !AddString) {
480 StringLocation = ((UINT8 *) (&NewBuffer->IfrData) + Count);
481 CopyMem (StringLocation, NewString, StrSize (NewString));
482
483 //
484 // Advance the destination location by Count number of bytes
485 //
486 Count = Count + StrSize (NewString);
487
488 //
489 // Add the difference between the new string and the old string to the length
490 //
491 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
492
493 //
494 // Since StringPack is a packed structure, we need to size it carefully (byte-wise) to avoid alignment issues
495 //
496 StringLocation = (UINT8 *) &Location[Index];
497 for (Offset = 0;
498 (StringLocation[Offset] != 0) || (StringLocation[Offset + 1] != 0);
499 Offset = (RELOFST) (Offset + 2)
500 )
501 ;
502 Offset = (RELOFST) (Offset + 2);
503
504 Length = Length + (UINT32) StrSize (NewString) - Offset;
505
506 CopyMem (&StringPack->Header.Length, &Length, sizeof (UINT32));
507 } else {
508 StringLocation = (UINT8 *) &Location[Index];
509 for (Offset = 0;
510 (StringLocation[Offset] != 0) || (StringLocation[Offset + 1] != 0);
511 Offset = (RELOFST) (Offset + 2)
512 )
513 ;
514 Offset = (RELOFST) (Offset + 2);
515
516 CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), StringLocation, Offset);
517
518 //
519 // Advance the destination location by Count number of bytes
520 //
521 Count = Count + Offset;
522 }
523 //
524 // Retrieve the number of characters to advance the index - should land at beginning of next string
525 //
526 Index = Index + Offset;
527 Increment++;
528 StringCount--;
529 Offset = 0;
530 } while (StringCount > 0);
531
532 //
533 // If we are adding a new string, then the above do/while will not suffice
534 //
535 if (AddString) {
536 Offset = (RELOFST) StrSize (NewString);
537 CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), NewString, Offset);
538
539 Count = Count + StrSize (NewString);
540 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
541 Length = Length + (UINT32) StrSize (NewString);
542 CopyMem (&StringPack->Header.Length, &Length, sizeof (UINT32));
543 }
544
545 if (ResetStrings) {
546 //
547 // Skip the remainder of strings in the string package
548 //
549 StringCount = OriginalStringCount - TotalStringCount;
550
551 while (StringCount > 0) {
552 StringLocation = (UINT8 *) &Location[Index];
553 for (Offset = 0;
554 (StringLocation[Offset] != 0) || (StringLocation[Offset + 1] != 0);
555 Offset = (RELOFST) (Offset + 2)
556 )
557 ;
558 Offset = (RELOFST) (Offset + 2);
559 Index = Index + Offset;
560 StringCount--;
561
562 //
563 // Adjust the size of the string pack by the string size we just skipped.
564 // Also reduce the length by the size of a RelativeOffset value since we
565 // obviously would have skipped that as well.
566 //
567 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
568 Length = Length - Offset - sizeof (RELOFST);
569 CopyMem (&StringPack->Header.Length, &Length, sizeof (UINT32));
570 }
571 }
572
573 StringPack = (EFI_HII_STRING_PACK *) &Location[Index];
574
575 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
576 for (; Length != 0;) {
577
578 CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), StringPack, Length);
579
580 Count = Count + Length;
581 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Length);
582 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
583 }
584 //
585 // Copy the null terminator to the new buffer
586 //
587 CopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), StringPack, sizeof (EFI_HII_STRING_PACK));
588
589 //
590 // Based on if there is IFR data in this package instance, determine
591 // what the location is of the beginning of the string data.
592 //
593 if (StringPackageInstance->IfrSize > 0) {
594 Location = (UINT8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize;
595 StringPack = (EFI_HII_STRING_PACK *) Location;
596 Location = (UINT8 *) (&NewBuffer->IfrData) + NewBuffer->IfrSize;
597 NewStringPack = (EFI_HII_STRING_PACK *) Location;
598 } else {
599 StringPack = (EFI_HII_STRING_PACK *) (&StringPackageInstance->IfrData);
600 NewStringPack = (EFI_HII_STRING_PACK *) (&NewBuffer->IfrData);
601 }
602
603 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
604 for (; Length != 0;) {
605 //
606 // Since we updated the old version of the string data as we moved things over
607 // And we had a chicken-egg problem with the data we copied, let's post-fix the new
608 // buffer with accurate length data.
609 //
610 CopyMem (&Count, &NewStringPack->Header.Length, sizeof (UINT32));
611 CopyMem (&NewStringPack->Header.Length, &StringPack->Header.Length, sizeof (UINT32));
612 CopyMem (&StringPack->Header.Length, &Count, sizeof (UINT32));
613
614 CopyMem (&Count, &NewStringPack->Header.Length, sizeof (UINT32));
615 NewStringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (NewStringPack) + Count);
616 CopyMem (&Count, &StringPack->Header.Length, sizeof (UINT32));
617 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Count);
618 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
619 }
620
621 GetPackSize ((VOID *) ((CHAR8 *) (&NewBuffer->IfrData) + NewBuffer->IfrSize), &NewBuffer->StringSize, NULL);
622
623 //
624 // Search through the handles until the requested handle is found.
625 //
626 for (HandleDatabase = HiiData->DatabaseHead;
627 HandleDatabase->Handle != 0;
628 HandleDatabase = HandleDatabase->NextHandleDatabase
629 ) {
630 if (HandleDatabase->Handle == StringPackageInstance->Handle) {
631 //
632 // Free the previous buffer associated with this handle, and assign the new buffer to the handle
633 //
634 gBS->FreePool (HandleDatabase->Buffer);
635 HandleDatabase->Buffer = NewBuffer;
636 break;
637 }
638 }
639
640 return EFI_SUCCESS;
641 }
642
643 EFI_STATUS
644 EFIAPI
645 HiiNewString (
646 IN EFI_HII_PROTOCOL *This,
647 IN CHAR16 *Language,
648 IN EFI_HII_HANDLE Handle,
649 IN OUT STRING_REF *Reference,
650 IN CHAR16 *NewString
651 )
652 /*++
653
654 Routine Description:
655 This function allows a new String to be added to an already existing String Package.
656 We will make a buffer the size of the package + StrSize of the new string. We will
657 copy the string package that first gets changed and the following language packages until
658 we encounter the NULL string package. All this time we will ensure that the offsets have
659 been adjusted.
660
661 Arguments:
662
663 Returns:
664
665 --*/
666 {
667 UINTN Index;
668 CHAR16 *LangCodes;
669 CHAR16 Lang[4];
670 STRING_REF OriginalValue;
671 EFI_STATUS Status;
672
673 //
674 // To avoid a warning 4 uninitialized variable warning
675 //
676 Status = EFI_SUCCESS;
677
678 Status = HiiGetPrimaryLanguages (
679 This,
680 Handle,
681 &LangCodes
682 );
683
684 if (!EFI_ERROR (Status)) {
685 OriginalValue = *Reference;
686
687 if (Language == NULL) {
688 for (Index = 0; LangCodes[Index] != 0; Index += 3) {
689 *Reference = OriginalValue;
690 CopyMem (Lang, &LangCodes[Index], 6);
691 Lang[3] = 0;
692 Status = HiiNewString2 (
693 This,
694 Lang,
695 Handle,
696 Reference,
697 NewString,
698 FALSE
699 );
700
701 }
702 } else {
703 Status = HiiNewString2 (
704 This,
705 Language,
706 Handle,
707 Reference,
708 NewString,
709 FALSE
710 );
711 }
712
713 gBS->FreePool (LangCodes);
714 }
715
716 return Status;
717 }
718
719 EFI_STATUS
720 EFIAPI
721 HiiResetStrings (
722 IN EFI_HII_PROTOCOL *This,
723 IN EFI_HII_HANDLE Handle
724 )
725 /*++
726
727 Routine Description:
728
729 This function removes any new strings that were added after the initial string export for this handle.
730
731 Arguments:
732
733 Returns:
734
735 --*/
736 {
737 UINTN Index;
738 CHAR16 *LangCodes;
739 CHAR16 Lang[4];
740 STRING_REF Reference;
741 CHAR16 NewString;
742 EFI_STATUS Status;
743
744 Reference = 1;
745 NewString = 0;
746
747 HiiGetPrimaryLanguages (
748 This,
749 Handle,
750 &LangCodes
751 );
752
753 for (Index = 0; LangCodes[Index] != 0; Index += 3) {
754 CopyMem (Lang, &LangCodes[Index], 6);
755 Lang[3] = 0;
756 Status = HiiNewString2 (
757 This,
758 Lang,
759 Handle,
760 &Reference,
761 &NewString,
762 TRUE
763 );
764 ASSERT_EFI_ERROR (Status);
765 }
766
767 gBS->FreePool (LangCodes);
768 return EFI_SUCCESS;
769 }
770
771 EFI_STATUS
772 EFIAPI
773 HiiGetString (
774 IN EFI_HII_PROTOCOL *This,
775 IN EFI_HII_HANDLE Handle,
776 IN STRING_REF Token,
777 IN BOOLEAN Raw,
778 IN CHAR16 *LanguageString,
779 IN OUT UINTN *BufferLengthTemp,
780 OUT EFI_STRING StringBuffer
781 )
782 /*++
783
784 Routine Description:
785
786 This function extracts a string from a package already registered with the EFI HII database.
787
788 Arguments:
789 This - A pointer to the EFI_HII_PROTOCOL instance.
790 Handle - The HII handle on which the string resides.
791 Token - The string token assigned to the string.
792 Raw - If TRUE, the string is returned unedited in the internal storage format described
793 above. If false, the string returned is edited by replacing <cr> with <space>
794 and by removing special characters such as the <wide> prefix.
795 LanguageString - Pointer to a NULL-terminated string containing a single ISO 639-2 language
796 identifier, indicating the language to print. If the LanguageString is empty (starts
797 with a NULL), the default system language will be used to determine the language.
798 BufferLength - Length of the StringBuffer. If the status reports that the buffer width is too
799 small, this parameter is filled with the length of the buffer needed.
800 StringBuffer - The buffer designed to receive the characters in the string. Type EFI_STRING is
801 defined in String.
802
803 Returns:
804 EFI_INVALID_PARAMETER - If input parameter is invalid.
805 EFI_BUFFER_TOO_SMALL - If the *BufferLength is too small.
806 EFI_SUCCESS - Operation is successful.
807
808 --*/
809 {
810 EFI_HII_PACKAGE_INSTANCE *PackageInstance;
811 EFI_HII_PACKAGE_INSTANCE *StringPackageInstance;
812 EFI_HII_DATA *HiiData;
813 EFI_HII_HANDLE_DATABASE *HandleDatabase;
814 EFI_HII_STRING_PACK *StringPack;
815 RELOFST *StringPointer;
816 EFI_STATUS Status;
817 UINTN DataSize;
818 CHAR8 Lang[3];
819 CHAR16 Language[3];
820 UINT32 Length;
821 UINTN Count;
822 RELOFST Offset;
823 UINT16 *Local;
824 UINT16 Zero;
825 UINT16 Narrow;
826 UINT16 Wide;
827 UINT16 NoBreak;
828 BOOLEAN LangFound;
829 UINT16 *BufferLength = (UINT16 *) BufferLengthTemp;
830
831 if (This == NULL) {
832 return EFI_INVALID_PARAMETER;
833 }
834
835 LangFound = TRUE;
836
837 DataSize = sizeof (Lang);
838
839 HiiData = EFI_HII_DATA_FROM_THIS (This);
840
841 PackageInstance = NULL;
842 Zero = 0;
843 Narrow = NARROW_CHAR;
844 Wide = WIDE_CHAR;
845 NoBreak = NON_BREAKING_CHAR;
846
847 //
848 // Check numeric value against the head of the database
849 //
850 for (HandleDatabase = HiiData->DatabaseHead;
851 HandleDatabase != NULL;
852 HandleDatabase = HandleDatabase->NextHandleDatabase
853 ) {
854 //
855 // Match the numeric value with the database entry - if matched, extract PackageInstance
856 //
857 if (Handle == HandleDatabase->Handle) {
858 PackageInstance = HandleDatabase->Buffer;
859 break;
860 }
861 }
862 //
863 // No handle was found - error condition
864 //
865 if (PackageInstance == NULL) {
866 return EFI_INVALID_PARAMETER;
867 }
868
869 Status = ValidatePack (This, PackageInstance, &StringPackageInstance, NULL);
870
871 //
872 // If there is no specified language, assume the system default language
873 //
874 if (LanguageString == NULL) {
875 //
876 // Get system default language
877 //
878 Status = gRT->GetVariable (
879 (CHAR16 *) L"Lang",
880 &gEfiGlobalVariableGuid,
881 NULL,
882 &DataSize,
883 Lang
884 );
885
886 if (EFI_ERROR (Status)) {
887 //
888 // If Lang doesn't exist, just use the first language you find
889 //
890 LangFound = FALSE;
891 goto LangNotFound;
892 }
893 //
894 // Convert the ASCII Lang variable to a Unicode Language variable
895 //
896 AsciiToUnicode ((UINT8 *)Lang, Language);
897 } else {
898 //
899 // Copy input ISO value to Language variable
900 //
901 CopyMem (Language, LanguageString, 6);
902 }
903 //
904 // Based on if there is IFR data in this package instance, determine
905 // what the location is of the beginning of the string data.
906 //
907 LangNotFound:
908 if (StringPackageInstance->IfrSize > 0) {
909 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize);
910 } else {
911 StringPack = (EFI_HII_STRING_PACK *) (&StringPackageInstance->IfrData);
912 }
913 //
914 // If Token is 0, extract entire string package
915 //
916 if (Token == 0) {
917 //
918 // Compute the entire string pack length, including all languages' and the terminating pack's.
919 //
920 Length = 0;
921 while (0 != StringPack->Header.Length) {
922 Length += StringPack->Header.Length;
923 StringPack = (VOID*)(((UINT8*)StringPack) + StringPack->Header.Length);
924 }
925 //
926 // Back to the start of package.
927 //
928 StringPack = (VOID*)(((UINT8*)StringPack) - Length);
929 //
930 // Terminating zero sub-pack.
931 //
932 Length += sizeof (EFI_HII_STRING_PACK);
933
934 //
935 // If trying to get the entire string package and have insufficient space. Return error.
936 //
937 if (Length > *BufferLength || StringBuffer == NULL) {
938 *BufferLength = (UINT16)Length;
939 return EFI_BUFFER_TOO_SMALL;
940 }
941 //
942 // Copy the Pack to the caller's buffer.
943 //
944 *BufferLength = (UINT16)Length;
945 CopyMem (StringBuffer, StringPack, Length);
946
947 return EFI_SUCCESS;
948 }
949 //
950 // There may be multiple instances packed together of strings
951 // so we must walk the self describing structures until we encounter
952 // what we are looking for, and then extract the string we are looking for
953 //
954 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
955 for (; Length != 0;) {
956 //
957 // If passed in Language ISO value is in this string pack's language string
958 // then we are dealing with the strings we want.
959 //
960 CopyMem (&Offset, &StringPack->LanguageNameString, sizeof (RELOFST));
961 Status = HiiCompareLanguage ((CHAR16 *) ((CHAR8 *) (StringPack) + Offset), Language);
962
963 //
964 // If we cannot find the lang variable, we skip this check and use the first language available
965 //
966 if (LangFound) {
967 if (EFI_ERROR (Status)) {
968 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Length);
969 CopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
970 continue;
971 }
972 }
973
974 StringPointer = (RELOFST *) (StringPack + 1);
975
976 //
977 // We have the right string package - size it, and copy it to the StringBuffer
978 //
979 if (Token >= StringPack->NumStringPointers) {
980 return EFI_INVALID_PARAMETER;
981 } else {
982 CopyMem (&Offset, &StringPointer[Token], sizeof (RELOFST));
983 }
984 //
985 // Since StringPack is a packed structure, we need to determine the string's
986 // size safely, thus byte-wise. Post-increment the size to include the null-terminator
987 //
988 Local = (UINT16 *) ((CHAR8 *) (StringPack) + Offset);
989 for (Count = 0; CompareMem (&Local[Count], &Zero, 2); Count++)
990 ;
991 Count++;
992
993 Count = Count * sizeof (CHAR16);;
994
995 if (*BufferLength >= Count && StringBuffer != NULL) {
996 //
997 // Copy the string to the user's buffer
998 //
999 if (Raw) {
1000 CopyMem (StringBuffer, Local, Count);
1001 } else {
1002 for (Count = 0; CompareMem (Local, &Zero, 2); Local++) {
1003 //
1004 // Skip "Narraw, Wide, NoBreak"
1005 //
1006 if (CompareMem (Local, &Narrow, 2) &&
1007 CompareMem (Local, &Wide, 2) &&
1008 CompareMem (Local, &NoBreak, 2)) {
1009 CopyMem (&StringBuffer[Count++], Local, 2);
1010 }
1011 }
1012 //
1013 // Add "NULL" at the end.
1014 //
1015 CopyMem (&StringBuffer[Count], &Zero, 2);
1016 Count++;
1017 Count *= sizeof (CHAR16);
1018 }
1019
1020 *BufferLength = (UINT16) Count;
1021 return EFI_SUCCESS;
1022 } else {
1023 *BufferLength = (UINT16) Count;
1024 return EFI_BUFFER_TOO_SMALL;
1025 }
1026
1027 }
1028
1029 LangFound = FALSE;
1030 goto LangNotFound;
1031 }
1032
1033 EFI_STATUS
1034 EFIAPI
1035 HiiGetLine (
1036 IN EFI_HII_PROTOCOL *This,
1037 IN EFI_HII_HANDLE Handle,
1038 IN STRING_REF Token,
1039 IN OUT UINT16 *Index,
1040 IN UINT16 LineWidth,
1041 IN CHAR16 *LanguageString,
1042 IN OUT UINT16 *BufferLength,
1043 OUT EFI_STRING StringBuffer
1044 )
1045 /*++
1046
1047 Routine Description:
1048
1049 This function allows a program to extract a part of a string of not more than a given width.
1050 With repeated calls, this allows a calling program to extract "lines" of text that fit inside
1051 columns. The effort of measuring the fit of strings inside columns is localized to this call.
1052
1053 Arguments:
1054
1055 Returns:
1056
1057 --*/
1058 {
1059 UINTN Count;
1060 EFI_HII_PACKAGE_INSTANCE *PackageInstance;
1061 EFI_HII_PACKAGE_INSTANCE *StringPackageInstance;
1062 EFI_HII_DATA *HiiData;
1063 EFI_HII_HANDLE_DATABASE *HandleDatabase;
1064 EFI_HII_STRING_PACK *StringPack;
1065 RELOFST *StringPointer;
1066 CHAR16 *Location;
1067 EFI_STATUS Status;
1068 UINTN DataSize;
1069 CHAR8 Lang[3];
1070 CHAR16 Language[3];
1071
1072 if (This == NULL) {
1073 return EFI_INVALID_PARAMETER;
1074 }
1075
1076 HiiData = EFI_HII_DATA_FROM_THIS (This);
1077
1078 HandleDatabase = HiiData->DatabaseHead;
1079
1080 PackageInstance = NULL;
1081 DataSize = 4;
1082
1083 //
1084 // Check numeric value against the head of the database
1085 //
1086 for (; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) {
1087 //
1088 // Match the numeric value with the database entry - if matched, extract PackageInstance
1089 //
1090 if (Handle == HandleDatabase->Handle) {
1091 PackageInstance = HandleDatabase->Buffer;
1092 }
1093 }
1094 //
1095 // No handle was found - error condition
1096 //
1097 if (PackageInstance == NULL) {
1098 return EFI_INVALID_PARAMETER;
1099 }
1100
1101 Status = ValidatePack (This, PackageInstance, &StringPackageInstance, NULL);
1102
1103 //
1104 // If there is no specified language, assume the system default language
1105 //
1106 if (LanguageString == NULL) {
1107 //
1108 // Get system default language
1109 //
1110 Status = gRT->GetVariable (
1111 (CHAR16 *) L"Lang",
1112 &gEfiGlobalVariableGuid,
1113 NULL,
1114 &DataSize,
1115 Lang
1116 );
1117
1118 if (EFI_ERROR (Status)) {
1119 return Status;
1120 }
1121 //
1122 // Convert the ASCII Lang variable to a Unicode Language variable
1123 //
1124 AsciiToUnicode ((UINT8 *)Lang, Language);
1125 } else {
1126 //
1127 // Copy input ISO value to Language variable
1128 //
1129 CopyMem (Language, LanguageString, 6);
1130 }
1131 //
1132 // Based on if there is IFR data in this package instance, determine
1133 // what the location is of the beginning of the string data.
1134 //
1135 if (StringPackageInstance->IfrSize > 0) {
1136 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize);
1137 } else {
1138 StringPack = (EFI_HII_STRING_PACK *) (&StringPackageInstance->IfrData);
1139 }
1140
1141 StringPointer = (RELOFST *) (StringPack + 1);
1142
1143 //
1144 // There may be multiple instances packed together of strings
1145 // so we must walk the self describing structures until we encounter
1146 // what we are looking for, and then extract the string we are looking for
1147 //
1148 for (; StringPack->Header.Length != 0;) {
1149 //
1150 // If passed in Language ISO value is in this string pack's language string
1151 // then we are dealing with the strings we want.
1152 //
1153 Status = HiiCompareLanguage ((CHAR16 *) ((CHAR8 *) (StringPack) + StringPack->LanguageNameString), Language);
1154
1155 if (EFI_ERROR (Status)) {
1156 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + StringPack->Header.Length);
1157 continue;
1158 }
1159
1160 Location = (CHAR16 *) ((CHAR8 *) (StringPack) + StringPointer[Token] +*Index * 2);
1161
1162 //
1163 // If the size of the remaining string is less than the LineWidth
1164 // then copy the entire thing
1165 //
1166 if (StrSize (Location) <= LineWidth) {
1167 if (*BufferLength >= StrSize (Location)) {
1168 StrCpy (StringBuffer, Location);
1169 return EFI_SUCCESS;
1170 } else {
1171 *BufferLength = (UINT16) StrSize (Location);
1172 return EFI_BUFFER_TOO_SMALL;
1173 }
1174 } else {
1175 //
1176 // Rewind the string from the maximum size until we see a space the break the line
1177 //
1178 for (Count = LineWidth; Location[Count] != 0x0020; Count--)
1179 ;
1180
1181 //
1182 // Put the index at the next character
1183 //
1184 *Index = (UINT16) (Count + 1);
1185
1186 if (*BufferLength >= Count) {
1187 StrnCpy (StringBuffer, Location, Count);
1188 return EFI_SUCCESS;
1189 } else {
1190 *BufferLength = (UINT16) Count;
1191 return EFI_BUFFER_TOO_SMALL;
1192 }
1193 }
1194 }
1195
1196 return EFI_SUCCESS;
1197 }
1198
1199 EFI_STATUS
1200 HiiCompareLanguage (
1201 IN CHAR16 *LanguageStringLocation,
1202 IN CHAR16 *Language
1203 )
1204 {
1205 UINT8 *Local;
1206 UINTN Index;
1207 CHAR16 *InputString;
1208 CHAR16 *OriginalInputString;
1209
1210 //
1211 // Allocate a temporary buffer for InputString
1212 //
1213 InputString = AllocateZeroPool (0x100);
1214
1215 ASSERT (InputString);
1216
1217 OriginalInputString = InputString;
1218
1219 Local = (UINT8 *) LanguageStringLocation;
1220
1221 //
1222 // Determine the size of this packed string safely (e.g. access by byte), post-increment
1223 // to include the null-terminator
1224 //
1225 for (Index = 0; Local[Index] != 0; Index = Index + 2)
1226 ;
1227 //
1228 // MARMAR Index = Index + 2;
1229 //
1230 // This is a packed structure that this location comes from, so let's make sure
1231 // the value is aligned by copying it to a local variable and working on it.
1232 //
1233 CopyMem (InputString, LanguageStringLocation, Index);
1234
1235 for (Index = 0; Index < 3; Index++) {
1236 InputString[Index] = (CHAR16) (InputString[Index] | 0x20);
1237 Language[Index] = (CHAR16) (Language[Index] | 0x20);
1238 }
1239 //
1240 // If the Language is the same return success
1241 //
1242 if (CompareMem (LanguageStringLocation, Language, 6) == 0) {
1243 gBS->FreePool (InputString);
1244 return EFI_SUCCESS;
1245 }
1246 //
1247 // Skip the first three letters that comprised the primary language,
1248 // see if what is being compared against is a secondary language
1249 //
1250 InputString = InputString + 3;
1251
1252 //
1253 // If the Language is not the same as the Primary language, see if there are any
1254 // secondary languages, and if there are see if we have a match. If not, return an error.
1255 //
1256 for (Index = 0; InputString[Index] != 0; Index = Index + 3) {
1257 //
1258 // Getting in here means we have a secondary language
1259 //
1260 if (CompareMem (&InputString[Index], Language, 6) == 0) {
1261 gBS->FreePool (InputString);
1262 return EFI_SUCCESS;
1263 }
1264 }
1265 //
1266 // If nothing was found, return the error
1267 //
1268 gBS->FreePool (OriginalInputString);
1269 return EFI_NOT_FOUND;
1270
1271 }