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