summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg/Universal/BdsDxe/Language.c
blob: 8724b13f4ca1d764bd50be8287d13683fbbed136 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/** @file
  Language settings

Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "Bds.h"
#define ISO_639_2_ENTRY_SIZE  3

/**
  Check if lang is in supported language codes according to language string.

  This code is used to check if lang is in in supported language codes. It can handle
  RFC4646 and ISO639 language tags.
  In ISO639 language tags, take 3-characters as a delimitation to find matched string.
  In RFC4646 language tags, take semicolon as a delimitation to find matched string.

  For example:
    SupportedLang  = "engfraengfra"
    Iso639Language = TRUE
    Lang           = "eng", the return value is "TRUE", or
    Lang           = "chs", the return value is "FALSE".
  Another example:
    SupportedLang  = "en;fr;en-US;fr-FR"
    Iso639Language = FALSE
    Lang           = "en", the return value is "TRUE", or
    Lang           = "zh", the return value is "FALSE".

  @param  SupportedLang               Platform supported language codes.
  @param  Lang                        Configured language.
  @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.

  @retval TRUE  lang is in supported language codes.
  @retval FALSE lang is not in supported language codes.

**/
BOOLEAN
IsLangInSupportedLangCodes (
  IN  CHAR8    *SupportedLang,
  IN  CHAR8    *Lang,
  IN  BOOLEAN  Iso639Language
  )
{
  UINTN  Index;
  UINTN  CompareLength;
  UINTN  LanguageLength;

  if (Iso639Language) {
    CompareLength = ISO_639_2_ENTRY_SIZE;
    for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
      if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
        //
        // Successfully find the Lang string in SupportedLang string.
        //
        return TRUE;
      }
    }

    return FALSE;
  } else {
    //
    // Compare RFC4646 language code
    //
    for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++) {
    }

    for ( ; *SupportedLang != '\0'; SupportedLang += CompareLength) {
      //
      // Skip ';' characters in SupportedLang
      //
      for ( ; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++) {
      }

      //
      // Determine the length of the next language code in SupportedLang
      //
      for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++) {
      }

      if ((CompareLength == LanguageLength) &&
          (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0))
      {
        //
        // Successfully find the Lang string in SupportedLang string.
        //
        return TRUE;
      }
    }

    return FALSE;
  }
}

/**
  Initialize Lang or PlatformLang variable, if Lang or PlatformLang variable is not found,
  or it has been set to an unsupported value(not one of platform supported language codes),
  set the default language code to it.

  @param  LangName                    Language name, L"Lang" or L"PlatformLang".
  @param  SupportedLang               Platform supported language codes.
  @param  DefaultLang                 Default language code.
  @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646,
                                      TRUE for L"Lang" LangName or FALSE for L"PlatformLang" LangName.

**/
VOID
InitializeLangVariable (
  IN CHAR16   *LangName,
  IN CHAR8    *SupportedLang,
  IN CHAR8    *DefaultLang,
  IN BOOLEAN  Iso639Language
  )
{
  CHAR8  *Lang;

  //
  // Find current Lang or PlatformLang from EFI Variable.
  //
  GetEfiGlobalVariable2 (LangName, (VOID **)&Lang, NULL);

  //
  // If Lang or PlatformLang variable is not found,
  // or it has been set to an unsupported value(not one of the supported language codes),
  // set the default language code to it.
  //
  if ((Lang == NULL) || !IsLangInSupportedLangCodes (SupportedLang, Lang, Iso639Language)) {
    //
    // The default language code should be one of the supported language codes.
    //
    ASSERT (IsLangInSupportedLangCodes (SupportedLang, DefaultLang, Iso639Language));
    BdsDxeSetVariableAndReportStatusCodeOnError (
      LangName,
      &gEfiGlobalVariableGuid,
      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
      AsciiStrSize (DefaultLang),
      DefaultLang
      );
  }

  if (Lang != NULL) {
    FreePool (Lang);
  }
}

/**
  Determine the current language that will be used
  based on language related EFI Variables.

  @param LangCodesSettingRequired - If required to set LangCodes variable

**/
VOID
InitializeLanguage (
  BOOLEAN  LangCodesSettingRequired
  )
{
  EFI_STATUS  Status;
  CHAR8       *LangCodes;
  CHAR8       *PlatformLangCodes;

  LangCodes         = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLangCodes);
  PlatformLangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes);
  if (LangCodesSettingRequired) {
    if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
      //
      // UEFI 2.1 depricated this variable so we support turning it off
      //
      Status = gRT->SetVariable (
                      L"LangCodes",
                      &gEfiGlobalVariableGuid,
                      EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
                      AsciiStrSize (LangCodes),
                      LangCodes
                      );
      //
      // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
      //
      ASSERT_EFI_ERROR (Status);
    }

    Status = gRT->SetVariable (
                    L"PlatformLangCodes",
                    &gEfiGlobalVariableGuid,
                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
                    AsciiStrSize (PlatformLangCodes),
                    PlatformLangCodes
                    );
    //
    // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
    //
    ASSERT_EFI_ERROR (Status);
  }

  if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
    //
    // UEFI 2.1 depricated this variable so we support turning it off
    //
    InitializeLangVariable (L"Lang", LangCodes, (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLang), TRUE);
  }

  InitializeLangVariable (L"PlatformLang", PlatformLangCodes, (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLang), FALSE);
}