1 /** @file
2   Driver to implement English version of Unicode Collation Protocol.
3 
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 
10 #include "UnicodeCollationEng.h"
11 
12 CHAR8 mEngUpperMap[MAP_TABLE_SIZE];
13 CHAR8 mEngLowerMap[MAP_TABLE_SIZE];
14 CHAR8 mEngInfoMap[MAP_TABLE_SIZE];
15 
16 CHAR8 mOtherChars[] = {
17   '0',
18   '1',
19   '2',
20   '3',
21   '4',
22   '5',
23   '6',
24   '7',
25   '8',
26   '9',
27   '\\',
28   '.',
29   '_',
30   '^',
31   '$',
32   '~',
33   '!',
34   '#',
35   '%',
36   '&',
37   '-',
38   '{',
39   '}',
40   '(',
41   ')',
42   '@',
43   '`',
44   '\'',
45   '\0'
46 };
47 
48 EFI_HANDLE  mHandle = NULL;
49 
50 //
51 // EFI Unicode Collation Protocol supporting ISO 639-2 language code
52 //
53 GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_COLLATION_PROTOCOL  UnicodeEng = {
54   EngStriColl,
55   EngMetaiMatch,
56   EngStrLwr,
57   EngStrUpr,
58   EngFatToStr,
59   EngStrToFat,
60   "eng"
61 };
62 
63 //
64 // EFI Unicode Collation2 Protocol supporting RFC 4646 language code
65 //
66 GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_COLLATION_PROTOCOL  Unicode2Eng = {
67   EngStriColl,
68   EngMetaiMatch,
69   EngStrLwr,
70   EngStrUpr,
71   EngFatToStr,
72   EngStrToFat,
73   "en"
74 };
75 
76 /**
77   The user Entry Point for English module.
78 
79   This function initializes unicode character mapping and then installs Unicode
80   Collation & Unicode Collation 2 Protocols based on the feature flags.
81 
82   @param  ImageHandle    The firmware allocated handle for the EFI image.
83   @param  SystemTable    A pointer to the EFI System Table.
84 
85   @retval EFI_SUCCESS    The entry point is executed successfully.
86   @retval other          Some error occurs when executing this entry point.
87 
88 **/
89 EFI_STATUS
90 EFIAPI
InitializeUnicodeCollationEng(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)91 InitializeUnicodeCollationEng (
92   IN EFI_HANDLE       ImageHandle,
93   IN EFI_SYSTEM_TABLE *SystemTable
94   )
95 {
96   EFI_STATUS  Status;
97   UINTN       Index;
98   UINTN       Index2;
99 
100   //
101   // Initialize mapping tables for the supported languages
102   //
103   for (Index = 0; Index < MAP_TABLE_SIZE; Index++) {
104     mEngUpperMap[Index] = (CHAR8) Index;
105     mEngLowerMap[Index] = (CHAR8) Index;
106     mEngInfoMap[Index]  = 0;
107 
108     if ((Index >= 'a' && Index <= 'z') || (Index >= 0xe0 && Index <= 0xf6) || (Index >= 0xf8 && Index <= 0xfe)) {
109 
110       Index2                = Index - 0x20;
111       mEngUpperMap[Index]   = (CHAR8) Index2;
112       mEngLowerMap[Index2]  = (CHAR8) Index;
113 
114       mEngInfoMap[Index] |= CHAR_FAT_VALID;
115       mEngInfoMap[Index2] |= CHAR_FAT_VALID;
116     }
117   }
118 
119   for (Index = 0; mOtherChars[Index] != 0; Index++) {
120     Index2 = mOtherChars[Index];
121     mEngInfoMap[Index2] |= CHAR_FAT_VALID;
122   }
123 
124   if (FeaturePcdGet (PcdUnicodeCollation2Support)) {
125     if (FeaturePcdGet (PcdUnicodeCollationSupport)) {
126       Status = gBS->InstallMultipleProtocolInterfaces (
127                       &mHandle,
128                       &gEfiUnicodeCollationProtocolGuid,
129                       &UnicodeEng,
130                       &gEfiUnicodeCollation2ProtocolGuid,
131                       &Unicode2Eng,
132                       NULL
133                       );
134       ASSERT_EFI_ERROR (Status);
135     } else {
136       Status = gBS->InstallMultipleProtocolInterfaces (
137                       &mHandle,
138                       &gEfiUnicodeCollation2ProtocolGuid,
139                       &Unicode2Eng,
140                       NULL
141                       );
142       ASSERT_EFI_ERROR (Status);
143     }
144   } else {
145     if (FeaturePcdGet (PcdUnicodeCollationSupport)) {
146       Status = gBS->InstallMultipleProtocolInterfaces (
147                       &mHandle,
148                       &gEfiUnicodeCollationProtocolGuid,
149                       &UnicodeEng,
150                       NULL
151                       );
152       ASSERT_EFI_ERROR (Status);
153     } else {
154       //
155       // This module must support to produce at least one of Unicode Collation Protocol
156       // and Unicode Collation 2 Protocol.
157       //
158       ASSERT (FALSE);
159       Status = EFI_UNSUPPORTED;
160     }
161   }
162 
163   return Status;
164 }
165 
166 
167 /**
168   Performs a case-insensitive comparison of two Null-terminated strings.
169 
170   @param  This Protocol instance pointer.
171   @param  Str1 A pointer to a Null-terminated string.
172   @param  Str2 A pointer to a Null-terminated string.
173 
174   @retval 0   Str1 is equivalent to Str2
175   @retval > 0 Str1 is lexically greater than Str2
176   @retval < 0 Str1 is lexically less than Str2
177 
178 **/
179 INTN
180 EFIAPI
EngStriColl(IN EFI_UNICODE_COLLATION_PROTOCOL * This,IN CHAR16 * Str1,IN CHAR16 * Str2)181 EngStriColl (
182   IN EFI_UNICODE_COLLATION_PROTOCOL   *This,
183   IN CHAR16                           *Str1,
184   IN CHAR16                           *Str2
185   )
186 {
187   while (*Str1 != 0) {
188     if (TO_UPPER (*Str1) != TO_UPPER (*Str2)) {
189       break;
190     }
191 
192     Str1 += 1;
193     Str2 += 1;
194   }
195 
196   return TO_UPPER (*Str1) - TO_UPPER (*Str2);
197 }
198 
199 
200 /**
201   Converts all the characters in a Null-terminated string to
202   lower case characters.
203 
204   @param  This   Protocol instance pointer.
205   @param  Str    A pointer to a Null-terminated string.
206 
207 **/
208 VOID
209 EFIAPI
EngStrLwr(IN EFI_UNICODE_COLLATION_PROTOCOL * This,IN OUT CHAR16 * Str)210 EngStrLwr (
211   IN EFI_UNICODE_COLLATION_PROTOCOL   *This,
212   IN OUT CHAR16                       *Str
213   )
214 {
215   while (*Str != 0) {
216     *Str = TO_LOWER (*Str);
217     Str += 1;
218   }
219 }
220 
221 
222 /**
223   Converts all the characters in a Null-terminated string to upper
224   case characters.
225 
226   @param  This   Protocol instance pointer.
227   @param  Str    A pointer to a Null-terminated string.
228 
229 **/
230 VOID
231 EFIAPI
EngStrUpr(IN EFI_UNICODE_COLLATION_PROTOCOL * This,IN OUT CHAR16 * Str)232 EngStrUpr (
233   IN EFI_UNICODE_COLLATION_PROTOCOL   *This,
234   IN OUT CHAR16                       *Str
235   )
236 {
237   while (*Str != 0) {
238     *Str = TO_UPPER (*Str);
239     Str += 1;
240   }
241 }
242 
243 /**
244   Performs a case-insensitive comparison of a Null-terminated
245   pattern string and a Null-terminated string.
246 
247   @param  This    Protocol instance pointer.
248   @param  String  A pointer to a Null-terminated string.
249   @param  Pattern A pointer to a Null-terminated pattern string.
250 
251   @retval TRUE    Pattern was found in String.
252   @retval FALSE   Pattern was not found in String.
253 
254 **/
255 BOOLEAN
256 EFIAPI
EngMetaiMatch(IN EFI_UNICODE_COLLATION_PROTOCOL * This,IN CHAR16 * String,IN CHAR16 * Pattern)257 EngMetaiMatch (
258   IN EFI_UNICODE_COLLATION_PROTOCOL   *This,
259   IN CHAR16                           *String,
260   IN CHAR16                           *Pattern
261   )
262 {
263   CHAR16  CharC;
264   CHAR16  CharP;
265   CHAR16  Index3;
266 
267   for (;;) {
268     CharP = *Pattern;
269     Pattern += 1;
270 
271     switch (CharP) {
272     case 0:
273       //
274       // End of pattern.  If end of string, TRUE match
275       //
276       if (*String != 0) {
277         return FALSE;
278       } else {
279         return TRUE;
280       }
281 
282     case '*':
283       //
284       // Match zero or more chars
285       //
286       while (*String != 0) {
287         if (EngMetaiMatch (This, String, Pattern)) {
288           return TRUE;
289         }
290 
291         String += 1;
292       }
293 
294       return EngMetaiMatch (This, String, Pattern);
295 
296     case '?':
297       //
298       // Match any one char
299       //
300       if (*String == 0) {
301         return FALSE;
302       }
303 
304       String += 1;
305       break;
306 
307     case '[':
308       //
309       // Match char set
310       //
311       CharC = *String;
312       if (CharC == 0) {
313         //
314         // syntax problem
315         //
316         return FALSE;
317       }
318 
319       Index3  = 0;
320       CharP   = *Pattern++;
321       while (CharP != 0) {
322         if (CharP == ']') {
323           return FALSE;
324         }
325 
326         if (CharP == '-') {
327           //
328           // if range of chars, get high range
329           //
330           CharP = *Pattern;
331           if (CharP == 0 || CharP == ']') {
332             //
333             // syntax problem
334             //
335             return FALSE;
336           }
337 
338           if (TO_UPPER (CharC) >= TO_UPPER (Index3) && TO_UPPER (CharC) <= TO_UPPER (CharP)) {
339             //
340             // if in range, it's a match
341             //
342             break;
343           }
344         }
345 
346         Index3 = CharP;
347         if (TO_UPPER (CharC) == TO_UPPER (CharP)) {
348           //
349           // if char matches
350           //
351           break;
352         }
353 
354         CharP = *Pattern++;
355       }
356       //
357       // skip to end of match char set
358       //
359       while ((CharP != 0) && (CharP != ']')) {
360         CharP = *Pattern;
361         Pattern += 1;
362       }
363 
364       String += 1;
365       break;
366 
367     default:
368       CharC = *String;
369       if (TO_UPPER (CharC) != TO_UPPER (CharP)) {
370         return FALSE;
371       }
372 
373       String += 1;
374       break;
375     }
376   }
377 }
378 
379 
380 /**
381   Converts an 8.3 FAT file name in an OEM character set to a Null-terminated string.
382 
383   @param  This    Protocol instance pointer.
384   @param  FatSize The size of the string Fat in bytes.
385   @param  Fat     A pointer to a Null-terminated string that contains an 8.3 file
386                   name using an 8-bit OEM character set.
387   @param  String  A pointer to a Null-terminated string. The string must
388                   be preallocated to hold FatSize characters.
389 
390 **/
391 VOID
392 EFIAPI
EngFatToStr(IN EFI_UNICODE_COLLATION_PROTOCOL * This,IN UINTN FatSize,IN CHAR8 * Fat,OUT CHAR16 * String)393 EngFatToStr (
394   IN EFI_UNICODE_COLLATION_PROTOCOL   *This,
395   IN UINTN                            FatSize,
396   IN CHAR8                            *Fat,
397   OUT CHAR16                          *String
398   )
399 {
400   //
401   // No DBCS issues, just expand and add null terminate to end of string
402   //
403   while ((*Fat != 0) && (FatSize != 0)) {
404     *String = *Fat;
405     String += 1;
406     Fat += 1;
407     FatSize -= 1;
408   }
409 
410   *String = 0;
411 }
412 
413 
414 /**
415   Converts a Null-terminated string to legal characters in a FAT
416   filename using an OEM character set.
417 
418   @param  This    Protocol instance pointer.
419   @param  String  A pointer to a Null-terminated string. The string must
420                   be preallocated to hold FatSize characters.
421   @param  FatSize The size of the string Fat in bytes.
422   @param  Fat     A pointer to a Null-terminated string that contains an 8.3 file
423                   name using an OEM character set.
424 
425   @retval TRUE    Fat is a Long File Name
426   @retval FALSE   Fat is an 8.3 file name
427 
428 **/
429 BOOLEAN
430 EFIAPI
EngStrToFat(IN EFI_UNICODE_COLLATION_PROTOCOL * This,IN CHAR16 * String,IN UINTN FatSize,OUT CHAR8 * Fat)431 EngStrToFat (
432   IN EFI_UNICODE_COLLATION_PROTOCOL   *This,
433   IN CHAR16                           *String,
434   IN UINTN                            FatSize,
435   OUT CHAR8                           *Fat
436   )
437 {
438   BOOLEAN SpecialCharExist;
439 
440   SpecialCharExist = FALSE;
441   while ((*String != 0) && (FatSize != 0)) {
442     //
443     // Skip '.' or ' ' when making a fat name
444     //
445     if (*String != '.' && *String != ' ') {
446       //
447       // If this is a valid fat char, move it.
448       // Otherwise, move a '_' and flag the fact that the name needs a long file name.
449       //
450       if (*String < MAP_TABLE_SIZE && ((mEngInfoMap[*String] & CHAR_FAT_VALID) != 0)) {
451         *Fat = mEngUpperMap[*String];
452       } else {
453         *Fat              = '_';
454         SpecialCharExist  = TRUE;
455       }
456 
457       Fat += 1;
458       FatSize -= 1;
459     }
460 
461     String += 1;
462   }
463   //
464   // Do not terminate that fat string
465   //
466   return SpecialCharExist;
467 }
468