# 53. Russian 글꼴 추가 - Part 2.

&#x20;이제 우리 글꼴을 HII 데이터베이스에 추가할 시점이다.

&#x20;새로운 애플리케이션을 초기화한다.

```
./createNewApp.sh HIIAddRussianFont
```

&#x20;패키지 DSC 파일(`UefiLessonsPkg.dsc`)에 추가한다.

```
$ vi UefiLessonsPkg/UefiLessonsPkg.dsc
---
[Components]
  UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
```

&#x20;애플리케이션에서는 HII 데이터베이스에 패키지 목록을 채울 것이므로, `UefiLessonsPkg.dec`에서 이 패키지 목록에 대한 GUID를 선언해야 한다.

```
$ vi UefiLessonsPkg/UefiLessonsPkg.dec
---
[Guids]
  ...
  gHIIAddRussianFontGuid = { 0x9fe2f616, 0x323c, 0x45a7, { 0x87, 0xa2, 0xdf, 0xef, 0xf5, 0x17, 0xcc, 0x66 }}
```

&#x20;그리고 애플리케이션을 이용하기 위해서 INF 파일을 선언한다.

```
$ vi UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
---
[Packages]
  ...
  UefiLessonsPkg/UefiLessonsPkg.dec

[Guids]
  gHIIAddRussianFontGuid
```

&#x20;또한 HII 서비스(ex. `HiiAddPackages` 함수)용 라이브러리를 사용하므로 처음부터 포함시키도록 하자.

```
[Packages]
  ...
  MdeModulePkg/MdeModulePkg.dec

[LibraryClasses]
  ...
  HiiLib
```

## String.uni file

&#x20;애플리케이션 소스(`HIIAddRussianFont.inf`)에 문자열 UNI 파일을 추가한다.

```
$ vi UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
---
[Sources]
  ...
  Strings.uni
```

&#x20;그 다음 아래의 문자열을 사용하여 이 `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  "абвгдеёжзийклмнопрстуфхцчшщьъэюя"
```

&#x20;알파벳 문자열은 해당 언어의 모든 문자가 올바르게 출력되었는지 확인하는 데 도움이 된다.

## RussianFont.c

&#x20;이전 장에서 받은 러시아어 글꼴 Glyph가 포함된 파일을 `HIIAddRussianFont.inf`에 추가한다.

```
$ vi UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf
---
[Sources]
  ...
  RussianFont.c
```

&#x20;다음 내용이 포함된 파일일 경우를 대비하여

```
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

&#x20;이제 기본 코드를 작성할 차례이다.

```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;
}
```

&#x20;여기서 우리는,

* `RussianFont.c` 파일의 Glyph 배열에서 글꼴 패키지 데이터를 구성한다. 이 다음에 `CreateSimpleFontPkg` 함수를 정의한다.
* `HiiAddPackages`를 사용하여 글꼴 패키지와 애플리케이션 문자열 패키지를 모두 추가한다. (이 함수는 가변적이며, 다양한 수의 패키지를 사용하여 모두 push하여 새 패키지 목록을 만들 수 있다. <https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/UefiHiiLib/HiiLib.c>)
* 패키지를 추가하면, 더 이상 `FontPackage`가 필요하지 않으므로 `FreePool` 기능으로 해제하는 것을 잊지 않도록 하자.
* 모든 것이 정상이라면, `HiiGetString`을 사용하여 모든 언어의 모든 문자열을 출력한다.

&#x20;이제 `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
...
```

&#x20;함수에서 글꼴 패키지에 필요한 배열을 할당해야 한다. 패키지 자체를 위한 공간을 할당하는 것 외에도 모든 데이터 앞에 추가할 패키지 크기에 대해 4바이트를 추가해야 한다. 알다시피 이것은 `HiiAddPackages` 함수에 필요한 데이터 형식이다.

```c
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;
}
```

&#x20;이제 패키지 데이터를 채우자. 먼저 헤더를 채운다.

```c
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));
```

&#x20;그런 다음 Glyphs 데이터를 복사한다(`CopyMem` 함수의 경우, `<Library/BaseMemoryLib.h>` 헤더를 포함한다.).

```c
UINT8* Location = (UINT8*)(&SimpleFont->NumberOfWideGlyphs + 1);
CopyMem(Location, NarrowGlyph, NarrowGlyphSizeInBytes);
CopyMem(Location + NarrowGlyphSizeInBytes, WideGlyph, WideGlyphSizeInBytes);
```

&#x20;애플리케이션을 빌드하고 실행하면, 러시아어 문자열이 올바르게 출력되는 것을 볼 수 있다.

<figure><img src="/files/JpWjwMoWAcmcPVu8y6fe" alt=""><figcaption></figcaption></figure>

애플리케이션의 시작 부분과 끝 부분에 러시아어로 일부 문자열을 출력해보겠다.

```c
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  Print(L"Привет!\n");

  ...

  Print(L"Привет!\n");

  return EFI_SUCCESS;
}
```

&#x20;첫 번째 출력내용은 `!`만 출력한다. 러시아어 유니코드 기호 Glyph를 표시하는 방법에 대한 정보가 시스템에 없기 때문이다. 그러나 마지막에 글꼴 패키지를 추가한 후의 내용에는 예상된 결과를 출력한다.

<figure><img src="/files/hzTtoSMbnWJI3ZURJodl" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bob-mcd-team.gitbook.io/uefi/uefi-development/hii/53.russian-font-part-2.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
