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