53. Russian 글꼴 추가 - Part 2.
EFI_HII_SIMPLE_FONT_PACKAGE 구성 및 HII 데이터베이스에 채우기
이제 우리 글꼴을 HII 데이터베이스에 추가할 시점이다.
새로운 애플리케이션을 초기화한다.
./createNewApp.sh HIIAddRussianFont
패키지 DSC 파일(UefiLessonsPkg.dsc
)에 추가한다.
$ vi UefiLessonsPkg/UefiLessonsPkg.dsc
---
[Components]
UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
애플리케이션에서는 HII 데이터베이스에 패키지 목록을 채울 것이므로, UefiLessonsPkg.dec
에서 이 패키지 목록에 대한 GUID를 선언해야 한다.
$ vi UefiLessonsPkg/UefiLessonsPkg.dec
---
[Guids]
...
gHIIAddRussianFontGuid = { 0x9fe2f616, 0x323c, 0x45a7, { 0x87, 0xa2, 0xdf, 0xef, 0xf5, 0x17, 0xcc, 0x66 }}
그리고 애플리케이션을 이용하기 위해서 INF 파일을 선언한다.
$ vi UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
---
[Packages]
...
UefiLessonsPkg/UefiLessonsPkg.dec
[Guids]
gHIIAddRussianFontGuid
또한 HII 서비스(ex. HiiAddPackages
함수)용 라이브러리를 사용하므로 처음부터 포함시키도록 하자.
[Packages]
...
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
...
HiiLib
String.uni file
애플리케이션 소스(HIIAddRussianFont.inf
)에 문자열 UNI 파일을 추가한다.
$ vi UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
---
[Sources]
...
Strings.uni
그 다음 아래의 문자열을 사용하여 이 Strings.uni
파일을 만든다.
"Hello!"
"Bye!"
대문자 알파벳
소문자 알파벳
#langdef en-US "English"
#langdef fr-FR "Francais"
#langdef ru-RU "Russian"
#string STR_HELLO #language en-US "Hello!"
#language fr-FR "Bonjour!"
#language ru-RU "Привет!"
#string STR_BYE #language en-US "Bye!"
#language fr-FR "Au revoir!"
#language ru-RU "До свидания!"
#string STR_ALPHABET_UPPERCASE #language en-US "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#language fr-FR "ABCDEFGHIJKLMNOPQRSTUVWXYZÀÈÙÉÂÊÎÔÛËÏÜŸÆŒÇ"
#language ru-RU "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЪЭЮЯ"
#string STR_ALPHABET_LOWERCASE #language en-US "abcdefghijklmnopqrstuvwxyz"
#language fr-FR "abcdefghijklmnopqrstuvwxyzàèùéâêîôûëïüÿæœç"
#language ru-RU "абвгдеёжзийклмнопрстуфхцчшщьъэюя"
알파벳 문자열은 해당 언어의 모든 문자가 올바르게 출력되었는지 확인하는 데 도움이 된다.
RussianFont.c
이전 장에서 받은 러시아어 글꼴 Glyph가 포함된 파일을 HIIAddRussianFont.inf
에 추가한다.
$ vi UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
---
[Sources]
...
RussianFont.c
다음 내용이 포함된 파일일 경우를 대비하여
EFI_WIDE_GLYPH gSimpleFontWideGlyphData[] = {
{ 0x00, 0x00, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
};
UINT32 gSimpleFontWideBytes = sizeof(gSimpleFontWideGlyphData);
EFI_NARROW_GLYPH gSimpleFontNarrowGlyphData[] = {
{ 0x400, 0x00, { 0x60,0x30,0x00,0xfe,0x66,0x62,0x60,0x68,0x78,0x68,0x60,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00}},
{ 0x401, 0x00, { 0x66,0x66,0x00,0xfe,0x66,0x62,0x60,0x68,0x78,0x68,0x60,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00}},
{ 0x402, 0x00, { 0x00,0x00,0x00,0xfc,0x64,0x60,0x60,0x6c,0x76,0x66,0x66,0x66,0x66,0x66,0xe6,0x0c,0x00,0x00,0x00}},
{ 0x403, 0x00, { 0x0c,0x18,0x00,0xfe,0x66,0x62,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00}},
{ 0x404, 0x00, { 0x00,0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc8,0xf8,0xc8,0xc0,0xc0,0xc2,0x66,0x3c,0x00,0x00,0x00,0x00}},
...
{ 0x45c, 0x00, { 0x00,0x00,0x00,0x0c,0x18,0x30,0x00,0xe6,0x66,0x6c,0x78,0x78,0x6c,0x66,0xe6,0x00,0x00,0x00,0x00}},
{ 0x45d, 0x00, { 0x00,0x00,0x00,0x60,0x30,0x18,0x00,0xc6,0xc6,0xce,0xde,0xf6,0xe6,0xc6,0xc6,0x00,0x00,0x00,0x00}},
{ 0x45e, 0x00, { 0x00,0x00,0x00,0x00,0x6c,0x38,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x06,0x0c,0xf8,0x00}},
{ 0x45f, 0x00, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xfe,0x10,0x10,0x00,0x00}},
};
UINT32 gSimpleFontNarrowBytes = sizeof(gSimpleFontNarrowGlyphData);
HIIAddRussianFont.c
이제 기본 코드를 작성할 차례이다.
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/HiiLib.h>
#include <Library/MemoryAllocationLib.h>
extern EFI_WIDE_GLYPH gSimpleFontWideGlyphData[];
extern UINT32 gSimpleFontWideBytes;
extern EFI_NARROW_GLYPH gSimpleFontNarrowGlyphData[];
extern UINT32 gSimpleFontNarrowBytes;
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT8* FontPackage = CreateSimpleFontPkg(gSimpleFontWideGlyphData,
gSimpleFontWideBytes,
gSimpleFontNarrowGlyphData,
gSimpleFontNarrowBytes);
EFI_HII_HANDLE Handle = HiiAddPackages(&gHIIAddRussianFontGuid,
NULL,
FontPackage,
HIIAddRussianFontStrings,
NULL);
FreePool(FontPackage);
if (Handle == NULL)
{
Print(L"Error! Can't perform HiiAddPackages\n");
return EFI_INVALID_PARAMETER;
}
Print(L"en-US ID=1: %s\n", HiiGetString(Handle, 1, "en-US"));
Print(L"en-US ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "en-US"));
Print(L"en-US ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "en-US"));
Print(L"en-US ID=4: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_UPPERCASE), "en-US"));
Print(L"en-US ID=5: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_LOWERCASE), "en-US"));
Print(L"fr-FR ID=1: %s\n", HiiGetString(Handle, 1, "fr-FR"));
Print(L"fr-FR ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "fr-FR"));
Print(L"fr-FR ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "fr-FR"));
Print(L"fr-FR ID=4: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_UPPERCASE), "fr-FR"));
Print(L"fr-FR ID=5: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_LOWERCASE), "fr-FR"));
Print(L"ru-RU ID=1: %s\n", HiiGetString(Handle, 1, "ru-RU"));
Print(L"ru-RU ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "ru-RU"));
Print(L"ru-RU ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "ru-RU"));
Print(L"ru-RU ID=4: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_UPPERCASE), "ru-RU"));
Print(L"ru-RU ID=5: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_ALPHABET_LOWERCASE), "ru-RU"));
return EFI_SUCCESS;
}
여기서 우리는,
RussianFont.c
파일의 Glyph 배열에서 글꼴 패키지 데이터를 구성한다. 이 다음에CreateSimpleFontPkg
함수를 정의한다.HiiAddPackages
를 사용하여 글꼴 패키지와 애플리케이션 문자열 패키지를 모두 추가한다. (이 함수는 가변적이며, 다양한 수의 패키지를 사용하여 모두 push하여 새 패키지 목록을 만들 수 있다. https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/UefiHiiLib/HiiLib.c)패키지를 추가하면, 더 이상
FontPackage
가 필요하지 않으므로FreePool
기능으로 해제하는 것을 잊지 않도록 하자.모든 것이 정상이라면,
HiiGetString
을 사용하여 모든 언어의 모든 문자열을 출력한다.
이제 CreateSimpleFontPkg
함수를 정의한다. 먼저, 글꼴 패키지 생성에 필요한 정의 및 유형이다. https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiInternalFormRepresentation.h
///
/// A simplified font package consists of a font header
/// followed by a series of glyph structures.
///
typedef struct _EFI_HII_SIMPLE_FONT_PACKAGE_HDR {
EFI_HII_PACKAGE_HEADER Header;
UINT16 NumberOfNarrowGlyphs;
UINT16 NumberOfWideGlyphs;
// EFI_NARROW_GLYPH NarrowGlyphs[];
// EFI_WIDE_GLYPH WideGlyphs[];
} EFI_HII_SIMPLE_FONT_PACKAGE_HDR;
///
/// The header found at the start of each package.
///
typedef struct {
UINT32 Length:24;
UINT32 Type:8;
// UINT8 Data[...];
} EFI_HII_PACKAGE_HEADER;
//
// Value of HII package type
//
...
#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07
...
함수에서 글꼴 패키지에 필요한 배열을 할당해야 한다. 패키지 자체를 위한 공간을 할당하는 것 외에도 모든 데이터 앞에 추가할 패키지 크기에 대해 4바이트를 추가해야 한다. 알다시피 이것은 HiiAddPackages
함수에 필요한 데이터 형식이다.
UINT8* CreateSimpleFontPkg(EFI_WIDE_GLYPH* WideGlyph,
UINT32 WideGlyphSizeInBytes,
EFI_NARROW_GLYPH* NarrowGlyph,
UINT32 NarrowGlyphSizeInBytes)
{
UINT32 PackageLen = sizeof(EFI_HII_SIMPLE_FONT_PACKAGE_HDR) + WideGlyphSizeInBytes + NarrowGlyphSizeInBytes + 4;
UINT8* FontPackage = (UINT8*)AllocateZeroPool (PackageLen);
*(UINT32*)FontPackage = PackageLen;
...
return FontPackage;
}
이제 패키지 데이터를 채우자. 먼저 헤더를 채운다.
EFI_HII_SIMPLE_FONT_PACKAGE_HDR *SimpleFont;
SimpleFont = (EFI_HII_SIMPLE_FONT_PACKAGE_HDR*)(FontPackage + 4);
SimpleFont->Header.Length = (UINT32)(PackageLen - 4);
SimpleFont->Header.Type = EFI_HII_PACKAGE_SIMPLE_FONTS;
SimpleFont->NumberOfNarrowGlyphs = (UINT16)(NarrowGlyphSizeInBytes / sizeof(EFI_NARROW_GLYPH));
SimpleFont->NumberOfWideGlyphs = (UINT16)(WideGlyphSizeInBytes / sizeof(EFI_WIDE_GLYPH));
그런 다음 Glyphs 데이터를 복사한다(CopyMem
함수의 경우, <Library/BaseMemoryLib.h>
헤더를 포함한다.).
UINT8* Location = (UINT8*)(&SimpleFont->NumberOfWideGlyphs + 1);
CopyMem(Location, NarrowGlyph, NarrowGlyphSizeInBytes);
CopyMem(Location + NarrowGlyphSizeInBytes, WideGlyph, WideGlyphSizeInBytes);
애플리케이션을 빌드하고 실행하면, 러시아어 문자열이 올바르게 출력되는 것을 볼 수 있다.

애플리케이션의 시작 부분과 끝 부분에 러시아어로 일부 문자열을 출력해보겠다.
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
Print(L"Привет!\n");
...
Print(L"Привет!\n");
return EFI_SUCCESS;
}
첫 번째 출력내용은 !
만 출력한다. 러시아어 유니코드 기호 Glyph를 표시하는 방법에 대한 정보가 시스템에 없기 때문이다. 그러나 마지막에 글꼴 패키지를 추가한 후의 내용에는 예상된 결과를 출력한다.

Last updated