]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkPkg/Library/FrameworkUefiLib/UefiLib.c
IntelFrameworkPkg/FrameworkUefiLib: implement EfiEventGroupSignal
[mirror_edk2.git] / IntelFrameworkPkg / Library / FrameworkUefiLib / UefiLib.c
1 /** @file
2 The UEFI Library provides functions and macros that simplify the development of
3 UEFI Drivers and UEFI Applications. These functions and macros help manage EFI
4 events, build simple locks utilizing EFI Task Priority Levels (TPLs), install
5 EFI Driver Model related protocols, manage Unicode string tables for UEFI Drivers,
6 and print messages on the console output and standard error devices.
7
8 Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 **/
18
19
20 #include "UefiLibInternal.h"
21
22 /**
23 Compare whether two names of languages are identical.
24
25 @param Language1 Name of language 1.
26 @param Language2 Name of language 2.
27
28 @retval TRUE Language 1 and language 2 are the same.
29 @retval FALSE Language 1 and language 2 are not the same.
30
31 **/
32 BOOLEAN
33 CompareIso639LanguageCode (
34 IN CONST CHAR8 *Language1,
35 IN CONST CHAR8 *Language2
36 )
37 {
38 UINT32 Name1;
39 UINT32 Name2;
40
41 Name1 = ReadUnaligned24 ((CONST UINT32 *) Language1);
42 Name2 = ReadUnaligned24 ((CONST UINT32 *) Language2);
43
44 return (BOOLEAN) (Name1 == Name2);
45 }
46
47 /**
48 Retrieves a pointer to the system configuration table from the EFI System Table
49 based on a specified GUID.
50
51 This function searches the list of configuration tables stored in the EFI System Table
52 for a table with a GUID that matches TableGuid. If a match is found, then a pointer to
53 the configuration table is returned in Table., and EFI_SUCCESS is returned. If a matching GUID
54 is not found, then EFI_NOT_FOUND is returned.
55 If TableGuid is NULL, then ASSERT().
56 If Table is NULL, then ASSERT().
57
58 @param TableGuid Pointer to table's GUID type..
59 @param Table Pointer to the table associated with TableGuid in the EFI System Table.
60
61 @retval EFI_SUCCESS A configuration table matching TableGuid was found.
62 @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.
63
64 **/
65 EFI_STATUS
66 EFIAPI
67 EfiGetSystemConfigurationTable (
68 IN EFI_GUID *TableGuid,
69 OUT VOID **Table
70 )
71 {
72 EFI_SYSTEM_TABLE *SystemTable;
73 UINTN Index;
74
75 ASSERT (TableGuid != NULL);
76 ASSERT (Table != NULL);
77
78 SystemTable = gST;
79 *Table = NULL;
80 for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {
81 if (CompareGuid (TableGuid, &(SystemTable->ConfigurationTable[Index].VendorGuid))) {
82 *Table = SystemTable->ConfigurationTable[Index].VendorTable;
83 return EFI_SUCCESS;
84 }
85 }
86
87 return EFI_NOT_FOUND;
88 }
89
90 /**
91 Creates and returns a notification event and registers that event with all the protocol
92 instances specified by ProtocolGuid.
93
94 This function causes the notification function to be executed for every protocol of type
95 ProtocolGuid instance that exists in the system when this function is invoked. If there are
96 no instances of ProtocolGuid in the handle database at the time this function is invoked,
97 then the notification function is still executed one time. In addition, every time a protocol
98 of type ProtocolGuid instance is installed or reinstalled, the notification function is also
99 executed. This function returns the notification event that was created.
100 If ProtocolGuid is NULL, then ASSERT().
101 If NotifyTpl is not a legal TPL value, then ASSERT().
102 If NotifyFunction is NULL, then ASSERT().
103 If Registration is NULL, then ASSERT().
104
105
106 @param ProtocolGuid Supplies GUID of the protocol upon whose installation the event is fired.
107 @param NotifyTpl Supplies the task priority level of the event notifications.
108 @param NotifyFunction Supplies the function to notify when the event is signaled.
109 @param NotifyContext The context parameter to pass to NotifyFunction.
110 @param Registration A pointer to a memory location to receive the registration value.
111 This value is passed to LocateHandle() to obtain new handles that
112 have been added that support the ProtocolGuid-specified protocol.
113
114 @return The notification event that was created.
115
116 **/
117 EFI_EVENT
118 EFIAPI
119 EfiCreateProtocolNotifyEvent(
120 IN EFI_GUID *ProtocolGuid,
121 IN EFI_TPL NotifyTpl,
122 IN EFI_EVENT_NOTIFY NotifyFunction,
123 IN VOID *NotifyContext, OPTIONAL
124 OUT VOID **Registration
125 )
126 {
127 EFI_STATUS Status;
128 EFI_EVENT Event;
129
130 ASSERT (ProtocolGuid != NULL);
131 ASSERT (NotifyFunction != NULL);
132 ASSERT (Registration != NULL);
133
134 //
135 // Create the event
136 //
137
138 Status = gBS->CreateEvent (
139 EVT_NOTIFY_SIGNAL,
140 NotifyTpl,
141 NotifyFunction,
142 NotifyContext,
143 &Event
144 );
145 ASSERT_EFI_ERROR (Status);
146
147 //
148 // Register for protocol notifications on this event
149 //
150
151 Status = gBS->RegisterProtocolNotify (
152 ProtocolGuid,
153 Event,
154 Registration
155 );
156
157 ASSERT_EFI_ERROR (Status);
158
159 //
160 // Kick the event so we will perform an initial pass of
161 // current installed drivers
162 //
163
164 gBS->SignalEvent (Event);
165 return Event;
166 }
167
168 /**
169 Creates a named event that can be signaled with EfiNamedEventSignal().
170
171 This function creates an event using NotifyTpl, NoifyFunction, and NotifyContext.
172 This event is signaled with EfiNamedEventSignal(). This provides the ability for one or more
173 listeners on the same event named by the GUID specified by Name.
174 If Name is NULL, then ASSERT().
175 If NotifyTpl is not a legal TPL value, then ASSERT().
176 If NotifyFunction is NULL, then ASSERT().
177
178 @param Name Supplies GUID name of the event.
179 @param NotifyTpl Supplies the task priority level of the event notifications.
180 @param NotifyFunction Supplies the function to notify when the event is signaled.
181 @param NotifyContext The context parameter to pass to NotifyFunction.
182 @param Registration A pointer to a memory location to receive the registration value.
183
184 @retval EFI_SUCCESS A named event was created.
185 @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
186
187 **/
188 EFI_STATUS
189 EFIAPI
190 EfiNamedEventListen (
191 IN CONST EFI_GUID *Name,
192 IN EFI_TPL NotifyTpl,
193 IN EFI_EVENT_NOTIFY NotifyFunction,
194 IN CONST VOID *NotifyContext, OPTIONAL
195 OUT VOID *Registration OPTIONAL
196 )
197 {
198 EFI_STATUS Status;
199 EFI_EVENT Event;
200 VOID *RegistrationLocal;
201
202 ASSERT (Name != NULL);
203 ASSERT (NotifyFunction != NULL);
204 ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
205
206 //
207 // Create event
208 //
209 Status = gBS->CreateEvent (
210 EVT_NOTIFY_SIGNAL,
211 NotifyTpl,
212 NotifyFunction,
213 (VOID *) NotifyContext,
214 &Event
215 );
216 ASSERT_EFI_ERROR (Status);
217
218 //
219 // The Registration is not optional to RegisterProtocolNotify().
220 // To make it optional to EfiNamedEventListen(), may need to substitute with a local.
221 //
222 if (Registration != NULL) {
223 RegistrationLocal = Registration;
224 } else {
225 RegistrationLocal = &RegistrationLocal;
226 }
227
228 //
229 // Register for an installation of protocol interface
230 //
231
232 Status = gBS->RegisterProtocolNotify (
233 (EFI_GUID *) Name,
234 Event,
235 RegistrationLocal
236 );
237 ASSERT_EFI_ERROR (Status);
238
239 return Status;
240 }
241
242 /**
243 Signals a named event created with EfiNamedEventListen().
244
245 This function signals the named event specified by Name. The named event must have been
246 created with EfiNamedEventListen().
247 If Name is NULL, then ASSERT().
248
249 @param Name Supplies GUID name of the event.
250
251 @retval EFI_SUCCESS A named event was signaled.
252 @retval EFI_OUT_OF_RESOURCES There are not enough resource to signal the named event.
253
254 **/
255 EFI_STATUS
256 EFIAPI
257 EfiNamedEventSignal (
258 IN CONST EFI_GUID *Name
259 )
260 {
261 EFI_STATUS Status;
262 EFI_HANDLE Handle;
263
264 ASSERT(Name != NULL);
265
266 Handle = NULL;
267 Status = gBS->InstallProtocolInterface (
268 &Handle,
269 (EFI_GUID *) Name,
270 EFI_NATIVE_INTERFACE,
271 NULL
272 );
273 ASSERT_EFI_ERROR (Status);
274
275 Status = gBS->UninstallProtocolInterface (
276 Handle,
277 (EFI_GUID *) Name,
278 NULL
279 );
280 ASSERT_EFI_ERROR (Status);
281
282 return Status;
283 }
284
285 /**
286 Signals an event group by placing a new event in the group temporarily and
287 signaling it.
288
289 @param[in] EventGroup Supplies the unique identifier of the event
290 group to signal.
291
292 @retval EFI_SUCCESS The event group was signaled successfully.
293 @retval EFI_INVALID_PARAMETER EventGroup is NULL.
294 @return Error codes that report problems about event
295 creation or signaling.
296 **/
297 EFI_STATUS
298 EFIAPI
299 EfiEventGroupSignal (
300 IN CONST EFI_GUID *EventGroup
301 )
302 {
303 EFI_STATUS Status;
304 EFI_EVENT Event;
305
306 if (EventGroup == NULL) {
307 return EFI_INVALID_PARAMETER;
308 }
309
310 Status = gBS->CreateEventEx (
311 EVT_NOTIFY_SIGNAL,
312 TPL_CALLBACK,
313 InternalEmptyFunction,
314 NULL,
315 EventGroup,
316 &Event
317 );
318 if (EFI_ERROR (Status)) {
319 return Status;
320 }
321
322 Status = gBS->SignalEvent (Event);
323 gBS->CloseEvent (Event);
324
325 return Status;
326 }
327
328 /**
329 Returns the current TPL.
330
331 This function returns the current TPL. There is no EFI service to directly
332 retrieve the current TPL. Instead, the RaiseTPL() function is used to raise
333 the TPL to TPL_HIGH_LEVEL. This will return the current TPL. The TPL level
334 can then immediately be restored back to the current TPL level with a call
335 to RestoreTPL().
336
337 @return The current TPL.
338
339 **/
340 EFI_TPL
341 EFIAPI
342 EfiGetCurrentTpl (
343 VOID
344 )
345 {
346 EFI_TPL Tpl;
347
348 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
349 gBS->RestoreTPL (Tpl);
350
351 return Tpl;
352 }
353
354
355 /**
356 Initializes a basic mutual exclusion lock.
357
358 This function initializes a basic mutual exclusion lock to the released state
359 and returns the lock. Each lock provides mutual exclusion access at its task
360 priority level. Since there is no preemption or multiprocessor support in EFI,
361 acquiring the lock only consists of raising to the locks TPL.
362 If Lock is NULL, then ASSERT().
363 If Priority is not a valid TPL value, then ASSERT().
364
365 @param Lock A pointer to the lock data structure to initialize.
366 @param Priority EFI TPL associated with the lock.
367
368 @return The lock.
369
370 **/
371 EFI_LOCK *
372 EFIAPI
373 EfiInitializeLock (
374 IN OUT EFI_LOCK *Lock,
375 IN EFI_TPL Priority
376 )
377 {
378 ASSERT (Lock != NULL);
379 ASSERT (Priority <= TPL_HIGH_LEVEL);
380
381 Lock->Tpl = Priority;
382 Lock->OwnerTpl = TPL_APPLICATION;
383 Lock->Lock = EfiLockReleased ;
384 return Lock;
385 }
386
387 /**
388 Acquires ownership of a lock.
389
390 This function raises the system's current task priority level to the task
391 priority level of the mutual exclusion lock. Then, it places the lock in the
392 acquired state.
393 If Lock is NULL, then ASSERT().
394 If Lock is not initialized, then ASSERT().
395 If Lock is already in the acquired state, then ASSERT().
396
397 @param Lock A pointer to the lock to acquire.
398
399 **/
400 VOID
401 EFIAPI
402 EfiAcquireLock (
403 IN EFI_LOCK *Lock
404 )
405 {
406 ASSERT (Lock != NULL);
407 ASSERT (Lock->Lock == EfiLockReleased);
408
409 Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
410 Lock->Lock = EfiLockAcquired;
411 }
412
413 /**
414 Acquires ownership of a lock.
415
416 This function raises the system's current task priority level to the task priority
417 level of the mutual exclusion lock. Then, it attempts to place the lock in the acquired state.
418 If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
419 Otherwise, EFI_SUCCESS is returned.
420 If Lock is NULL, then ASSERT().
421 If Lock is not initialized, then ASSERT().
422
423 @param Lock A pointer to the lock to acquire.
424
425 @retval EFI_SUCCESS The lock was acquired.
426 @retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned.
427
428 **/
429 EFI_STATUS
430 EFIAPI
431 EfiAcquireLockOrFail (
432 IN EFI_LOCK *Lock
433 )
434 {
435
436 ASSERT (Lock != NULL);
437 ASSERT (Lock->Lock != EfiLockUninitialized);
438
439 if (Lock->Lock == EfiLockAcquired) {
440 //
441 // Lock is already owned, so bail out
442 //
443 return EFI_ACCESS_DENIED;
444 }
445
446 Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
447
448 Lock->Lock = EfiLockAcquired;
449
450 return EFI_SUCCESS;
451 }
452
453 /**
454 Releases ownership of a lock.
455
456 This function transitions a mutual exclusion lock from the acquired state to
457 the released state, and restores the system's task priority level to its
458 previous level.
459 If Lock is NULL, then ASSERT().
460 If Lock is not initialized, then ASSERT().
461 If Lock is already in the released state, then ASSERT().
462
463 @param Lock A pointer to the lock to release.
464
465 **/
466 VOID
467 EFIAPI
468 EfiReleaseLock (
469 IN EFI_LOCK *Lock
470 )
471 {
472 EFI_TPL Tpl;
473
474 ASSERT (Lock != NULL);
475 ASSERT (Lock->Lock == EfiLockAcquired);
476
477 Tpl = Lock->OwnerTpl;
478
479 Lock->Lock = EfiLockReleased;
480
481 gBS->RestoreTPL (Tpl);
482 }
483
484 /**
485 Tests whether a controller handle is being managed by a specific driver.
486
487 This function tests whether the driver specified by DriverBindingHandle is
488 currently managing the controller specified by ControllerHandle. This test
489 is performed by evaluating if the the protocol specified by ProtocolGuid is
490 present on ControllerHandle and is was opened by DriverBindingHandle with an
491 attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
492 If ProtocolGuid is NULL, then ASSERT().
493
494 @param ControllerHandle A handle for a controller to test.
495 @param DriverBindingHandle Specifies the driver binding handle for the
496 driver.
497 @param ProtocolGuid Specifies the protocol that the driver specified
498 by DriverBindingHandle opens in its Start()
499 function.
500
501 @retval EFI_SUCCESS ControllerHandle is managed by the driver
502 specified by DriverBindingHandle.
503 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
504 specified by DriverBindingHandle.
505
506 **/
507 EFI_STATUS
508 EFIAPI
509 EfiTestManagedDevice (
510 IN CONST EFI_HANDLE ControllerHandle,
511 IN CONST EFI_HANDLE DriverBindingHandle,
512 IN CONST EFI_GUID *ProtocolGuid
513 )
514 {
515 EFI_STATUS Status;
516 VOID *ManagedInterface;
517
518 ASSERT (ProtocolGuid != NULL);
519
520 Status = gBS->OpenProtocol (
521 ControllerHandle,
522 (EFI_GUID *) ProtocolGuid,
523 &ManagedInterface,
524 DriverBindingHandle,
525 ControllerHandle,
526 EFI_OPEN_PROTOCOL_BY_DRIVER
527 );
528 if (!EFI_ERROR (Status)) {
529 gBS->CloseProtocol (
530 ControllerHandle,
531 (EFI_GUID *) ProtocolGuid,
532 DriverBindingHandle,
533 ControllerHandle
534 );
535 return EFI_UNSUPPORTED;
536 }
537
538 if (Status != EFI_ALREADY_STARTED) {
539 return EFI_UNSUPPORTED;
540 }
541
542 return EFI_SUCCESS;
543 }
544
545 /**
546 Tests whether a child handle is a child device of the controller.
547
548 This function tests whether ChildHandle is one of the children of
549 ControllerHandle. This test is performed by checking to see if the protocol
550 specified by ProtocolGuid is present on ControllerHandle and opened by
551 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
552 If ProtocolGuid is NULL, then ASSERT().
553
554 @param ControllerHandle A handle for a (parent) controller to test.
555 @param ChildHandle A child handle to test.
556 @param ProtocolGuid Supplies the protocol that the child controller
557 opens on its parent controller.
558
559 @retval EFI_SUCCESS ChildHandle is a child of the ControllerHandle.
560 @retval EFI_UNSUPPORTED ChildHandle is not a child of the
561 ControllerHandle.
562
563 **/
564 EFI_STATUS
565 EFIAPI
566 EfiTestChildHandle (
567 IN CONST EFI_HANDLE ControllerHandle,
568 IN CONST EFI_HANDLE ChildHandle,
569 IN CONST EFI_GUID *ProtocolGuid
570 )
571 {
572 EFI_STATUS Status;
573 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
574 UINTN EntryCount;
575 UINTN Index;
576
577 ASSERT (ProtocolGuid != NULL);
578
579 //
580 // Retrieve the list of agents that are consuming the specific protocol
581 // on ControllerHandle.
582 //
583 Status = gBS->OpenProtocolInformation (
584 ControllerHandle,
585 (EFI_GUID *) ProtocolGuid,
586 &OpenInfoBuffer,
587 &EntryCount
588 );
589 if (EFI_ERROR (Status)) {
590 return EFI_UNSUPPORTED;
591 }
592
593 //
594 // Inspect if ChildHandle is one of the agents.
595 //
596 Status = EFI_UNSUPPORTED;
597 for (Index = 0; Index < EntryCount; Index++) {
598 if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&
599 (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
600 Status = EFI_SUCCESS;
601 break;
602 }
603 }
604
605 FreePool (OpenInfoBuffer);
606 return Status;
607 }
608
609 /**
610 This function looks up a Unicode string in UnicodeStringTable.
611
612 If Language is a member of SupportedLanguages and a Unicode string is found in
613 UnicodeStringTable that matches the language code specified by Language, then it
614 is returned in UnicodeString.
615
616 @param Language A pointer to the ISO 639-2 language code for the
617 Unicode string to look up and return.
618 @param SupportedLanguages A pointer to the set of ISO 639-2 language codes
619 that the Unicode string table supports. Language
620 must be a member of this set.
621 @param UnicodeStringTable A pointer to the table of Unicode strings.
622 @param UnicodeString A pointer to the Unicode string from UnicodeStringTable
623 that matches the language specified by Language.
624
625 @retval EFI_SUCCESS The Unicode string that matches the language
626 specified by Language was found
627 in the table of Unicode strings UnicodeStringTable,
628 and it was returned in UnicodeString.
629 @retval EFI_INVALID_PARAMETER Language is NULL.
630 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
631 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
632 @retval EFI_UNSUPPORTED UnicodeStringTable is NULL.
633 @retval EFI_UNSUPPORTED The language specified by Language is not a
634 member of SupportedLanguages.
635 @retval EFI_UNSUPPORTED The language specified by Language is not
636 supported by UnicodeStringTable.
637
638 **/
639 EFI_STATUS
640 EFIAPI
641 LookupUnicodeString (
642 IN CONST CHAR8 *Language,
643 IN CONST CHAR8 *SupportedLanguages,
644 IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable,
645 OUT CHAR16 **UnicodeString
646 )
647 {
648 //
649 // Make sure the parameters are valid
650 //
651 if (Language == NULL || UnicodeString == NULL) {
652 return EFI_INVALID_PARAMETER;
653 }
654
655 //
656 // If there are no supported languages, or the Unicode String Table is empty, then the
657 // Unicode String specified by Language is not supported by this Unicode String Table
658 //
659 if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
660 return EFI_UNSUPPORTED;
661 }
662
663 //
664 // Make sure Language is in the set of Supported Languages
665 //
666 while (*SupportedLanguages != 0) {
667 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
668
669 //
670 // Search the Unicode String Table for the matching Language specifier
671 //
672 while (UnicodeStringTable->Language != NULL) {
673 if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) {
674
675 //
676 // A matching string was found, so return it
677 //
678 *UnicodeString = UnicodeStringTable->UnicodeString;
679 return EFI_SUCCESS;
680 }
681
682 UnicodeStringTable++;
683 }
684
685 return EFI_UNSUPPORTED;
686 }
687
688 SupportedLanguages += 3;
689 }
690
691 return EFI_UNSUPPORTED;
692 }
693
694
695
696 /**
697 This function looks up a Unicode string in UnicodeStringTable.
698
699 If Language is a member of SupportedLanguages and a Unicode string is found in
700 UnicodeStringTable that matches the language code specified by Language, then
701 it is returned in UnicodeString.
702
703 @param Language A pointer to an ASCII string containing the ISO 639-2 or the
704 RFC 4646 language code for the Unicode string to look up and
705 return. If Iso639Language is TRUE, then this ASCII string is
706 not assumed to be Null-terminated, and only the first three
707 characters are used. If Iso639Language is FALSE, then this ASCII
708 string must be Null-terminated.
709 @param SupportedLanguages A pointer to a Null-terminated ASCII string that contains a
710 set of ISO 639-2 or RFC 4646 language codes that the Unicode
711 string table supports. Language must be a member of this set.
712 If Iso639Language is TRUE, then this string contains one or more
713 ISO 639-2 language codes with no separator characters. If Iso639Language
714 is FALSE, then is string contains one or more RFC 4646 language
715 codes separated by ';'.
716 @param UnicodeStringTable A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
717 is defined in "Related Definitions".
718 @param UnicodeString A pointer to the Null-terminated Unicode string from UnicodeStringTable
719 that matches the language specified by Language.
720 @param Iso639Language Specifies the supported language code format. If it is TRUE, then
721 Language and SupportedLanguages follow ISO 639-2 language code format.
722 Otherwise, they follow RFC 4646 language code format.
723
724
725 @retval EFI_SUCCESS The Unicode string that matches the language specified by Language
726 was found in the table of Unicode strings UnicodeStringTable, and
727 it was returned in UnicodeString.
728 @retval EFI_INVALID_PARAMETER Language is NULL.
729 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
730 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
731 @retval EFI_UNSUPPORTED UnicodeStringTable is NULL.
732 @retval EFI_UNSUPPORTED The language specified by Language is not a member of SupportedLanguages.
733 @retval EFI_UNSUPPORTED The language specified by Language is not supported by UnicodeStringTable.
734
735 **/
736 EFI_STATUS
737 EFIAPI
738 LookupUnicodeString2 (
739 IN CONST CHAR8 *Language,
740 IN CONST CHAR8 *SupportedLanguages,
741 IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable,
742 OUT CHAR16 **UnicodeString,
743 IN BOOLEAN Iso639Language
744 )
745 {
746 BOOLEAN Found;
747 UINTN Index;
748 CHAR8 *LanguageString;
749
750 //
751 // Make sure the parameters are valid
752 //
753 if (Language == NULL || UnicodeString == NULL) {
754 return EFI_INVALID_PARAMETER;
755 }
756
757 //
758 // If there are no supported languages, or the Unicode String Table is empty, then the
759 // Unicode String specified by Language is not supported by this Unicode String Table
760 //
761 if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
762 return EFI_UNSUPPORTED;
763 }
764
765 //
766 // Make sure Language is in the set of Supported Languages
767 //
768 Found = FALSE;
769 while (*SupportedLanguages != 0) {
770 if (Iso639Language) {
771 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
772 Found = TRUE;
773 break;
774 }
775 SupportedLanguages += 3;
776 } else {
777 for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
778 if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {
779 Found = TRUE;
780 break;
781 }
782 SupportedLanguages += Index;
783 for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
784 }
785 }
786
787 //
788 // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
789 //
790 if (!Found) {
791 return EFI_UNSUPPORTED;
792 }
793
794 //
795 // Search the Unicode String Table for the matching Language specifier
796 //
797 while (UnicodeStringTable->Language != NULL) {
798 LanguageString = UnicodeStringTable->Language;
799 while (0 != *LanguageString) {
800 for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
801 if (AsciiStrnCmp(LanguageString, Language, Index) == 0) {
802 *UnicodeString = UnicodeStringTable->UnicodeString;
803 return EFI_SUCCESS;
804 }
805 LanguageString += Index;
806 for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] == ';'; Index++);
807 }
808 UnicodeStringTable++;
809 }
810
811 return EFI_UNSUPPORTED;
812 }
813
814
815 /**
816 This function adds a Unicode string to UnicodeStringTable.
817
818 If Language is a member of SupportedLanguages then UnicodeString is added to
819 UnicodeStringTable. New buffers are allocated for both Language and
820 UnicodeString. The contents of Language and UnicodeString are copied into
821 these new buffers. These buffers are automatically freed when
822 FreeUnicodeStringTable() is called.
823
824 @param Language A pointer to the ISO 639-2 language code for the Unicode
825 string to add.
826 @param SupportedLanguages A pointer to the set of ISO 639-2 language codes
827 that the Unicode string table supports.
828 Language must be a member of this set.
829 @param UnicodeStringTable A pointer to the table of Unicode strings.
830 @param UnicodeString A pointer to the Unicode string to add.
831
832 @retval EFI_SUCCESS The Unicode string that matches the language
833 specified by Language was found in the table of
834 Unicode strings UnicodeStringTable, and it was
835 returned in UnicodeString.
836 @retval EFI_INVALID_PARAMETER Language is NULL.
837 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
838 @retval EFI_INVALID_PARAMETER UnicodeString is an empty string.
839 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
840 @retval EFI_ALREADY_STARTED A Unicode string with language Language is
841 already present in UnicodeStringTable.
842 @retval EFI_OUT_OF_RESOURCES There is not enough memory to add another
843 Unicode string to UnicodeStringTable.
844 @retval EFI_UNSUPPORTED The language specified by Language is not a
845 member of SupportedLanguages.
846
847 **/
848 EFI_STATUS
849 EFIAPI
850 AddUnicodeString (
851 IN CONST CHAR8 *Language,
852 IN CONST CHAR8 *SupportedLanguages,
853 IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable,
854 IN CONST CHAR16 *UnicodeString
855 )
856 {
857 UINTN NumberOfEntries;
858 EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable;
859 EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable;
860 UINTN UnicodeStringLength;
861
862 //
863 // Make sure the parameter are valid
864 //
865 if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
866 return EFI_INVALID_PARAMETER;
867 }
868
869 //
870 // If there are no supported languages, then a Unicode String can not be added
871 //
872 if (SupportedLanguages == NULL) {
873 return EFI_UNSUPPORTED;
874 }
875
876 //
877 // If the Unicode String is empty, then a Unicode String can not be added
878 //
879 if (UnicodeString[0] == 0) {
880 return EFI_INVALID_PARAMETER;
881 }
882
883 //
884 // Make sure Language is a member of SupportedLanguages
885 //
886 while (*SupportedLanguages != 0) {
887 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
888
889 //
890 // Determine the size of the Unicode String Table by looking for a NULL Language entry
891 //
892 NumberOfEntries = 0;
893 if (*UnicodeStringTable != NULL) {
894 OldUnicodeStringTable = *UnicodeStringTable;
895 while (OldUnicodeStringTable->Language != NULL) {
896 if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) {
897 return EFI_ALREADY_STARTED;
898 }
899
900 OldUnicodeStringTable++;
901 NumberOfEntries++;
902 }
903 }
904
905 //
906 // Allocate space for a new Unicode String Table. It must hold the current number of
907 // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
908 // marker
909 //
910 NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
911 if (NewUnicodeStringTable == NULL) {
912 return EFI_OUT_OF_RESOURCES;
913 }
914
915 //
916 // If the current Unicode String Table contains any entries, then copy them to the
917 // newly allocated Unicode String Table.
918 //
919 if (*UnicodeStringTable != NULL) {
920 CopyMem (
921 NewUnicodeStringTable,
922 *UnicodeStringTable,
923 NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
924 );
925 }
926
927 //
928 // Allocate space for a copy of the Language specifier
929 //
930 NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language);
931 if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
932 gBS->FreePool (NewUnicodeStringTable);
933 return EFI_OUT_OF_RESOURCES;
934 }
935
936 //
937 // Compute the length of the Unicode String
938 //
939 for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++)
940 ;
941
942 //
943 // Allocate space for a copy of the Unicode String
944 //
945 NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (
946 (UnicodeStringLength + 1) * sizeof (CHAR16),
947 UnicodeString
948 );
949 if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
950 gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
951 gBS->FreePool (NewUnicodeStringTable);
952 return EFI_OUT_OF_RESOURCES;
953 }
954
955 //
956 // Mark the end of the Unicode String Table
957 //
958 NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL;
959 NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;
960
961 //
962 // Free the old Unicode String Table
963 //
964 if (*UnicodeStringTable != NULL) {
965 gBS->FreePool (*UnicodeStringTable);
966 }
967
968 //
969 // Point UnicodeStringTable at the newly allocated Unicode String Table
970 //
971 *UnicodeStringTable = NewUnicodeStringTable;
972
973 return EFI_SUCCESS;
974 }
975
976 SupportedLanguages += 3;
977 }
978
979 return EFI_UNSUPPORTED;
980 }
981
982
983 /**
984 This function adds the Null-terminated Unicode string specified by UnicodeString
985 to UnicodeStringTable.
986
987 If Language is a member of SupportedLanguages then UnicodeString is added to
988 UnicodeStringTable. New buffers are allocated for both Language and UnicodeString.
989 The contents of Language and UnicodeString are copied into these new buffers.
990 These buffers are automatically freed when EfiLibFreeUnicodeStringTable() is called.
991
992 @param Language A pointer to an ASCII string containing the ISO 639-2 or
993 the RFC 4646 language code for the Unicode string to add.
994 If Iso639Language is TRUE, then this ASCII string is not
995 assumed to be Null-terminated, and only the first three
996 chacters are used. If Iso639Language is FALSE, then this
997 ASCII string must be Null-terminated.
998 @param SupportedLanguages A pointer to a Null-terminated ASCII string that contains
999 a set of ISO 639-2 or RFC 4646 language codes that the Unicode
1000 string table supports. Language must be a member of this set.
1001 If Iso639Language is TRUE, then this string contains one or more
1002 ISO 639-2 language codes with no separator characters.
1003 If Iso639Language is FALSE, then is string contains one or more
1004 RFC 4646 language codes separated by ';'.
1005 @param UnicodeStringTable A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
1006 is defined in "Related Definitions".
1007 @param UnicodeString A pointer to the Unicode string to add.
1008 @param Iso639Language Specifies the supported language code format. If it is TRUE,
1009 then Language and SupportedLanguages follow ISO 639-2 language code format.
1010 Otherwise, they follow RFC 4646 language code format.
1011
1012 @retval EFI_SUCCESS The Unicode string that matches the language specified by
1013 Language was found in the table of Unicode strings UnicodeStringTable,
1014 and it was returned in UnicodeString.
1015 @retval EFI_INVALID_PARAMETER Language is NULL.
1016 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
1017 @retval EFI_INVALID_PARAMETER UnicodeString is an empty string.
1018 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
1019 @retval EFI_ALREADY_STARTED A Unicode string with language Language is already present in
1020 UnicodeStringTable.
1021 @retval EFI_OUT_OF_RESOURCES There is not enough memory to add another Unicode string UnicodeStringTable.
1022 @retval EFI_UNSUPPORTED The language specified by Language is not a member of SupportedLanguages.
1023
1024 **/
1025 EFI_STATUS
1026 EFIAPI
1027 AddUnicodeString2 (
1028 IN CONST CHAR8 *Language,
1029 IN CONST CHAR8 *SupportedLanguages,
1030 IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable,
1031 IN CONST CHAR16 *UnicodeString,
1032 IN BOOLEAN Iso639Language
1033 )
1034 {
1035 UINTN NumberOfEntries;
1036 EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable;
1037 EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable;
1038 UINTN UnicodeStringLength;
1039 BOOLEAN Found;
1040 UINTN Index;
1041 CHAR8 *LanguageString;
1042
1043 //
1044 // Make sure the parameter are valid
1045 //
1046 if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
1047 return EFI_INVALID_PARAMETER;
1048 }
1049
1050 //
1051 // If there are no supported languages, then a Unicode String can not be added
1052 //
1053 if (SupportedLanguages == NULL) {
1054 return EFI_UNSUPPORTED;
1055 }
1056
1057 //
1058 // If the Unicode String is empty, then a Unicode String can not be added
1059 //
1060 if (UnicodeString[0] == 0) {
1061 return EFI_INVALID_PARAMETER;
1062 }
1063
1064 //
1065 // Make sure Language is a member of SupportedLanguages
1066 //
1067 Found = FALSE;
1068 while (*SupportedLanguages != 0) {
1069 if (Iso639Language) {
1070 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
1071 Found = TRUE;
1072 break;
1073 }
1074 SupportedLanguages += 3;
1075 } else {
1076 for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
1077 if (AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) {
1078 Found = TRUE;
1079 break;
1080 }
1081 SupportedLanguages += Index;
1082 for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
1083 }
1084 }
1085
1086 //
1087 // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
1088 //
1089 if (!Found) {
1090 return EFI_UNSUPPORTED;
1091 }
1092
1093 //
1094 // Determine the size of the Unicode String Table by looking for a NULL Language entry
1095 //
1096 NumberOfEntries = 0;
1097 if (*UnicodeStringTable != NULL) {
1098 OldUnicodeStringTable = *UnicodeStringTable;
1099 while (OldUnicodeStringTable->Language != NULL) {
1100 LanguageString = OldUnicodeStringTable->Language;
1101
1102 while (*LanguageString != 0) {
1103 for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
1104
1105 if (AsciiStrnCmp (Language, LanguageString, Index) == 0) {
1106 return EFI_ALREADY_STARTED;
1107 }
1108 LanguageString += Index;
1109 for (; *LanguageString != 0 && *LanguageString == ';'; LanguageString++);
1110 }
1111 OldUnicodeStringTable++;
1112 NumberOfEntries++;
1113 }
1114 }
1115
1116 //
1117 // Allocate space for a new Unicode String Table. It must hold the current number of
1118 // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
1119 // marker
1120 //
1121 NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
1122 if (NewUnicodeStringTable == NULL) {
1123 return EFI_OUT_OF_RESOURCES;
1124 }
1125
1126 //
1127 // If the current Unicode String Table contains any entries, then copy them to the
1128 // newly allocated Unicode String Table.
1129 //
1130 if (*UnicodeStringTable != NULL) {
1131 CopyMem (
1132 NewUnicodeStringTable,
1133 *UnicodeStringTable,
1134 NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
1135 );
1136 }
1137
1138 //
1139 // Allocate space for a copy of the Language specifier
1140 //
1141 NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (AsciiStrSize(Language), Language);
1142 if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
1143 gBS->FreePool (NewUnicodeStringTable);
1144 return EFI_OUT_OF_RESOURCES;
1145 }
1146
1147 //
1148 // Compute the length of the Unicode String
1149 //
1150 for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++);
1151
1152 //
1153 // Allocate space for a copy of the Unicode String
1154 //
1155 NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (StrSize (UnicodeString), UnicodeString);
1156 if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
1157 gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
1158 gBS->FreePool (NewUnicodeStringTable);
1159 return EFI_OUT_OF_RESOURCES;
1160 }
1161
1162 //
1163 // Mark the end of the Unicode String Table
1164 //
1165 NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL;
1166 NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;
1167
1168 //
1169 // Free the old Unicode String Table
1170 //
1171 if (*UnicodeStringTable != NULL) {
1172 gBS->FreePool (*UnicodeStringTable);
1173 }
1174
1175 //
1176 // Point UnicodeStringTable at the newly allocated Unicode String Table
1177 //
1178 *UnicodeStringTable = NewUnicodeStringTable;
1179
1180 return EFI_SUCCESS;
1181 }
1182
1183 /**
1184 This function frees the table of Unicode strings in UnicodeStringTable.
1185
1186 If UnicodeStringTable is NULL, then EFI_SUCCESS is returned.
1187 Otherwise, each language code, and each Unicode string in the Unicode string
1188 table are freed, and EFI_SUCCESS is returned.
1189
1190 @param UnicodeStringTable A pointer to the table of Unicode strings.
1191
1192 @retval EFI_SUCCESS The Unicode string table was freed.
1193
1194 **/
1195 EFI_STATUS
1196 EFIAPI
1197 FreeUnicodeStringTable (
1198 IN EFI_UNICODE_STRING_TABLE *UnicodeStringTable
1199 )
1200 {
1201 UINTN Index;
1202
1203 //
1204 // If the Unicode String Table is NULL, then it is already freed
1205 //
1206 if (UnicodeStringTable == NULL) {
1207 return EFI_SUCCESS;
1208 }
1209
1210 //
1211 // Loop through the Unicode String Table until we reach the end of table marker
1212 //
1213 for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {
1214
1215 //
1216 // Free the Language string from the Unicode String Table
1217 //
1218 gBS->FreePool (UnicodeStringTable[Index].Language);
1219
1220 //
1221 // Free the Unicode String from the Unicode String Table
1222 //
1223 if (UnicodeStringTable[Index].UnicodeString != NULL) {
1224 gBS->FreePool (UnicodeStringTable[Index].UnicodeString);
1225 }
1226 }
1227
1228 //
1229 // Free the Unicode String Table itself
1230 //
1231 gBS->FreePool (UnicodeStringTable);
1232
1233 return EFI_SUCCESS;
1234 }
1235
1236 /**
1237 Returns a pointer to an allocated buffer that contains the contents of a
1238 variable retrieved through the UEFI Runtime Service GetVariable(). The
1239 returned buffer is allocated using AllocatePool(). The caller is responsible
1240 for freeing this buffer with FreePool().
1241
1242 If Name is NULL, then ASSERT().
1243 If Guid is NULL, then ASSERT().
1244
1245 @param[in] Name Pointer to a Null-terminated Unicode string.
1246 @param[in] Guid Pointer to an EFI_GUID structure
1247
1248 @retval NULL The variable could not be retrieved.
1249 @retval NULL There are not enough resources available for the variable contents.
1250 @retval Other A pointer to allocated buffer containing the variable contents.
1251
1252 **/
1253 VOID *
1254 EFIAPI
1255 GetVariable (
1256 IN CONST CHAR16 *Name,
1257 IN CONST EFI_GUID *Guid
1258 )
1259 {
1260 EFI_STATUS Status;
1261 UINTN Size;
1262 VOID *Value;
1263
1264 ASSERT (Name != NULL);
1265 ASSERT (Guid != NULL);
1266
1267 //
1268 // Try to get the variable size.
1269 //
1270 Value = NULL;
1271 Size = 0;
1272 Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value);
1273 if (Status != EFI_BUFFER_TOO_SMALL) {
1274 return NULL;
1275 }
1276
1277 //
1278 // Allocate buffer to get the variable.
1279 //
1280 Value = AllocatePool (Size);
1281 if (Value == NULL) {
1282 return NULL;
1283 }
1284
1285 //
1286 // Get the variable data.
1287 //
1288 Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value);
1289 if (EFI_ERROR (Status)) {
1290 FreePool(Value);
1291 return NULL;
1292 }
1293
1294 return Value;
1295 }
1296
1297
1298 /**
1299 Returns a pointer to an allocated buffer that contains the contents of a
1300 variable retrieved through the UEFI Runtime Service GetVariable(). This
1301 function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.
1302 The returned buffer is allocated using AllocatePool(). The caller is
1303 responsible for freeing this buffer with FreePool().
1304
1305 If Name is NULL, then ASSERT().
1306
1307 @param[in] Name Pointer to a Null-terminated Unicode string.
1308
1309 @retval NULL The variable could not be retrieved.
1310 @retval NULL There are not enough resources available for the variable contents.
1311 @retval Other A pointer to allocated buffer containing the variable contents.
1312
1313 **/
1314 VOID *
1315 EFIAPI
1316 GetEfiGlobalVariable (
1317 IN CONST CHAR16 *Name
1318 )
1319 {
1320 return GetVariable (Name, &gEfiGlobalVariableGuid);
1321 }
1322
1323
1324 /**
1325 Returns a pointer to an allocated buffer that contains the best matching language
1326 from a set of supported languages.
1327
1328 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1329 code types may not be mixed in a single call to this function. The language
1330 code returned is allocated using AllocatePool(). The caller is responsible for
1331 freeing the allocated buffer using FreePool(). This function supports a variable
1332 argument list that allows the caller to pass in a prioritized list of language
1333 codes to test against all the language codes in SupportedLanguages.
1334
1335 If SupportedLanguages is NULL, then ASSERT().
1336
1337 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1338 contains a set of language codes in the format
1339 specified by Iso639Language.
1340 @param[in] Iso639Language If TRUE, then all language codes are assumed to be
1341 in ISO 639-2 format. If FALSE, then all language
1342 codes are assumed to be in RFC 4646 language format
1343 @param[in] ... A variable argument list that contains pointers to
1344 Null-terminated ASCII strings that contain one or more
1345 language codes in the format specified by Iso639Language.
1346 The first language code from each of these language
1347 code lists is used to determine if it is an exact or
1348 close match to any of the language codes in
1349 SupportedLanguages. Close matches only apply to RFC 4646
1350 language codes, and the matching algorithm from RFC 4647
1351 is used to determine if a close match is present. If
1352 an exact or close match is found, then the matching
1353 language code from SupportedLanguages is returned. If
1354 no matches are found, then the next variable argument
1355 parameter is evaluated. The variable argument list
1356 is terminated by a NULL.
1357
1358 @retval NULL The best matching language could not be found in SupportedLanguages.
1359 @retval NULL There are not enough resources available to return the best matching
1360 language.
1361 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1362 language in SupportedLanguages.
1363
1364 **/
1365 CHAR8 *
1366 EFIAPI
1367 GetBestLanguage (
1368 IN CONST CHAR8 *SupportedLanguages,
1369 IN BOOLEAN Iso639Language,
1370 ...
1371 )
1372 {
1373 VA_LIST Args;
1374 CHAR8 *Language;
1375 UINTN CompareLength;
1376 UINTN LanguageLength;
1377 CONST CHAR8 *Supported;
1378 CHAR8 *BestLanguage;
1379
1380 ASSERT (SupportedLanguages != NULL);
1381
1382 VA_START (Args, Iso639Language);
1383 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
1384 //
1385 // Default to ISO 639-2 mode
1386 //
1387 CompareLength = 3;
1388 LanguageLength = MIN (3, AsciiStrLen (Language));
1389
1390 //
1391 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1392 //
1393 if (!Iso639Language) {
1394 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
1395 }
1396
1397 //
1398 // Trim back the length of Language used until it is empty
1399 //
1400 while (LanguageLength > 0) {
1401 //
1402 // Loop through all language codes in SupportedLanguages
1403 //
1404 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
1405 //
1406 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1407 //
1408 if (!Iso639Language) {
1409 //
1410 // Skip ';' characters in Supported
1411 //
1412 for (; *Supported != '\0' && *Supported == ';'; Supported++);
1413 //
1414 // Determine the length of the next language code in Supported
1415 //
1416 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
1417 //
1418 // If Language is longer than the Supported, then skip to the next language
1419 //
1420 if (LanguageLength > CompareLength) {
1421 continue;
1422 }
1423 }
1424 //
1425 // See if the first LanguageLength characters in Supported match Language
1426 //
1427 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
1428 VA_END (Args);
1429 //
1430 // Allocate, copy, and return the best matching language code from SupportedLanguages
1431 //
1432 BestLanguage = AllocateZeroPool (CompareLength + 1);
1433 if (BestLanguage == NULL) {
1434 return NULL;
1435 }
1436 return CopyMem (BestLanguage, Supported, CompareLength);
1437 }
1438 }
1439
1440 if (Iso639Language) {
1441 //
1442 // If ISO 639 mode, then each language can only be tested once
1443 //
1444 LanguageLength = 0;
1445 } else {
1446 //
1447 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1448 //
1449 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
1450 }
1451 }
1452 }
1453 VA_END (Args);
1454
1455 //
1456 // No matches were found
1457 //
1458 return NULL;
1459 }
1460
1461 /**
1462 An empty function to pass error checking of CreateEventEx ().
1463
1464 This empty function ensures that EVT_NOTIFY_SIGNAL_ALL is error
1465 checked correctly since it is now mapped into CreateEventEx() in UEFI 2.0.
1466
1467 @param Event Event whose notification function is being invoked.
1468 @param Context Pointer to the notification function's context,
1469 which is implementation-dependent.
1470
1471 **/
1472 VOID
1473 EFIAPI
1474 InternalEmptyFunction (
1475 IN EFI_EVENT Event,
1476 IN VOID *Context
1477 )
1478 {
1479 }