/** @file | |
The UEFI Library provides functions and macros that simplify the development of | |
UEFI Drivers and UEFI Applications. These functions and macros help manage EFI | |
events, build simple locks utilizing EFI Task Priority Levels (TPLs), install | |
EFI Driver Model related protocols, manage Unicode string tables for UEFI Drivers, | |
and print messages on the console output and standard error devices. | |
Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php. | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "UefiLibInternal.h" | |
/** | |
Empty constructor function that is required to resolve dependencies between | |
libraries. | |
** DO NOT REMOVE ** | |
@param ImageHandle The firmware allocated handle for the EFI image. | |
@param SystemTable A pointer to the EFI System Table. | |
@retval EFI_SUCCESS The constructor executed correctly. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UefiLibConstructor ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
return EFI_SUCCESS; | |
} | |
/** | |
Compare whether two names of languages are identical. | |
@param Language1 Name of language 1. | |
@param Language2 Name of language 2. | |
@retval TRUE Language 1 and language 2 are the same. | |
@retval FALSE Language 1 and language 2 are not the same. | |
**/ | |
BOOLEAN | |
CompareIso639LanguageCode ( | |
IN CONST CHAR8 *Language1, | |
IN CONST CHAR8 *Language2 | |
) | |
{ | |
UINT32 Name1; | |
UINT32 Name2; | |
Name1 = ReadUnaligned24 ((CONST UINT32 *) Language1); | |
Name2 = ReadUnaligned24 ((CONST UINT32 *) Language2); | |
return (BOOLEAN) (Name1 == Name2); | |
} | |
/** | |
Retrieves a pointer to the system configuration table from the EFI System Table | |
based on a specified GUID. | |
This function searches the list of configuration tables stored in the EFI System Table | |
for a table with a GUID that matches TableGuid. If a match is found, then a pointer to | |
the configuration table is returned in Table., and EFI_SUCCESS is returned. If a matching GUID | |
is not found, then EFI_NOT_FOUND is returned. | |
If TableGuid is NULL, then ASSERT(). | |
If Table is NULL, then ASSERT(). | |
@param TableGuid The pointer to table's GUID type. | |
@param Table The pointer to the table associated with TableGuid in the EFI System Table. | |
@retval EFI_SUCCESS A configuration table matching TableGuid was found. | |
@retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
EfiGetSystemConfigurationTable ( | |
IN EFI_GUID *TableGuid, | |
OUT VOID **Table | |
) | |
{ | |
EFI_SYSTEM_TABLE *SystemTable; | |
UINTN Index; | |
ASSERT (TableGuid != NULL); | |
ASSERT (Table != NULL); | |
SystemTable = gST; | |
*Table = NULL; | |
for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) { | |
if (CompareGuid (TableGuid, &(SystemTable->ConfigurationTable[Index].VendorGuid))) { | |
*Table = SystemTable->ConfigurationTable[Index].VendorTable; | |
return EFI_SUCCESS; | |
} | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
Creates and returns a notification event and registers that event with all the protocol | |
instances specified by ProtocolGuid. | |
This function causes the notification function to be executed for every protocol of type | |
ProtocolGuid instance that exists in the system when this function is invoked. If there are | |
no instances of ProtocolGuid in the handle database at the time this function is invoked, | |
then the notification function is still executed one time. In addition, every time a protocol | |
of type ProtocolGuid instance is installed or reinstalled, the notification function is also | |
executed. This function returns the notification event that was created. | |
If ProtocolGuid is NULL, then ASSERT(). | |
If NotifyTpl is not a legal TPL value, then ASSERT(). | |
If NotifyFunction is NULL, then ASSERT(). | |
If Registration is NULL, then ASSERT(). | |
@param ProtocolGuid Supplies GUID of the protocol upon whose installation the event is fired. | |
@param NotifyTpl Supplies the task priority level of the event notifications. | |
@param NotifyFunction Supplies the function to notify when the event is signaled. | |
@param NotifyContext The context parameter to pass to NotifyFunction. | |
@param Registration A pointer to a memory location to receive the registration value. | |
This value is passed to LocateHandle() to obtain new handles that | |
have been added that support the ProtocolGuid-specified protocol. | |
@return The notification event that was created. | |
**/ | |
EFI_EVENT | |
EFIAPI | |
EfiCreateProtocolNotifyEvent( | |
IN EFI_GUID *ProtocolGuid, | |
IN EFI_TPL NotifyTpl, | |
IN EFI_EVENT_NOTIFY NotifyFunction, | |
IN VOID *NotifyContext, OPTIONAL | |
OUT VOID **Registration | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_EVENT Event; | |
ASSERT (ProtocolGuid != NULL); | |
ASSERT (NotifyFunction != NULL); | |
ASSERT (Registration != NULL); | |
// | |
// Create the event | |
// | |
Status = gBS->CreateEvent ( | |
EVT_NOTIFY_SIGNAL, | |
NotifyTpl, | |
NotifyFunction, | |
NotifyContext, | |
&Event | |
); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Register for protocol notifications on this event | |
// | |
Status = gBS->RegisterProtocolNotify ( | |
ProtocolGuid, | |
Event, | |
Registration | |
); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Kick the event so we will perform an initial pass of | |
// current installed drivers | |
// | |
gBS->SignalEvent (Event); | |
return Event; | |
} | |
/** | |
Creates a named event that can be signaled with EfiNamedEventSignal(). | |
This function creates an event using NotifyTpl, NoifyFunction, and NotifyContext. | |
This event is signaled with EfiNamedEventSignal(). This provides the ability for one or more | |
listeners on the same event named by the GUID specified by Name. | |
If Name is NULL, then ASSERT(). | |
If NotifyTpl is not a legal TPL value, then ASSERT(). | |
If NotifyFunction is NULL, then ASSERT(). | |
@param Name Supplies the GUID name of the event. | |
@param NotifyTpl Supplies the task priority level of the event notifications. | |
@param NotifyFunction Supplies the function to notify when the event is signaled. | |
@param NotifyContext The context parameter to pass to NotifyFunction. | |
@param Registration A pointer to a memory location to receive the registration value. | |
@retval EFI_SUCCESS A named event was created. | |
@retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
EfiNamedEventListen ( | |
IN CONST EFI_GUID *Name, | |
IN EFI_TPL NotifyTpl, | |
IN EFI_EVENT_NOTIFY NotifyFunction, | |
IN CONST VOID *NotifyContext, OPTIONAL | |
OUT VOID *Registration OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_EVENT Event; | |
VOID *RegistrationLocal; | |
ASSERT (Name != NULL); | |
ASSERT (NotifyFunction != NULL); | |
ASSERT (NotifyTpl <= TPL_HIGH_LEVEL); | |
// | |
// Create event | |
// | |
Status = gBS->CreateEvent ( | |
EVT_NOTIFY_SIGNAL, | |
NotifyTpl, | |
NotifyFunction, | |
(VOID *) NotifyContext, | |
&Event | |
); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// The Registration is not optional to RegisterProtocolNotify(). | |
// To make it optional to EfiNamedEventListen(), may need to substitute with a local. | |
// | |
if (Registration != NULL) { | |
RegistrationLocal = Registration; | |
} else { | |
RegistrationLocal = &RegistrationLocal; | |
} | |
// | |
// Register for an installation of protocol interface | |
// | |
Status = gBS->RegisterProtocolNotify ( | |
(EFI_GUID *) Name, | |
Event, | |
RegistrationLocal | |
); | |
ASSERT_EFI_ERROR (Status); | |
return Status; | |
} | |
/** | |
Signals a named event created with EfiNamedEventListen(). | |
This function signals the named event specified by Name. The named event must have been | |
created with EfiNamedEventListen(). | |
If Name is NULL, then ASSERT(). | |
@param Name Supplies the GUID name of the event. | |
@retval EFI_SUCCESS A named event was signaled. | |
@retval EFI_OUT_OF_RESOURCES There are not enough resource to signal the named event. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
EfiNamedEventSignal ( | |
IN CONST EFI_GUID *Name | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE Handle; | |
ASSERT(Name != NULL); | |
Handle = NULL; | |
Status = gBS->InstallProtocolInterface ( | |
&Handle, | |
(EFI_GUID *) Name, | |
EFI_NATIVE_INTERFACE, | |
NULL | |
); | |
ASSERT_EFI_ERROR (Status); | |
Status = gBS->UninstallProtocolInterface ( | |
Handle, | |
(EFI_GUID *) Name, | |
NULL | |
); | |
ASSERT_EFI_ERROR (Status); | |
return Status; | |
} | |
/** | |
Returns the current TPL. | |
This function returns the current TPL. There is no EFI service to directly | |
retrieve the current TPL. Instead, the RaiseTPL() function is used to raise | |
the TPL to TPL_HIGH_LEVEL. This will return the current TPL. The TPL level | |
can then immediately be restored back to the current TPL level with a call | |
to RestoreTPL(). | |
@return The current TPL. | |
**/ | |
EFI_TPL | |
EFIAPI | |
EfiGetCurrentTpl ( | |
VOID | |
) | |
{ | |
EFI_TPL Tpl; | |
Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); | |
gBS->RestoreTPL (Tpl); | |
return Tpl; | |
} | |
/** | |
Initializes a basic mutual exclusion lock. | |
This function initializes a basic mutual exclusion lock to the released state | |
and returns the lock. Each lock provides mutual exclusion access at its task | |
priority level. Since there is no preemption or multiprocessor support in EFI, | |
acquiring the lock only consists of raising to the locks TPL. | |
If Lock is NULL, then ASSERT(). | |
If Priority is not a valid TPL value, then ASSERT(). | |
@param Lock A pointer to the lock data structure to initialize. | |
@param Priority EFI TPL is associated with the lock. | |
@return The lock. | |
**/ | |
EFI_LOCK * | |
EFIAPI | |
EfiInitializeLock ( | |
IN OUT EFI_LOCK *Lock, | |
IN EFI_TPL Priority | |
) | |
{ | |
ASSERT (Lock != NULL); | |
ASSERT (Priority <= TPL_HIGH_LEVEL); | |
Lock->Tpl = Priority; | |
Lock->OwnerTpl = TPL_APPLICATION; | |
Lock->Lock = EfiLockReleased ; | |
return Lock; | |
} | |
/** | |
Acquires ownership of a lock. | |
This function raises the system's current task priority level to the task | |
priority level of the mutual exclusion lock. Then, it places the lock in the | |
acquired state. | |
If Lock is NULL, then ASSERT(). | |
If Lock is not initialized, then ASSERT(). | |
If Lock is already in the acquired state, then ASSERT(). | |
@param Lock A pointer to the lock to acquire. | |
**/ | |
VOID | |
EFIAPI | |
EfiAcquireLock ( | |
IN EFI_LOCK *Lock | |
) | |
{ | |
ASSERT (Lock != NULL); | |
ASSERT (Lock->Lock == EfiLockReleased); | |
Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl); | |
Lock->Lock = EfiLockAcquired; | |
} | |
/** | |
Acquires ownership of a lock. | |
This function raises the system's current task priority level to the task priority | |
level of the mutual exclusion lock. Then, it attempts to place the lock in the acquired state. | |
If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned. | |
Otherwise, EFI_SUCCESS is returned. | |
If Lock is NULL, then ASSERT(). | |
If Lock is not initialized, then ASSERT(). | |
@param Lock A pointer to the lock to acquire. | |
@retval EFI_SUCCESS The lock was acquired. | |
@retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
EfiAcquireLockOrFail ( | |
IN EFI_LOCK *Lock | |
) | |
{ | |
ASSERT (Lock != NULL); | |
ASSERT (Lock->Lock != EfiLockUninitialized); | |
if (Lock->Lock == EfiLockAcquired) { | |
// | |
// Lock is already owned, so bail out | |
// | |
return EFI_ACCESS_DENIED; | |
} | |
Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl); | |
Lock->Lock = EfiLockAcquired; | |
return EFI_SUCCESS; | |
} | |
/** | |
Releases ownership of a lock. | |
This function transitions a mutual exclusion lock from the acquired state to | |
the released state, and restores the system's task priority level to its | |
previous level. | |
If Lock is NULL, then ASSERT(). | |
If Lock is not initialized, then ASSERT(). | |
If Lock is already in the released state, then ASSERT(). | |
@param Lock A pointer to the lock to release. | |
**/ | |
VOID | |
EFIAPI | |
EfiReleaseLock ( | |
IN EFI_LOCK *Lock | |
) | |
{ | |
EFI_TPL Tpl; | |
ASSERT (Lock != NULL); | |
ASSERT (Lock->Lock == EfiLockAcquired); | |
Tpl = Lock->OwnerTpl; | |
Lock->Lock = EfiLockReleased; | |
gBS->RestoreTPL (Tpl); | |
} | |
/** | |
Tests whether a controller handle is being managed by a specific driver. | |
This function tests whether the driver specified by DriverBindingHandle is | |
currently managing the controller specified by ControllerHandle. This test | |
is performed by evaluating if the the protocol specified by ProtocolGuid is | |
present on ControllerHandle and is was opened by DriverBindingHandle with an | |
attribute of EFI_OPEN_PROTOCOL_BY_DRIVER. | |
If ProtocolGuid is NULL, then ASSERT(). | |
@param ControllerHandle A handle for a controller to test. | |
@param DriverBindingHandle Specifies the driver binding handle for the | |
driver. | |
@param ProtocolGuid Specifies the protocol that the driver specified | |
by DriverBindingHandle opens in its Start() | |
function. | |
@retval EFI_SUCCESS ControllerHandle is managed by the driver | |
specified by DriverBindingHandle. | |
@retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver | |
specified by DriverBindingHandle. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
EfiTestManagedDevice ( | |
IN CONST EFI_HANDLE ControllerHandle, | |
IN CONST EFI_HANDLE DriverBindingHandle, | |
IN CONST EFI_GUID *ProtocolGuid | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *ManagedInterface; | |
ASSERT (ProtocolGuid != NULL); | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
(EFI_GUID *) ProtocolGuid, | |
&ManagedInterface, | |
DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (!EFI_ERROR (Status)) { | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
(EFI_GUID *) ProtocolGuid, | |
DriverBindingHandle, | |
ControllerHandle | |
); | |
return EFI_UNSUPPORTED; | |
} | |
if (Status != EFI_ALREADY_STARTED) { | |
return EFI_UNSUPPORTED; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Tests whether a child handle is a child device of the controller. | |
This function tests whether ChildHandle is one of the children of | |
ControllerHandle. This test is performed by checking to see if the protocol | |
specified by ProtocolGuid is present on ControllerHandle and opened by | |
ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. | |
If ProtocolGuid is NULL, then ASSERT(). | |
@param ControllerHandle A handle for a (parent) controller to test. | |
@param ChildHandle A child handle to test. | |
@param ProtocolGuid Supplies the protocol that the child controller | |
opens on its parent controller. | |
@retval EFI_SUCCESS ChildHandle is a child of the ControllerHandle. | |
@retval EFI_UNSUPPORTED ChildHandle is not a child of the | |
ControllerHandle. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
EfiTestChildHandle ( | |
IN CONST EFI_HANDLE ControllerHandle, | |
IN CONST EFI_HANDLE ChildHandle, | |
IN CONST EFI_GUID *ProtocolGuid | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; | |
UINTN EntryCount; | |
UINTN Index; | |
ASSERT (ProtocolGuid != NULL); | |
// | |
// Retrieve the list of agents that are consuming the specific protocol | |
// on ControllerHandle. | |
// | |
Status = gBS->OpenProtocolInformation ( | |
ControllerHandle, | |
(EFI_GUID *) ProtocolGuid, | |
&OpenInfoBuffer, | |
&EntryCount | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Inspect if ChildHandle is one of the agents. | |
// | |
Status = EFI_UNSUPPORTED; | |
for (Index = 0; Index < EntryCount; Index++) { | |
if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) && | |
(OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { | |
Status = EFI_SUCCESS; | |
break; | |
} | |
} | |
FreePool (OpenInfoBuffer); | |
return Status; | |
} | |
/** | |
This function looks up a Unicode string in UnicodeStringTable. | |
If Language is a member of SupportedLanguages and a Unicode string is found in | |
UnicodeStringTable that matches the language code specified by Language, then it | |
is returned in UnicodeString. | |
@param Language A pointer to the ISO 639-2 language code for the | |
Unicode string to look up and return. | |
@param SupportedLanguages A pointer to the set of ISO 639-2 language codes | |
that the Unicode string table supports. Language | |
must be a member of this set. | |
@param UnicodeStringTable A pointer to the table of Unicode strings. | |
@param UnicodeString A pointer to the Unicode string from UnicodeStringTable | |
that matches the language specified by Language. | |
@retval EFI_SUCCESS The Unicode string that matches the language | |
specified by Language was found | |
in the table of Unicode strings UnicodeStringTable, | |
and it was returned in UnicodeString. | |
@retval EFI_INVALID_PARAMETER Language is NULL. | |
@retval EFI_INVALID_PARAMETER UnicodeString is NULL. | |
@retval EFI_UNSUPPORTED SupportedLanguages is NULL. | |
@retval EFI_UNSUPPORTED UnicodeStringTable is NULL. | |
@retval EFI_UNSUPPORTED The language specified by Language is not a | |
member of SupportedLanguages. | |
@retval EFI_UNSUPPORTED The language specified by Language is not | |
supported by UnicodeStringTable. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
LookupUnicodeString ( | |
IN CONST CHAR8 *Language, | |
IN CONST CHAR8 *SupportedLanguages, | |
IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable, | |
OUT CHAR16 **UnicodeString | |
) | |
{ | |
// | |
// Make sure the parameters are valid | |
// | |
if (Language == NULL || UnicodeString == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// If there are no supported languages, or the Unicode String Table is empty, then the | |
// Unicode String specified by Language is not supported by this Unicode String Table | |
// | |
if (SupportedLanguages == NULL || UnicodeStringTable == NULL) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Make sure Language is in the set of Supported Languages | |
// | |
while (*SupportedLanguages != 0) { | |
if (CompareIso639LanguageCode (Language, SupportedLanguages)) { | |
// | |
// Search the Unicode String Table for the matching Language specifier | |
// | |
while (UnicodeStringTable->Language != NULL) { | |
if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) { | |
// | |
// A matching string was found, so return it | |
// | |
*UnicodeString = UnicodeStringTable->UnicodeString; | |
return EFI_SUCCESS; | |
} | |
UnicodeStringTable++; | |
} | |
return EFI_UNSUPPORTED; | |
} | |
SupportedLanguages += 3; | |
} | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
This function looks up a Unicode string in UnicodeStringTable. | |
If Language is a member of SupportedLanguages and a Unicode string is found in | |
UnicodeStringTable that matches the language code specified by Language, then | |
it is returned in UnicodeString. | |
@param Language A pointer to an ASCII string containing the ISO 639-2 or the | |
RFC 4646 language code for the Unicode string to look up and | |
return. If Iso639Language is TRUE, then this ASCII string is | |
not assumed to be Null-terminated, and only the first three | |
characters are used. If Iso639Language is FALSE, then this ASCII | |
string must be Null-terminated. | |
@param SupportedLanguages A pointer to a Null-terminated ASCII string that contains a | |
set of ISO 639-2 or RFC 4646 language codes that the Unicode | |
string table supports. Language must be a member of this set. | |
If Iso639Language is TRUE, then this string contains one or more | |
ISO 639-2 language codes with no separator characters. If Iso639Language | |
is FALSE, then is string contains one or more RFC 4646 language | |
codes separated by ';'. | |
@param UnicodeStringTable A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE | |
is defined in "Related Definitions". | |
@param UnicodeString A pointer to the Null-terminated Unicode string from UnicodeStringTable | |
that matches the language specified by Language. | |
@param Iso639Language Specifies the supported language code format. If it is TRUE, then | |
Language and SupportedLanguages follow ISO 639-2 language code format. | |
Otherwise, they follow RFC 4646 language code format. | |
@retval EFI_SUCCESS The Unicode string that matches the language specified by Language | |
was found in the table of Unicode strings UnicodeStringTable, and | |
it was returned in UnicodeString. | |
@retval EFI_INVALID_PARAMETER Language is NULL. | |
@retval EFI_INVALID_PARAMETER UnicodeString is NULL. | |
@retval EFI_UNSUPPORTED SupportedLanguages is NULL. | |
@retval EFI_UNSUPPORTED UnicodeStringTable is NULL. | |
@retval EFI_UNSUPPORTED The language specified by Language is not a member of SupportedLanguages. | |
@retval EFI_UNSUPPORTED The language specified by Language is not supported by UnicodeStringTable. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
LookupUnicodeString2 ( | |
IN CONST CHAR8 *Language, | |
IN CONST CHAR8 *SupportedLanguages, | |
IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable, | |
OUT CHAR16 **UnicodeString, | |
IN BOOLEAN Iso639Language | |
) | |
{ | |
BOOLEAN Found; | |
UINTN Index; | |
CHAR8 *LanguageString; | |
// | |
// Make sure the parameters are valid | |
// | |
if (Language == NULL || UnicodeString == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// If there are no supported languages, or the Unicode String Table is empty, then the | |
// Unicode String specified by Language is not supported by this Unicode String Table | |
// | |
if (SupportedLanguages == NULL || UnicodeStringTable == NULL) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Make sure Language is in the set of Supported Languages | |
// | |
Found = FALSE; | |
while (*SupportedLanguages != 0) { | |
if (Iso639Language) { | |
if (CompareIso639LanguageCode (Language, SupportedLanguages)) { | |
Found = TRUE; | |
break; | |
} | |
SupportedLanguages += 3; | |
} else { | |
for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++); | |
if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) { | |
Found = TRUE; | |
break; | |
} | |
SupportedLanguages += Index; | |
for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++); | |
} | |
} | |
// | |
// If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED | |
// | |
if (!Found) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Search the Unicode String Table for the matching Language specifier | |
// | |
while (UnicodeStringTable->Language != NULL) { | |
LanguageString = UnicodeStringTable->Language; | |
while (0 != *LanguageString) { | |
for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++); | |
if (AsciiStrnCmp(LanguageString, Language, Index) == 0) { | |
*UnicodeString = UnicodeStringTable->UnicodeString; | |
return EFI_SUCCESS; | |
} | |
LanguageString += Index; | |
for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] == ';'; Index++); | |
} | |
UnicodeStringTable++; | |
} | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
This function adds a Unicode string to UnicodeStringTable. | |
If Language is a member of SupportedLanguages then UnicodeString is added to | |
UnicodeStringTable. New buffers are allocated for both Language and | |
UnicodeString. The contents of Language and UnicodeString are copied into | |
these new buffers. These buffers are automatically freed when | |
FreeUnicodeStringTable() is called. | |
@param Language A pointer to the ISO 639-2 language code for the Unicode | |
string to add. | |
@param SupportedLanguages A pointer to the set of ISO 639-2 language codes | |
that the Unicode string table supports. | |
Language must be a member of this set. | |
@param UnicodeStringTable A pointer to the table of Unicode strings. | |
@param UnicodeString A pointer to the Unicode string to add. | |
@retval EFI_SUCCESS The Unicode string that matches the language | |
specified by Language was found in the table of | |
Unicode strings UnicodeStringTable, and it was | |
returned in UnicodeString. | |
@retval EFI_INVALID_PARAMETER Language is NULL. | |
@retval EFI_INVALID_PARAMETER UnicodeString is NULL. | |
@retval EFI_INVALID_PARAMETER UnicodeString is an empty string. | |
@retval EFI_UNSUPPORTED SupportedLanguages is NULL. | |
@retval EFI_ALREADY_STARTED A Unicode string with language Language is | |
already present in UnicodeStringTable. | |
@retval EFI_OUT_OF_RESOURCES There is not enough memory to add another | |
Unicode string to UnicodeStringTable. | |
@retval EFI_UNSUPPORTED The language specified by Language is not a | |
member of SupportedLanguages. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
AddUnicodeString ( | |
IN CONST CHAR8 *Language, | |
IN CONST CHAR8 *SupportedLanguages, | |
IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable, | |
IN CONST CHAR16 *UnicodeString | |
) | |
{ | |
UINTN NumberOfEntries; | |
EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable; | |
EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable; | |
UINTN UnicodeStringLength; | |
// | |
// Make sure the parameter are valid | |
// | |
if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// If there are no supported languages, then a Unicode String can not be added | |
// | |
if (SupportedLanguages == NULL) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// If the Unicode String is empty, then a Unicode String can not be added | |
// | |
if (UnicodeString[0] == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Make sure Language is a member of SupportedLanguages | |
// | |
while (*SupportedLanguages != 0) { | |
if (CompareIso639LanguageCode (Language, SupportedLanguages)) { | |
// | |
// Determine the size of the Unicode String Table by looking for a NULL Language entry | |
// | |
NumberOfEntries = 0; | |
if (*UnicodeStringTable != NULL) { | |
OldUnicodeStringTable = *UnicodeStringTable; | |
while (OldUnicodeStringTable->Language != NULL) { | |
if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) { | |
return EFI_ALREADY_STARTED; | |
} | |
OldUnicodeStringTable++; | |
NumberOfEntries++; | |
} | |
} | |
// | |
// Allocate space for a new Unicode String Table. It must hold the current number of | |
// entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table | |
// marker | |
// | |
NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE)); | |
if (NewUnicodeStringTable == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// If the current Unicode String Table contains any entries, then copy them to the | |
// newly allocated Unicode String Table. | |
// | |
if (*UnicodeStringTable != NULL) { | |
CopyMem ( | |
NewUnicodeStringTable, | |
*UnicodeStringTable, | |
NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE) | |
); | |
} | |
// | |
// Allocate space for a copy of the Language specifier | |
// | |
NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language); | |
if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) { | |
FreePool (NewUnicodeStringTable); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Compute the length of the Unicode String | |
// | |
for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++) | |
; | |
// | |
// Allocate space for a copy of the Unicode String | |
// | |
NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool ( | |
(UnicodeStringLength + 1) * sizeof (CHAR16), | |
UnicodeString | |
); | |
if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) { | |
FreePool (NewUnicodeStringTable[NumberOfEntries].Language); | |
FreePool (NewUnicodeStringTable); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Mark the end of the Unicode String Table | |
// | |
NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL; | |
NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL; | |
// | |
// Free the old Unicode String Table | |
// | |
if (*UnicodeStringTable != NULL) { | |
FreePool (*UnicodeStringTable); | |
} | |
// | |
// Point UnicodeStringTable at the newly allocated Unicode String Table | |
// | |
*UnicodeStringTable = NewUnicodeStringTable; | |
return EFI_SUCCESS; | |
} | |
SupportedLanguages += 3; | |
} | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
This function adds the Null-terminated Unicode string specified by UnicodeString | |
to UnicodeStringTable. | |
If Language is a member of SupportedLanguages then UnicodeString is added to | |
UnicodeStringTable. New buffers are allocated for both Language and UnicodeString. | |
The contents of Language and UnicodeString are copied into these new buffers. | |
These buffers are automatically freed when EfiLibFreeUnicodeStringTable() is called. | |
@param Language A pointer to an ASCII string containing the ISO 639-2 or | |
the RFC 4646 language code for the Unicode string to add. | |
If Iso639Language is TRUE, then this ASCII string is not | |
assumed to be Null-terminated, and only the first three | |
chacters are used. If Iso639Language is FALSE, then this | |
ASCII string must be Null-terminated. | |
@param SupportedLanguages A pointer to a Null-terminated ASCII string that contains | |
a set of ISO 639-2 or RFC 4646 language codes that the Unicode | |
string table supports. Language must be a member of this set. | |
If Iso639Language is TRUE, then this string contains one or more | |
ISO 639-2 language codes with no separator characters. | |
If Iso639Language is FALSE, then is string contains one or more | |
RFC 4646 language codes separated by ';'. | |
@param UnicodeStringTable A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE | |
is defined in "Related Definitions". | |
@param UnicodeString A pointer to the Unicode string to add. | |
@param Iso639Language Specifies the supported language code format. If it is TRUE, | |
then Language and SupportedLanguages follow ISO 639-2 language code format. | |
Otherwise, they follow RFC 4646 language code format. | |
@retval EFI_SUCCESS The Unicode string that matches the language specified by | |
Language was found in the table of Unicode strings UnicodeStringTable, | |
and it was returned in UnicodeString. | |
@retval EFI_INVALID_PARAMETER Language is NULL. | |
@retval EFI_INVALID_PARAMETER UnicodeString is NULL. | |
@retval EFI_INVALID_PARAMETER UnicodeString is an empty string. | |
@retval EFI_UNSUPPORTED SupportedLanguages is NULL. | |
@retval EFI_ALREADY_STARTED A Unicode string with language Language is already present in | |
UnicodeStringTable. | |
@retval EFI_OUT_OF_RESOURCES There is not enough memory to add another Unicode string UnicodeStringTable. | |
@retval EFI_UNSUPPORTED The language specified by Language is not a member of SupportedLanguages. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
AddUnicodeString2 ( | |
IN CONST CHAR8 *Language, | |
IN CONST CHAR8 *SupportedLanguages, | |
IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable, | |
IN CONST CHAR16 *UnicodeString, | |
IN BOOLEAN Iso639Language | |
) | |
{ | |
UINTN NumberOfEntries; | |
EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable; | |
EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable; | |
UINTN UnicodeStringLength; | |
BOOLEAN Found; | |
UINTN Index; | |
CHAR8 *LanguageString; | |
// | |
// Make sure the parameter are valid | |
// | |
if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// If there are no supported languages, then a Unicode String can not be added | |
// | |
if (SupportedLanguages == NULL) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// If the Unicode String is empty, then a Unicode String can not be added | |
// | |
if (UnicodeString[0] == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Make sure Language is a member of SupportedLanguages | |
// | |
Found = FALSE; | |
while (*SupportedLanguages != 0) { | |
if (Iso639Language) { | |
if (CompareIso639LanguageCode (Language, SupportedLanguages)) { | |
Found = TRUE; | |
break; | |
} | |
SupportedLanguages += 3; | |
} else { | |
for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++); | |
if (AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) { | |
Found = TRUE; | |
break; | |
} | |
SupportedLanguages += Index; | |
for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++); | |
} | |
} | |
// | |
// If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED | |
// | |
if (!Found) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Determine the size of the Unicode String Table by looking for a NULL Language entry | |
// | |
NumberOfEntries = 0; | |
if (*UnicodeStringTable != NULL) { | |
OldUnicodeStringTable = *UnicodeStringTable; | |
while (OldUnicodeStringTable->Language != NULL) { | |
LanguageString = OldUnicodeStringTable->Language; | |
while (*LanguageString != 0) { | |
for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++); | |
if (AsciiStrnCmp (Language, LanguageString, Index) == 0) { | |
return EFI_ALREADY_STARTED; | |
} | |
LanguageString += Index; | |
for (; *LanguageString != 0 && *LanguageString == ';'; LanguageString++); | |
} | |
OldUnicodeStringTable++; | |
NumberOfEntries++; | |
} | |
} | |
// | |
// Allocate space for a new Unicode String Table. It must hold the current number of | |
// entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table | |
// marker | |
// | |
NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE)); | |
if (NewUnicodeStringTable == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// If the current Unicode String Table contains any entries, then copy them to the | |
// newly allocated Unicode String Table. | |
// | |
if (*UnicodeStringTable != NULL) { | |
CopyMem ( | |
NewUnicodeStringTable, | |
*UnicodeStringTable, | |
NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE) | |
); | |
} | |
// | |
// Allocate space for a copy of the Language specifier | |
// | |
NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (AsciiStrSize(Language), Language); | |
if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) { | |
FreePool (NewUnicodeStringTable); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Compute the length of the Unicode String | |
// | |
for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++); | |
// | |
// Allocate space for a copy of the Unicode String | |
// | |
NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (StrSize (UnicodeString), UnicodeString); | |
if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) { | |
FreePool (NewUnicodeStringTable[NumberOfEntries].Language); | |
FreePool (NewUnicodeStringTable); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Mark the end of the Unicode String Table | |
// | |
NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL; | |
NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL; | |
// | |
// Free the old Unicode String Table | |
// | |
if (*UnicodeStringTable != NULL) { | |
FreePool (*UnicodeStringTable); | |
} | |
// | |
// Point UnicodeStringTable at the newly allocated Unicode String Table | |
// | |
*UnicodeStringTable = NewUnicodeStringTable; | |
return EFI_SUCCESS; | |
} | |
/** | |
This function frees the table of Unicode strings in UnicodeStringTable. | |
If UnicodeStringTable is NULL, then EFI_SUCCESS is returned. | |
Otherwise, each language code, and each Unicode string in the Unicode string | |
table are freed, and EFI_SUCCESS is returned. | |
@param UnicodeStringTable A pointer to the table of Unicode strings. | |
@retval EFI_SUCCESS The Unicode string table was freed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FreeUnicodeStringTable ( | |
IN EFI_UNICODE_STRING_TABLE *UnicodeStringTable | |
) | |
{ | |
UINTN Index; | |
// | |
// If the Unicode String Table is NULL, then it is already freed | |
// | |
if (UnicodeStringTable == NULL) { | |
return EFI_SUCCESS; | |
} | |
// | |
// Loop through the Unicode String Table until we reach the end of table marker | |
// | |
for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) { | |
// | |
// Free the Language string from the Unicode String Table | |
// | |
FreePool (UnicodeStringTable[Index].Language); | |
// | |
// Free the Unicode String from the Unicode String Table | |
// | |
if (UnicodeStringTable[Index].UnicodeString != NULL) { | |
FreePool (UnicodeStringTable[Index].UnicodeString); | |
} | |
} | |
// | |
// Free the Unicode String Table itself | |
// | |
FreePool (UnicodeStringTable); | |
return EFI_SUCCESS; | |
} | |
#ifndef DISABLE_NEW_DEPRECATED_INTERFACES | |
/** | |
[ATTENTION] This function will be deprecated for security reason. | |
Returns a pointer to an allocated buffer that contains the contents of a | |
variable retrieved through the UEFI Runtime Service GetVariable(). The | |
returned buffer is allocated using AllocatePool(). The caller is responsible | |
for freeing this buffer with FreePool(). | |
If Name is NULL, then ASSERT(). | |
If Guid is NULL, then ASSERT(). | |
@param[in] Name The pointer to a Null-terminated Unicode string. | |
@param[in] Guid The pointer to an EFI_GUID structure | |
@retval NULL The variable could not be retrieved. | |
@retval NULL There are not enough resources available for the variable contents. | |
@retval Other A pointer to allocated buffer containing the variable contents. | |
**/ | |
VOID * | |
EFIAPI | |
GetVariable ( | |
IN CONST CHAR16 *Name, | |
IN CONST EFI_GUID *Guid | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Size; | |
VOID *Value; | |
ASSERT (Name != NULL); | |
ASSERT (Guid != NULL); | |
// | |
// Try to get the variable size. | |
// | |
Value = NULL; | |
Size = 0; | |
Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value); | |
if (Status != EFI_BUFFER_TOO_SMALL) { | |
return NULL; | |
} | |
// | |
// Allocate buffer to get the variable. | |
// | |
Value = AllocatePool (Size); | |
if (Value == NULL) { | |
return NULL; | |
} | |
// | |
// Get the variable data. | |
// | |
Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value); | |
if (EFI_ERROR (Status)) { | |
FreePool(Value); | |
return NULL; | |
} | |
return Value; | |
} | |
/** | |
[ATTENTION] This function will be deprecated for security reason. | |
Returns a pointer to an allocated buffer that contains the contents of a | |
variable retrieved through the UEFI Runtime Service GetVariable(). This | |
function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables. | |
The returned buffer is allocated using AllocatePool(). The caller is | |
responsible for freeing this buffer with FreePool(). | |
If Name is NULL, then ASSERT(). | |
@param[in] Name The pointer to a Null-terminated Unicode string. | |
@retval NULL The variable could not be retrieved. | |
@retval NULL There are not enough resources available for the variable contents. | |
@retval Other A pointer to allocated buffer containing the variable contents. | |
**/ | |
VOID * | |
EFIAPI | |
GetEfiGlobalVariable ( | |
IN CONST CHAR16 *Name | |
) | |
{ | |
return GetVariable (Name, &gEfiGlobalVariableGuid); | |
} | |
#endif | |
/** | |
Returns the status whether get the variable success. The function retrieves | |
variable through the UEFI Runtime Service GetVariable(). The | |
returned buffer is allocated using AllocatePool(). The caller is responsible | |
for freeing this buffer with FreePool(). | |
If Name is NULL, then ASSERT(). | |
If Guid is NULL, then ASSERT(). | |
If Value is NULL, then ASSERT(). | |
@param[in] Name The pointer to a Null-terminated Unicode string. | |
@param[in] Guid The pointer to an EFI_GUID structure | |
@param[out] Value The buffer point saved the variable info. | |
@param[out] Size The buffer size of the variable. | |
@return EFI_OUT_OF_RESOURCES Allocate buffer failed. | |
@return EFI_SUCCESS Find the specified variable. | |
@return Others Errors Return errors from call to gRT->GetVariable. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
GetVariable2 ( | |
IN CONST CHAR16 *Name, | |
IN CONST EFI_GUID *Guid, | |
OUT VOID **Value, | |
OUT UINTN *Size OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN BufferSize; | |
ASSERT (Name != NULL && Guid != NULL && Value != NULL); | |
// | |
// Try to get the variable size. | |
// | |
BufferSize = 0; | |
*Value = NULL; | |
if (Size != NULL) { | |
*Size = 0; | |
} | |
Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value); | |
if (Status != EFI_BUFFER_TOO_SMALL) { | |
return Status; | |
} | |
// | |
// Allocate buffer to get the variable. | |
// | |
*Value = AllocatePool (BufferSize); | |
ASSERT (*Value != NULL); | |
if (*Value == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Get the variable data. | |
// | |
Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value); | |
if (EFI_ERROR (Status)) { | |
FreePool(*Value); | |
*Value = NULL; | |
} | |
if (Size != NULL) { | |
*Size = BufferSize; | |
} | |
return Status; | |
} | |
/** | |
Returns a pointer to an allocated buffer that contains the contents of a | |
variable retrieved through the UEFI Runtime Service GetVariable(). This | |
function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables. | |
The returned buffer is allocated using AllocatePool(). The caller is | |
responsible for freeing this buffer with FreePool(). | |
If Name is NULL, then ASSERT(). | |
If Value is NULL, then ASSERT(). | |
@param[in] Name The pointer to a Null-terminated Unicode string. | |
@param[out] Value The buffer point saved the variable info. | |
@param[out] Size The buffer size of the variable. | |
@return EFI_OUT_OF_RESOURCES Allocate buffer failed. | |
@return EFI_SUCCESS Find the specified variable. | |
@return Others Errors Return errors from call to gRT->GetVariable. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
GetEfiGlobalVariable2 ( | |
IN CONST CHAR16 *Name, | |
OUT VOID **Value, | |
OUT UINTN *Size OPTIONAL | |
) | |
{ | |
return GetVariable2 (Name, &gEfiGlobalVariableGuid, Value, Size); | |
} | |
/** | |
Returns a pointer to an allocated buffer that contains the best matching language | |
from a set of supported languages. | |
This function supports both ISO 639-2 and RFC 4646 language codes, but language | |
code types may not be mixed in a single call to this function. The language | |
code returned is allocated using AllocatePool(). The caller is responsible for | |
freeing the allocated buffer using FreePool(). This function supports a variable | |
argument list that allows the caller to pass in a prioritized list of language | |
codes to test against all the language codes in SupportedLanguages. | |
If SupportedLanguages is NULL, then ASSERT(). | |
@param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that | |
contains a set of language codes in the format | |
specified by Iso639Language. | |
@param[in] Iso639Language If TRUE, then all language codes are assumed to be | |
in ISO 639-2 format. If FALSE, then all language | |
codes are assumed to be in RFC 4646 language format | |
@param[in] ... A variable argument list that contains pointers to | |
Null-terminated ASCII strings that contain one or more | |
language codes in the format specified by Iso639Language. | |
The first language code from each of these language | |
code lists is used to determine if it is an exact or | |
close match to any of the language codes in | |
SupportedLanguages. Close matches only apply to RFC 4646 | |
language codes, and the matching algorithm from RFC 4647 | |
is used to determine if a close match is present. If | |
an exact or close match is found, then the matching | |
language code from SupportedLanguages is returned. If | |
no matches are found, then the next variable argument | |
parameter is evaluated. The variable argument list | |
is terminated by a NULL. | |
@retval NULL The best matching language could not be found in SupportedLanguages. | |
@retval NULL There are not enough resources available to return the best matching | |
language. | |
@retval Other A pointer to a Null-terminated ASCII string that is the best matching | |
language in SupportedLanguages. | |
**/ | |
CHAR8 * | |
EFIAPI | |
GetBestLanguage ( | |
IN CONST CHAR8 *SupportedLanguages, | |
IN BOOLEAN Iso639Language, | |
... | |
) | |
{ | |
VA_LIST Args; | |
CHAR8 *Language; | |
UINTN CompareLength; | |
UINTN LanguageLength; | |
CONST CHAR8 *Supported; | |
CHAR8 *BestLanguage; | |
ASSERT (SupportedLanguages != NULL); | |
VA_START (Args, Iso639Language); | |
while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) { | |
// | |
// Default to ISO 639-2 mode | |
// | |
CompareLength = 3; | |
LanguageLength = MIN (3, AsciiStrLen (Language)); | |
// | |
// If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language | |
// | |
if (!Iso639Language) { | |
for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++); | |
} | |
// | |
// Trim back the length of Language used until it is empty | |
// | |
while (LanguageLength > 0) { | |
// | |
// Loop through all language codes in SupportedLanguages | |
// | |
for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) { | |
// | |
// In RFC 4646 mode, then Loop through all language codes in SupportedLanguages | |
// | |
if (!Iso639Language) { | |
// | |
// Skip ';' characters in Supported | |
// | |
for (; *Supported != '\0' && *Supported == ';'; Supported++); | |
// | |
// Determine the length of the next language code in Supported | |
// | |
for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++); | |
// | |
// If Language is longer than the Supported, then skip to the next language | |
// | |
if (LanguageLength > CompareLength) { | |
continue; | |
} | |
} | |
// | |
// See if the first LanguageLength characters in Supported match Language | |
// | |
if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) { | |
VA_END (Args); | |
// | |
// Allocate, copy, and return the best matching language code from SupportedLanguages | |
// | |
BestLanguage = AllocateZeroPool (CompareLength + 1); | |
if (BestLanguage == NULL) { | |
return NULL; | |
} | |
return CopyMem (BestLanguage, Supported, CompareLength); | |
} | |
} | |
if (Iso639Language) { | |
// | |
// If ISO 639 mode, then each language can only be tested once | |
// | |
LanguageLength = 0; | |
} else { | |
// | |
// If RFC 4646 mode, then trim Language from the right to the next '-' character | |
// | |
for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--); | |
} | |
} | |
} | |
VA_END (Args); | |
// | |
// No matches were found | |
// | |
return NULL; | |
} | |