mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
483 lines
11 KiB
C
483 lines
11 KiB
C
/** @file
|
|
Driver to implement English version of Unicode Collation Protocol.
|
|
|
|
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "OcUnicodeCollationEngInternal.h"
|
|
|
|
CHAR8 mEngUpperMap[MAP_TABLE_SIZE];
|
|
CHAR8 mEngLowerMap[MAP_TABLE_SIZE];
|
|
CHAR8 mEngInfoMap[MAP_TABLE_SIZE];
|
|
|
|
CHAR8 mOtherChars[] = {
|
|
'0',
|
|
'1',
|
|
'2',
|
|
'3',
|
|
'4',
|
|
'5',
|
|
'6',
|
|
'7',
|
|
'8',
|
|
'9',
|
|
'\\',
|
|
'.',
|
|
'_',
|
|
'^',
|
|
'$',
|
|
'~',
|
|
'!',
|
|
'#',
|
|
'%',
|
|
'&',
|
|
'-',
|
|
'{',
|
|
'}',
|
|
'(',
|
|
')',
|
|
'@',
|
|
'`',
|
|
'\'',
|
|
'\0'
|
|
};
|
|
|
|
//
|
|
// Supported language list, meant to contain one extra language if necessary.
|
|
//
|
|
STATIC CHAR8 UnicodeLanguages[6] = "en";
|
|
|
|
//
|
|
// EFI Unicode Collation2 Protocol supporting RFC 4646 language code
|
|
//
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_COLLATION_PROTOCOL gInternalUnicode2Eng = {
|
|
EngStriColl,
|
|
EngMetaiMatch,
|
|
EngStrLwr,
|
|
EngStrUpr,
|
|
EngFatToStr,
|
|
EngStrToFat,
|
|
UnicodeLanguages
|
|
};
|
|
|
|
VOID
|
|
OcUnicodeCollationUpdatePlatformLanguage (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR8 *PlatformLang;
|
|
UINTN Size;
|
|
|
|
//
|
|
// On several platforms EFI_PLATFORM_LANG_VARIABLE_NAME is not available.
|
|
// Fallback to "en-US" which is supported by this library and the wide majority of others.
|
|
//
|
|
Size = 0;
|
|
PlatformLang = NULL;
|
|
Status = gRT->GetVariable (
|
|
EFI_PLATFORM_LANG_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
NULL,
|
|
&Size,
|
|
PlatformLang
|
|
);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
Size,
|
|
(VOID **)&PlatformLang
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gRT->GetVariable (
|
|
EFI_PLATFORM_LANG_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
NULL,
|
|
&Size,
|
|
PlatformLang
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->FreePool (PlatformLang);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (AsciiStrnLenS (PlatformLang, Size) < 2) {
|
|
gBS->FreePool (PlatformLang);
|
|
PlatformLang = NULL;
|
|
}
|
|
} else {
|
|
PlatformLang = NULL;
|
|
}
|
|
|
|
if (PlatformLang == NULL) {
|
|
//
|
|
// No value or something broken, discard and fallback.
|
|
//
|
|
gRT->SetVariable (
|
|
EFI_PLATFORM_LANG_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
sizeof ("en-US"),
|
|
"en-US"
|
|
);
|
|
} else if (AsciiStrnCmp (PlatformLang, "en", 2) != 0) {
|
|
//
|
|
// On some platforms with missing gEfiUnicodeCollation2ProtocolGuid EFI_PLATFORM_LANG_VARIABLE_NAME is set
|
|
// to the value different from "en" or "en-...". This is not going to work with our driver and UEFI Shell
|
|
// will fail to load. Since we did not overwrite EFI_PLATFORM_LANG_VARIABLE_NAME, and it uses some other language,
|
|
// workaround by appending the other language to the list of supported ones.
|
|
//
|
|
STATIC_ASSERT (
|
|
sizeof (UnicodeLanguages) == 6 && sizeof (UnicodeLanguages[0]) == 1,
|
|
"UnicodeLanguages must contain one extra language"
|
|
);
|
|
UnicodeLanguages[2] = ';';
|
|
UnicodeLanguages[3] = PlatformLang[0];
|
|
UnicodeLanguages[4] = PlatformLang[1];
|
|
UnicodeLanguages[5] = '\0';
|
|
}
|
|
|
|
//
|
|
// Free allocated memory for platform languages
|
|
//
|
|
if (PlatformLang != NULL) {
|
|
gBS->FreePool (PlatformLang);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
OcUnicodeCollationInitializeMappingTables (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
|
|
//
|
|
// Initialize mapping tables for the supported languages
|
|
//
|
|
for (Index = 0; Index < MAP_TABLE_SIZE; Index++) {
|
|
mEngUpperMap[Index] = (CHAR8)Index;
|
|
mEngLowerMap[Index] = (CHAR8)Index;
|
|
mEngInfoMap[Index] = 0;
|
|
|
|
if (((Index >= 'a') && (Index <= 'z')) || ((Index >= 0xe0) && (Index <= 0xf6)) || ((Index >= 0xf8) && (Index <= 0xfe))) {
|
|
Index2 = Index - 0x20;
|
|
mEngUpperMap[Index] = (CHAR8)Index2;
|
|
mEngLowerMap[Index2] = (CHAR8)Index;
|
|
|
|
mEngInfoMap[Index] |= CHAR_FAT_VALID;
|
|
mEngInfoMap[Index2] |= CHAR_FAT_VALID;
|
|
}
|
|
}
|
|
|
|
for (Index = 0; mOtherChars[Index] != 0; Index++) {
|
|
Index2 = mOtherChars[Index];
|
|
mEngInfoMap[Index2] |= CHAR_FAT_VALID;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Performs a case-insensitive comparison of two Null-terminated strings.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param Str1 A pointer to a Null-terminated string.
|
|
@param Str2 A pointer to a Null-terminated string.
|
|
|
|
@retval 0 Str1 is equivalent to Str2
|
|
@retval > 0 Str1 is lexically greater than Str2
|
|
@retval < 0 Str1 is lexically less than Str2
|
|
|
|
**/
|
|
INTN
|
|
EFIAPI
|
|
EngStriColl (
|
|
IN EFI_UNICODE_COLLATION_PROTOCOL *This,
|
|
IN CHAR16 *Str1,
|
|
IN CHAR16 *Str2
|
|
)
|
|
{
|
|
while (*Str1 != 0) {
|
|
if (TO_UPPER (*Str1) != TO_UPPER (*Str2)) {
|
|
break;
|
|
}
|
|
|
|
Str1 += 1;
|
|
Str2 += 1;
|
|
}
|
|
|
|
return TO_UPPER (*Str1) - TO_UPPER (*Str2);
|
|
}
|
|
|
|
/**
|
|
Converts all the characters in a Null-terminated string to
|
|
lower case characters.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param Str A pointer to a Null-terminated string.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
EngStrLwr (
|
|
IN EFI_UNICODE_COLLATION_PROTOCOL *This,
|
|
IN OUT CHAR16 *Str
|
|
)
|
|
{
|
|
while (*Str != 0) {
|
|
*Str = TO_LOWER (*Str);
|
|
Str += 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Converts all the characters in a Null-terminated string to upper
|
|
case characters.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param Str A pointer to a Null-terminated string.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
EngStrUpr (
|
|
IN EFI_UNICODE_COLLATION_PROTOCOL *This,
|
|
IN OUT CHAR16 *Str
|
|
)
|
|
{
|
|
while (*Str != 0) {
|
|
*Str = TO_UPPER (*Str);
|
|
Str += 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Performs a case-insensitive comparison of a Null-terminated
|
|
pattern string and a Null-terminated string.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param String A pointer to a Null-terminated string.
|
|
@param Pattern A pointer to a Null-terminated pattern string.
|
|
|
|
@retval TRUE Pattern was found in String.
|
|
@retval FALSE Pattern was not found in String.
|
|
|
|
**/
|
|
BOOLEAN
|
|
EFIAPI
|
|
EngMetaiMatch (
|
|
IN EFI_UNICODE_COLLATION_PROTOCOL *This,
|
|
IN CHAR16 *String,
|
|
IN CHAR16 *Pattern
|
|
)
|
|
{
|
|
CHAR16 CharC;
|
|
CHAR16 CharP;
|
|
CHAR16 Index3;
|
|
|
|
for ( ; ;) {
|
|
CharP = *Pattern;
|
|
Pattern += 1;
|
|
|
|
switch (CharP) {
|
|
case 0:
|
|
//
|
|
// End of pattern. If end of string, TRUE match
|
|
//
|
|
if (*String != 0) {
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
|
|
case '*':
|
|
//
|
|
// Match zero or more chars
|
|
//
|
|
while (*String != 0) {
|
|
if (EngMetaiMatch (This, String, Pattern)) {
|
|
return TRUE;
|
|
}
|
|
|
|
String += 1;
|
|
}
|
|
|
|
return EngMetaiMatch (This, String, Pattern);
|
|
|
|
case '?':
|
|
//
|
|
// Match any one char
|
|
//
|
|
if (*String == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
String += 1;
|
|
break;
|
|
|
|
case '[':
|
|
//
|
|
// Match char set
|
|
//
|
|
CharC = *String;
|
|
if (CharC == 0) {
|
|
//
|
|
// syntax problem
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
Index3 = 0;
|
|
CharP = *Pattern++;
|
|
while (CharP != 0) {
|
|
if (CharP == ']') {
|
|
return FALSE;
|
|
}
|
|
|
|
if (CharP == '-') {
|
|
//
|
|
// if range of chars, get high range
|
|
//
|
|
CharP = *Pattern;
|
|
if ((CharP == 0) || (CharP == ']')) {
|
|
//
|
|
// syntax problem
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
if ((TO_UPPER (CharC) >= TO_UPPER (Index3)) && (TO_UPPER (CharC) <= TO_UPPER (CharP))) {
|
|
//
|
|
// if in range, it's a match
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
Index3 = CharP;
|
|
if (TO_UPPER (CharC) == TO_UPPER (CharP)) {
|
|
//
|
|
// if char matches
|
|
//
|
|
break;
|
|
}
|
|
|
|
CharP = *Pattern++;
|
|
}
|
|
|
|
//
|
|
// skip to end of match char set
|
|
//
|
|
while ((CharP != 0) && (CharP != ']')) {
|
|
CharP = *Pattern;
|
|
Pattern += 1;
|
|
}
|
|
|
|
String += 1;
|
|
break;
|
|
|
|
default:
|
|
CharC = *String;
|
|
if (TO_UPPER (CharC) != TO_UPPER (CharP)) {
|
|
return FALSE;
|
|
}
|
|
|
|
String += 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Converts an 8.3 FAT file name in an OEM character set to a Null-terminated string.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param FatSize The size of the string Fat in bytes.
|
|
@param Fat A pointer to a Null-terminated string that contains an 8.3 file
|
|
name using an 8-bit OEM character set.
|
|
@param String A pointer to a Null-terminated string. The string must
|
|
be preallocated to hold FatSize characters.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
EngFatToStr (
|
|
IN EFI_UNICODE_COLLATION_PROTOCOL *This,
|
|
IN UINTN FatSize,
|
|
IN CHAR8 *Fat,
|
|
OUT CHAR16 *String
|
|
)
|
|
{
|
|
//
|
|
// No DBCS issues, just expand and add null terminate to end of string
|
|
//
|
|
while ((*Fat != 0) && (FatSize != 0)) {
|
|
*String = *Fat;
|
|
String += 1;
|
|
Fat += 1;
|
|
FatSize -= 1;
|
|
}
|
|
|
|
*String = 0;
|
|
}
|
|
|
|
/**
|
|
Converts a Null-terminated string to legal characters in a FAT
|
|
filename using an OEM character set.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param String A pointer to a Null-terminated string. The string must
|
|
be preallocated to hold FatSize characters.
|
|
@param FatSize The size of the string Fat in bytes.
|
|
@param Fat A pointer to a Null-terminated string that contains an 8.3 file
|
|
name using an OEM character set.
|
|
|
|
@retval TRUE Fat is a Long File Name
|
|
@retval FALSE Fat is an 8.3 file name
|
|
|
|
**/
|
|
BOOLEAN
|
|
EFIAPI
|
|
EngStrToFat (
|
|
IN EFI_UNICODE_COLLATION_PROTOCOL *This,
|
|
IN CHAR16 *String,
|
|
IN UINTN FatSize,
|
|
OUT CHAR8 *Fat
|
|
)
|
|
{
|
|
BOOLEAN SpecialCharExist;
|
|
|
|
SpecialCharExist = FALSE;
|
|
while ((*String != 0) && (FatSize != 0)) {
|
|
//
|
|
// Skip '.' or ' ' when making a fat name
|
|
//
|
|
if ((*String != '.') && (*String != ' ')) {
|
|
//
|
|
// If this is a valid fat char, move it.
|
|
// Otherwise, move a '_' and flag the fact that the name needs a long file name.
|
|
//
|
|
if ((*String < MAP_TABLE_SIZE) && ((mEngInfoMap[*String] & CHAR_FAT_VALID) != 0)) {
|
|
*Fat = mEngUpperMap[*String];
|
|
} else {
|
|
*Fat = '_';
|
|
SpecialCharExist = TRUE;
|
|
}
|
|
|
|
Fat += 1;
|
|
FatSize -= 1;
|
|
}
|
|
|
|
String += 1;
|
|
}
|
|
|
|
//
|
|
// Do not terminate that fat string
|
|
//
|
|
return SpecialCharExist;
|
|
}
|