1*0bc4b0daSHeinrich Schuchardt // SPDX-License-Identifier: GPL-2.0+
2*0bc4b0daSHeinrich Schuchardt /*
3*0bc4b0daSHeinrich Schuchardt * EFI Unicode collation protocol
4*0bc4b0daSHeinrich Schuchardt *
5*0bc4b0daSHeinrich Schuchardt * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
6*0bc4b0daSHeinrich Schuchardt */
7*0bc4b0daSHeinrich Schuchardt
8*0bc4b0daSHeinrich Schuchardt #include <common.h>
9*0bc4b0daSHeinrich Schuchardt #include <charset.h>
10*0bc4b0daSHeinrich Schuchardt #include <cp1250.h>
11*0bc4b0daSHeinrich Schuchardt #include <cp437.h>
12*0bc4b0daSHeinrich Schuchardt #include <efi_loader.h>
13*0bc4b0daSHeinrich Schuchardt
14*0bc4b0daSHeinrich Schuchardt /* Characters that may not be used in file names */
15*0bc4b0daSHeinrich Schuchardt static const char illegal[] = "<>:\"/\\|?*";
16*0bc4b0daSHeinrich Schuchardt
17*0bc4b0daSHeinrich Schuchardt /*
18*0bc4b0daSHeinrich Schuchardt * EDK2 assumes codepage 1250 when creating FAT 8.3 file names.
19*0bc4b0daSHeinrich Schuchardt * Linux defaults to codepage 437 for FAT 8.3 file names.
20*0bc4b0daSHeinrich Schuchardt */
21*0bc4b0daSHeinrich Schuchardt #if CONFIG_FAT_DEFAULT_CODEPAGE == 1250
22*0bc4b0daSHeinrich Schuchardt /* Unicode code points for code page 1250 characters 0x80 - 0xff */
23*0bc4b0daSHeinrich Schuchardt static const u16 codepage[] = CP1250;
24*0bc4b0daSHeinrich Schuchardt #else
25*0bc4b0daSHeinrich Schuchardt /* Unicode code points for code page 437 characters 0x80 - 0xff */
26*0bc4b0daSHeinrich Schuchardt static const u16 codepage[] = CP437;
27*0bc4b0daSHeinrich Schuchardt #endif
28*0bc4b0daSHeinrich Schuchardt
29*0bc4b0daSHeinrich Schuchardt /* GUID of the EFI_UNICODE_COLLATION_PROTOCOL */
30*0bc4b0daSHeinrich Schuchardt const efi_guid_t efi_guid_unicode_collation_protocol =
31*0bc4b0daSHeinrich Schuchardt EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
32*0bc4b0daSHeinrich Schuchardt
33*0bc4b0daSHeinrich Schuchardt /**
34*0bc4b0daSHeinrich Schuchardt * efi_stri_coll() - compare utf-16 strings case-insenitively
35*0bc4b0daSHeinrich Schuchardt *
36*0bc4b0daSHeinrich Schuchardt * @this: unicode collation protocol instance
37*0bc4b0daSHeinrich Schuchardt * @s1: first string
38*0bc4b0daSHeinrich Schuchardt * @s2: second string
39*0bc4b0daSHeinrich Schuchardt *
40*0bc4b0daSHeinrich Schuchardt * This function implements the StriColl() service of the
41*0bc4b0daSHeinrich Schuchardt * EFI_UNICODE_COLLATION_PROTOCOL.
42*0bc4b0daSHeinrich Schuchardt *
43*0bc4b0daSHeinrich Schuchardt * See the Unified Extensible Firmware Interface (UEFI) specification for
44*0bc4b0daSHeinrich Schuchardt * details.
45*0bc4b0daSHeinrich Schuchardt *
46*0bc4b0daSHeinrich Schuchardt * TODO:
47*0bc4b0daSHeinrich Schuchardt * The implementation does not follow the Unicode collation algorithm.
48*0bc4b0daSHeinrich Schuchardt * For ASCII characters it results in the same sort order as EDK2.
49*0bc4b0daSHeinrich Schuchardt * We could use table UNICODE_CAPITALIZATION_TABLE for better results.
50*0bc4b0daSHeinrich Schuchardt *
51*0bc4b0daSHeinrich Schuchardt * Return: 0: s1 == s2, > 0: s1 > s2, < 0: s1 < s2
52*0bc4b0daSHeinrich Schuchardt */
efi_stri_coll(struct efi_unicode_collation_protocol * this,u16 * s1,u16 * s2)53*0bc4b0daSHeinrich Schuchardt static efi_intn_t EFIAPI efi_stri_coll(
54*0bc4b0daSHeinrich Schuchardt struct efi_unicode_collation_protocol *this, u16 *s1, u16 *s2)
55*0bc4b0daSHeinrich Schuchardt {
56*0bc4b0daSHeinrich Schuchardt s32 c1, c2;
57*0bc4b0daSHeinrich Schuchardt efi_intn_t ret = 0;
58*0bc4b0daSHeinrich Schuchardt
59*0bc4b0daSHeinrich Schuchardt EFI_ENTRY("%p, %ls, %ls", this, s1, s2);
60*0bc4b0daSHeinrich Schuchardt for (; *s1 | *s2; ++s1, ++s2) {
61*0bc4b0daSHeinrich Schuchardt c1 = utf_to_upper(*s1);
62*0bc4b0daSHeinrich Schuchardt c2 = utf_to_upper(*s2);
63*0bc4b0daSHeinrich Schuchardt if (c1 < c2) {
64*0bc4b0daSHeinrich Schuchardt ret = -1;
65*0bc4b0daSHeinrich Schuchardt goto out;
66*0bc4b0daSHeinrich Schuchardt } else if (c1 > c2) {
67*0bc4b0daSHeinrich Schuchardt ret = 1;
68*0bc4b0daSHeinrich Schuchardt goto out;
69*0bc4b0daSHeinrich Schuchardt }
70*0bc4b0daSHeinrich Schuchardt }
71*0bc4b0daSHeinrich Schuchardt out:
72*0bc4b0daSHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS);
73*0bc4b0daSHeinrich Schuchardt return ret;
74*0bc4b0daSHeinrich Schuchardt }
75*0bc4b0daSHeinrich Schuchardt
76*0bc4b0daSHeinrich Schuchardt /**
77*0bc4b0daSHeinrich Schuchardt * metai_match() - compare utf-16 string with a pattern string case-insenitively
78*0bc4b0daSHeinrich Schuchardt *
79*0bc4b0daSHeinrich Schuchardt * @s: string to compare
80*0bc4b0daSHeinrich Schuchardt * @p: pattern string
81*0bc4b0daSHeinrich Schuchardt *
82*0bc4b0daSHeinrich Schuchardt * The pattern string may use these:
83*0bc4b0daSHeinrich Schuchardt * - * matches >= 0 characters
84*0bc4b0daSHeinrich Schuchardt * - ? matches 1 character
85*0bc4b0daSHeinrich Schuchardt * - [<char1><char2>...<charN>] match any character in the set
86*0bc4b0daSHeinrich Schuchardt * - [<char1>-<char2>] matches any character in the range
87*0bc4b0daSHeinrich Schuchardt *
88*0bc4b0daSHeinrich Schuchardt * This function is called my efi_metai_match().
89*0bc4b0daSHeinrich Schuchardt *
90*0bc4b0daSHeinrich Schuchardt * For '*' pattern searches this function calls itself recursively.
91*0bc4b0daSHeinrich Schuchardt * Performance-wise this is suboptimal, especially for multiple '*' wildcards.
92*0bc4b0daSHeinrich Schuchardt * But it results in simple code.
93*0bc4b0daSHeinrich Schuchardt *
94*0bc4b0daSHeinrich Schuchardt * Return: true if the string is matched.
95*0bc4b0daSHeinrich Schuchardt */
metai_match(const u16 * s,const u16 * p)96*0bc4b0daSHeinrich Schuchardt static bool metai_match(const u16 *s, const u16 *p)
97*0bc4b0daSHeinrich Schuchardt {
98*0bc4b0daSHeinrich Schuchardt u16 first;
99*0bc4b0daSHeinrich Schuchardt
100*0bc4b0daSHeinrich Schuchardt for (; *s && *p; ++s, ++p) {
101*0bc4b0daSHeinrich Schuchardt switch (*p) {
102*0bc4b0daSHeinrich Schuchardt case '*':
103*0bc4b0daSHeinrich Schuchardt /* Match 0 or more characters */
104*0bc4b0daSHeinrich Schuchardt ++p;
105*0bc4b0daSHeinrich Schuchardt for (;; ++s) {
106*0bc4b0daSHeinrich Schuchardt if (metai_match(s, p))
107*0bc4b0daSHeinrich Schuchardt return true;
108*0bc4b0daSHeinrich Schuchardt if (!*s)
109*0bc4b0daSHeinrich Schuchardt return false;
110*0bc4b0daSHeinrich Schuchardt }
111*0bc4b0daSHeinrich Schuchardt case '?':
112*0bc4b0daSHeinrich Schuchardt /* Match any one character */
113*0bc4b0daSHeinrich Schuchardt break;
114*0bc4b0daSHeinrich Schuchardt case '[':
115*0bc4b0daSHeinrich Schuchardt /* Match any character in the set */
116*0bc4b0daSHeinrich Schuchardt ++p;
117*0bc4b0daSHeinrich Schuchardt first = *p;
118*0bc4b0daSHeinrich Schuchardt if (first == ']')
119*0bc4b0daSHeinrich Schuchardt /* Empty set */
120*0bc4b0daSHeinrich Schuchardt return false;
121*0bc4b0daSHeinrich Schuchardt ++p;
122*0bc4b0daSHeinrich Schuchardt if (*p == '-') {
123*0bc4b0daSHeinrich Schuchardt /* Range */
124*0bc4b0daSHeinrich Schuchardt ++p;
125*0bc4b0daSHeinrich Schuchardt if (*s < first || *s > *p)
126*0bc4b0daSHeinrich Schuchardt return false;
127*0bc4b0daSHeinrich Schuchardt ++p;
128*0bc4b0daSHeinrich Schuchardt if (*p != ']')
129*0bc4b0daSHeinrich Schuchardt return false;
130*0bc4b0daSHeinrich Schuchardt } else {
131*0bc4b0daSHeinrich Schuchardt /* Set */
132*0bc4b0daSHeinrich Schuchardt bool hit = false;
133*0bc4b0daSHeinrich Schuchardt
134*0bc4b0daSHeinrich Schuchardt if (*s == first)
135*0bc4b0daSHeinrich Schuchardt hit = true;
136*0bc4b0daSHeinrich Schuchardt for (; *p && *p != ']'; ++p) {
137*0bc4b0daSHeinrich Schuchardt if (*p == *s)
138*0bc4b0daSHeinrich Schuchardt hit = true;
139*0bc4b0daSHeinrich Schuchardt }
140*0bc4b0daSHeinrich Schuchardt if (!hit || *p != ']')
141*0bc4b0daSHeinrich Schuchardt return false;
142*0bc4b0daSHeinrich Schuchardt }
143*0bc4b0daSHeinrich Schuchardt break;
144*0bc4b0daSHeinrich Schuchardt default:
145*0bc4b0daSHeinrich Schuchardt /* Match one character */
146*0bc4b0daSHeinrich Schuchardt if (*p != *s)
147*0bc4b0daSHeinrich Schuchardt return false;
148*0bc4b0daSHeinrich Schuchardt }
149*0bc4b0daSHeinrich Schuchardt }
150*0bc4b0daSHeinrich Schuchardt if (!*p && !*s)
151*0bc4b0daSHeinrich Schuchardt return true;
152*0bc4b0daSHeinrich Schuchardt return false;
153*0bc4b0daSHeinrich Schuchardt }
154*0bc4b0daSHeinrich Schuchardt
155*0bc4b0daSHeinrich Schuchardt /**
156*0bc4b0daSHeinrich Schuchardt * efi_metai_match() - compare utf-16 string with a pattern string
157*0bc4b0daSHeinrich Schuchardt * case-insenitively
158*0bc4b0daSHeinrich Schuchardt *
159*0bc4b0daSHeinrich Schuchardt * @this: unicode collation protocol instance
160*0bc4b0daSHeinrich Schuchardt * @s: string to compare
161*0bc4b0daSHeinrich Schuchardt * @p: pattern string
162*0bc4b0daSHeinrich Schuchardt *
163*0bc4b0daSHeinrich Schuchardt * The pattern string may use these:
164*0bc4b0daSHeinrich Schuchardt * - * matches >= 0 characters
165*0bc4b0daSHeinrich Schuchardt * - ? matches 1 character
166*0bc4b0daSHeinrich Schuchardt * - [<char1><char2>...<charN>] match any character in the set
167*0bc4b0daSHeinrich Schuchardt * - [<char1>-<char2>] matches any character in the range
168*0bc4b0daSHeinrich Schuchardt *
169*0bc4b0daSHeinrich Schuchardt * This function implements the MetaMatch() service of the
170*0bc4b0daSHeinrich Schuchardt * EFI_UNICODE_COLLATION_PROTOCOL.
171*0bc4b0daSHeinrich Schuchardt *
172*0bc4b0daSHeinrich Schuchardt * Return: true if the string is matched.
173*0bc4b0daSHeinrich Schuchardt */
efi_metai_match(struct efi_unicode_collation_protocol * this,const u16 * string,const u16 * pattern)174*0bc4b0daSHeinrich Schuchardt static bool EFIAPI efi_metai_match(struct efi_unicode_collation_protocol *this,
175*0bc4b0daSHeinrich Schuchardt const u16 *string, const u16 *pattern)
176*0bc4b0daSHeinrich Schuchardt {
177*0bc4b0daSHeinrich Schuchardt bool ret;
178*0bc4b0daSHeinrich Schuchardt
179*0bc4b0daSHeinrich Schuchardt EFI_ENTRY("%p, %ls, %ls", this, string, pattern);
180*0bc4b0daSHeinrich Schuchardt ret = metai_match(string, pattern);
181*0bc4b0daSHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS);
182*0bc4b0daSHeinrich Schuchardt return ret;
183*0bc4b0daSHeinrich Schuchardt }
184*0bc4b0daSHeinrich Schuchardt
185*0bc4b0daSHeinrich Schuchardt /**
186*0bc4b0daSHeinrich Schuchardt * efi_str_lwr() - convert to lower case
187*0bc4b0daSHeinrich Schuchardt *
188*0bc4b0daSHeinrich Schuchardt * @this: unicode collation protocol instance
189*0bc4b0daSHeinrich Schuchardt * @string: string to convert
190*0bc4b0daSHeinrich Schuchardt * @p: pattern string
191*0bc4b0daSHeinrich Schuchardt *
192*0bc4b0daSHeinrich Schuchardt * The conversion is done in place. As long as upper and lower letters use the
193*0bc4b0daSHeinrich Schuchardt * same number of words this does not pose a problem.
194*0bc4b0daSHeinrich Schuchardt *
195*0bc4b0daSHeinrich Schuchardt * This function implements the StrLwr() service of the
196*0bc4b0daSHeinrich Schuchardt * EFI_UNICODE_COLLATION_PROTOCOL.
197*0bc4b0daSHeinrich Schuchardt */
efi_str_lwr(struct efi_unicode_collation_protocol * this,u16 * string)198*0bc4b0daSHeinrich Schuchardt static void EFIAPI efi_str_lwr(struct efi_unicode_collation_protocol *this,
199*0bc4b0daSHeinrich Schuchardt u16 *string)
200*0bc4b0daSHeinrich Schuchardt {
201*0bc4b0daSHeinrich Schuchardt EFI_ENTRY("%p, %ls", this, string);
202*0bc4b0daSHeinrich Schuchardt for (; *string; ++string)
203*0bc4b0daSHeinrich Schuchardt *string = utf_to_lower(*string);
204*0bc4b0daSHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS);
205*0bc4b0daSHeinrich Schuchardt }
206*0bc4b0daSHeinrich Schuchardt
207*0bc4b0daSHeinrich Schuchardt /**
208*0bc4b0daSHeinrich Schuchardt * efi_str_upr() - convert to upper case
209*0bc4b0daSHeinrich Schuchardt *
210*0bc4b0daSHeinrich Schuchardt * @this: unicode collation protocol instance
211*0bc4b0daSHeinrich Schuchardt * @string: string to convert
212*0bc4b0daSHeinrich Schuchardt * @p: pattern string
213*0bc4b0daSHeinrich Schuchardt *
214*0bc4b0daSHeinrich Schuchardt * The conversion is done in place. As long as upper and lower letters use the
215*0bc4b0daSHeinrich Schuchardt * same number of words this does not pose a problem.
216*0bc4b0daSHeinrich Schuchardt *
217*0bc4b0daSHeinrich Schuchardt * This function implements the StrUpr() service of the
218*0bc4b0daSHeinrich Schuchardt * EFI_UNICODE_COLLATION_PROTOCOL.
219*0bc4b0daSHeinrich Schuchardt */
efi_str_upr(struct efi_unicode_collation_protocol * this,u16 * string)220*0bc4b0daSHeinrich Schuchardt static void EFIAPI efi_str_upr(struct efi_unicode_collation_protocol *this,
221*0bc4b0daSHeinrich Schuchardt u16 *string)
222*0bc4b0daSHeinrich Schuchardt {
223*0bc4b0daSHeinrich Schuchardt EFI_ENTRY("%p, %ls", this, string);
224*0bc4b0daSHeinrich Schuchardt for (; *string; ++string)
225*0bc4b0daSHeinrich Schuchardt *string = utf_to_upper(*string);
226*0bc4b0daSHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS);
227*0bc4b0daSHeinrich Schuchardt }
228*0bc4b0daSHeinrich Schuchardt
229*0bc4b0daSHeinrich Schuchardt /**
230*0bc4b0daSHeinrich Schuchardt * efi_fat_to_str() - convert an 8.3 file name from an OEM codepage to Unicode
231*0bc4b0daSHeinrich Schuchardt *
232*0bc4b0daSHeinrich Schuchardt * @this: unicode collation protocol instance
233*0bc4b0daSHeinrich Schuchardt * @fat_size: size of the string to convert
234*0bc4b0daSHeinrich Schuchardt * @fat: string to convert
235*0bc4b0daSHeinrich Schuchardt * @string: converted string
236*0bc4b0daSHeinrich Schuchardt *
237*0bc4b0daSHeinrich Schuchardt * This function implements the FatToStr() service of the
238*0bc4b0daSHeinrich Schuchardt * EFI_UNICODE_COLLATION_PROTOCOL.
239*0bc4b0daSHeinrich Schuchardt */
efi_fat_to_str(struct efi_unicode_collation_protocol * this,efi_uintn_t fat_size,char * fat,u16 * string)240*0bc4b0daSHeinrich Schuchardt static void EFIAPI efi_fat_to_str(struct efi_unicode_collation_protocol *this,
241*0bc4b0daSHeinrich Schuchardt efi_uintn_t fat_size, char *fat, u16 *string)
242*0bc4b0daSHeinrich Schuchardt {
243*0bc4b0daSHeinrich Schuchardt efi_uintn_t i;
244*0bc4b0daSHeinrich Schuchardt u16 c;
245*0bc4b0daSHeinrich Schuchardt
246*0bc4b0daSHeinrich Schuchardt EFI_ENTRY("%p, %zu, %s, %p", this, fat_size, fat, string);
247*0bc4b0daSHeinrich Schuchardt for (i = 0; i < fat_size; ++i) {
248*0bc4b0daSHeinrich Schuchardt c = (unsigned char)fat[i];
249*0bc4b0daSHeinrich Schuchardt if (c > 0x80)
250*0bc4b0daSHeinrich Schuchardt c = codepage[i - 0x80];
251*0bc4b0daSHeinrich Schuchardt string[i] = c;
252*0bc4b0daSHeinrich Schuchardt if (!c)
253*0bc4b0daSHeinrich Schuchardt break;
254*0bc4b0daSHeinrich Schuchardt }
255*0bc4b0daSHeinrich Schuchardt string[i] = 0;
256*0bc4b0daSHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS);
257*0bc4b0daSHeinrich Schuchardt }
258*0bc4b0daSHeinrich Schuchardt
259*0bc4b0daSHeinrich Schuchardt /**
260*0bc4b0daSHeinrich Schuchardt * efi_fat_to_str() - convert a utf-16 string to legal characters for a FAT
261*0bc4b0daSHeinrich Schuchardt * file name in an OEM code page
262*0bc4b0daSHeinrich Schuchardt *
263*0bc4b0daSHeinrich Schuchardt * @this: unicode collation protocol instance
264*0bc4b0daSHeinrich Schuchardt * @string: Unicode string to convert
265*0bc4b0daSHeinrich Schuchardt * @fat_size: size of the target buffer
266*0bc4b0daSHeinrich Schuchardt * @fat: converted string
267*0bc4b0daSHeinrich Schuchardt *
268*0bc4b0daSHeinrich Schuchardt * This function implements the StrToFat() service of the
269*0bc4b0daSHeinrich Schuchardt * EFI_UNICODE_COLLATION_PROTOCOL.
270*0bc4b0daSHeinrich Schuchardt *
271*0bc4b0daSHeinrich Schuchardt * Return: true if an illegal character was substituted by '_'.
272*0bc4b0daSHeinrich Schuchardt */
efi_str_to_fat(struct efi_unicode_collation_protocol * this,const u16 * string,efi_uintn_t fat_size,char * fat)273*0bc4b0daSHeinrich Schuchardt static bool EFIAPI efi_str_to_fat(struct efi_unicode_collation_protocol *this,
274*0bc4b0daSHeinrich Schuchardt const u16 *string, efi_uintn_t fat_size,
275*0bc4b0daSHeinrich Schuchardt char *fat)
276*0bc4b0daSHeinrich Schuchardt {
277*0bc4b0daSHeinrich Schuchardt efi_uintn_t i;
278*0bc4b0daSHeinrich Schuchardt s32 c;
279*0bc4b0daSHeinrich Schuchardt bool ret = false;
280*0bc4b0daSHeinrich Schuchardt
281*0bc4b0daSHeinrich Schuchardt EFI_ENTRY("%p, %ls, %zu, %p", this, string, fat_size, fat);
282*0bc4b0daSHeinrich Schuchardt for (i = 0; i < fat_size;) {
283*0bc4b0daSHeinrich Schuchardt c = utf16_get(&string);
284*0bc4b0daSHeinrich Schuchardt switch (c) {
285*0bc4b0daSHeinrich Schuchardt /* Ignore period and space */
286*0bc4b0daSHeinrich Schuchardt case '.':
287*0bc4b0daSHeinrich Schuchardt case ' ':
288*0bc4b0daSHeinrich Schuchardt continue;
289*0bc4b0daSHeinrich Schuchardt case 0:
290*0bc4b0daSHeinrich Schuchardt break;
291*0bc4b0daSHeinrich Schuchardt }
292*0bc4b0daSHeinrich Schuchardt c = utf_to_upper(c);
293*0bc4b0daSHeinrich Schuchardt if (c >= 0x80) {
294*0bc4b0daSHeinrich Schuchardt int j;
295*0bc4b0daSHeinrich Schuchardt
296*0bc4b0daSHeinrich Schuchardt /* Look for codepage translation */
297*0bc4b0daSHeinrich Schuchardt for (j = 0; j < 0x80; ++j) {
298*0bc4b0daSHeinrich Schuchardt if (c == codepage[j]) {
299*0bc4b0daSHeinrich Schuchardt c = j + 0x80;
300*0bc4b0daSHeinrich Schuchardt break;
301*0bc4b0daSHeinrich Schuchardt }
302*0bc4b0daSHeinrich Schuchardt }
303*0bc4b0daSHeinrich Schuchardt if (j >= 0x80) {
304*0bc4b0daSHeinrich Schuchardt c = '_';
305*0bc4b0daSHeinrich Schuchardt ret = true;
306*0bc4b0daSHeinrich Schuchardt }
307*0bc4b0daSHeinrich Schuchardt } else if (c && (c < 0x20 || strchr(illegal, c))) {
308*0bc4b0daSHeinrich Schuchardt c = '_';
309*0bc4b0daSHeinrich Schuchardt ret = true;
310*0bc4b0daSHeinrich Schuchardt }
311*0bc4b0daSHeinrich Schuchardt
312*0bc4b0daSHeinrich Schuchardt fat[i] = c;
313*0bc4b0daSHeinrich Schuchardt if (!c)
314*0bc4b0daSHeinrich Schuchardt break;
315*0bc4b0daSHeinrich Schuchardt ++i;
316*0bc4b0daSHeinrich Schuchardt }
317*0bc4b0daSHeinrich Schuchardt EFI_EXIT(EFI_SUCCESS);
318*0bc4b0daSHeinrich Schuchardt return ret;
319*0bc4b0daSHeinrich Schuchardt }
320*0bc4b0daSHeinrich Schuchardt
321*0bc4b0daSHeinrich Schuchardt const struct efi_unicode_collation_protocol efi_unicode_collation_protocol = {
322*0bc4b0daSHeinrich Schuchardt .stri_coll = efi_stri_coll,
323*0bc4b0daSHeinrich Schuchardt .metai_match = efi_metai_match,
324*0bc4b0daSHeinrich Schuchardt .str_lwr = efi_str_lwr,
325*0bc4b0daSHeinrich Schuchardt .str_upr = efi_str_upr,
326*0bc4b0daSHeinrich Schuchardt .fat_to_str = efi_fat_to_str,
327*0bc4b0daSHeinrich Schuchardt .str_to_fat = efi_str_to_fat,
328*0bc4b0daSHeinrich Schuchardt .supported_languages = "en",
329*0bc4b0daSHeinrich Schuchardt };
330