]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/FileName.c
1. Correct File header to ## @file 2. Remove unnecessary .common] postfix on section.
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / FileName.c
CommitLineData
b9ec9330
QH
1/*++\r
2\r
3Copyright (c) 2005 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials are licensed and made available\r
5under the terms and conditions of the BSD License which accompanies this\r
6distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12\r
13Module Name:\r
14\r
15 FileName.c\r
16\r
17Abstract:\r
18\r
19 Functions for manipulating file names\r
20\r
21Revision History\r
22\r
23--*/\r
24\r
25#include "Fat.h"\r
26\r
27BOOLEAN\r
28FatCheckIs8Dot3Name (\r
29 IN CHAR16 *FileName,\r
30 OUT CHAR8 *File8Dot3Name\r
31 )\r
32/*++\r
33\r
34Routine Description:\r
35\r
36 This function checks whether the input FileName is a valid 8.3 short name.\r
37 If the input FileName is a valid 8.3, the output is the 8.3 short name;\r
38 otherwise, the output is the base tag of 8.3 short name.\r
39\r
40Arguments:\r
41\r
42 FileName - The input unicode filename.\r
43 File8Dot3Name - The output ascii 8.3 short name or base tag of 8.3 short name.\r
44\r
45Returns:\r
46\r
47 TRUE - The input unicode filename is a valid 8.3 short name.\r
48 FALSE - The input unicode filename is not a valid 8.3 short name.\r
49\r
50--*/\r
51{\r
52 BOOLEAN PossibleShortName;\r
53 CHAR16 *TempName;\r
54 CHAR16 *ExtendName;\r
55 CHAR16 *SeparateDot;\r
56 UINTN MainNameLen;\r
57 UINTN ExtendNameLen;\r
58\r
59 PossibleShortName = TRUE;\r
60 SeparateDot = NULL;\r
61 SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');\r
62 for (TempName = FileName; *TempName; TempName++) {\r
63 if (*TempName == L'.') {\r
64 SeparateDot = TempName;\r
65 }\r
66 }\r
67\r
68 if (SeparateDot == NULL) {\r
69 //\r
70 // Extended filename is not detected\r
71 //\r
72 MainNameLen = TempName - FileName;\r
73 ExtendName = TempName;\r
74 ExtendNameLen = 0;\r
75 } else {\r
76 //\r
77 // Extended filename is detected\r
78 //\r
79 MainNameLen = SeparateDot - FileName;\r
80 ExtendName = SeparateDot + 1;\r
81 ExtendNameLen = TempName - ExtendName;\r
82 }\r
83 //\r
84 // We scan the filename for the second time\r
85 // to check if there exists any extra blanks and dots\r
86 //\r
87 while (--TempName >= FileName) {\r
88 if ((*TempName == L'.' || *TempName == L' ') && (TempName != SeparateDot)) {\r
89 //\r
90 // There exist extra blanks and dots\r
91 //\r
92 PossibleShortName = FALSE;\r
93 }\r
94 }\r
95\r
96 if (MainNameLen == 0) {\r
97 PossibleShortName = FALSE;\r
98 }\r
99\r
100 if (MainNameLen > FAT_MAIN_NAME_LEN) {\r
101 PossibleShortName = FALSE;\r
102 MainNameLen = FAT_MAIN_NAME_LEN;\r
103 }\r
104\r
105 if (ExtendNameLen > FAT_EXTEND_NAME_LEN) {\r
106 PossibleShortName = FALSE;\r
107 ExtendNameLen = FAT_EXTEND_NAME_LEN;\r
108 }\r
109\r
110 if (FatStrToFat (FileName, MainNameLen, File8Dot3Name)) {\r
111 PossibleShortName = FALSE;\r
112 }\r
113\r
114 if (FatStrToFat (ExtendName, ExtendNameLen, File8Dot3Name + FAT_MAIN_NAME_LEN)) {\r
115 PossibleShortName = FALSE;\r
116 }\r
117\r
118 return PossibleShortName;\r
119}\r
120\r
121STATIC\r
122UINTN\r
123FatTrimAsciiTrailingBlanks (\r
124 IN CHAR8 *Name,\r
125 IN UINTN Len\r
126 )\r
127/*++\r
128\r
129Routine Description:\r
130\r
131 Trim the trailing blanks of fat name.\r
132\r
133Arguments:\r
134\r
135 Name - The Char8 string needs to be trimed.\r
136 Len - The length of the fat name.\r
137\r
138Returns:\r
139\r
140 The real length of the fat name after the trailing blanks are trimmed.\r
141\r
142--*/\r
143{\r
144 while (Len > 0 && Name[Len - 1] == ' ') {\r
145 Len--;\r
146 }\r
147\r
148 return Len;\r
149}\r
150\r
151VOID\r
152FatNameToStr (\r
153 IN CHAR8 *FatName,\r
154 IN UINTN Len,\r
155 IN UINTN LowerCase,\r
156 OUT CHAR16 *Str\r
157 )\r
158/*++\r
159\r
160Routine Description:\r
161\r
162 Convert the ascii fat name to the unicode string and strip trailing spaces,\r
163 and if necessary, convert the unicode string to lower case.\r
164\r
165Arguments:\r
166\r
167 FatName - The Char8 string needs to be converted.\r
168 Len - The length of the fat name.\r
169 LowerCase - Indicate whether to convert the string to lower case.\r
170 Str - The result of the convertion.\r
171\r
172Returns:\r
173\r
174 None.\r
175\r
176--*/\r
177{\r
178 //\r
179 // First, trim the trailing blanks\r
180 //\r
181 Len = FatTrimAsciiTrailingBlanks (FatName, Len);\r
182 //\r
183 // Convert fat string to unicode string\r
184 //\r
185 FatFatToStr (Len, FatName, Str);\r
186\r
187 //\r
188 // If the name is to be lower cased, do it now\r
189 //\r
190 if (LowerCase != 0) {\r
191 FatStrLwr (Str);\r
192 }\r
193}\r
194\r
195VOID\r
196FatCreate8Dot3Name (\r
197 IN FAT_OFILE *Parent,\r
198 IN FAT_DIRENT *DirEnt\r
199 )\r
200/*++\r
201\r
202Routine Description:\r
203\r
204 This function generates 8Dot3 name from user specified name for a newly created file.\r
205\r
206Arguments:\r
207\r
208 Parent - The parent directory.\r
209 DirEnt - The directory entry whose 8Dot3Name needs to be generated.\r
210\r
211Returns:\r
212\r
213 None.\r
214\r
215--*/\r
216{\r
217 CHAR8 *ShortName;\r
218 CHAR8 *ShortNameChar;\r
219 UINTN BaseTagLen;\r
220 UINTN Index;\r
221 UINTN Retry;\r
222 UINT8 Segment;\r
223 union {\r
224 UINT32 Crc;\r
225 struct HEX_DATA {\r
226 UINT8 Segment : HASH_VALUE_TAG_LEN;\r
227 } Hex[HASH_VALUE_TAG_LEN];\r
228 } HashValue;\r
229 //\r
230 // Make sure the whole directory has been loaded\r
231 //\r
232 ASSERT (Parent->ODir->EndOfDir);\r
233 ShortName = DirEnt->Entry.FileName;\r
234\r
235 //\r
236 // Trim trailing blanks of 8.3 name\r
237 //\r
238 BaseTagLen = FatTrimAsciiTrailingBlanks (ShortName, FAT_MAIN_NAME_LEN);\r
239 if (BaseTagLen > SPEC_BASE_TAG_LEN) {\r
240 BaseTagLen = SPEC_BASE_TAG_LEN;\r
241 }\r
242 //\r
243 // We first use the algorithm described by spec.\r
244 //\r
245 ShortNameChar = ShortName + BaseTagLen;\r
246 *ShortNameChar++ = '~';\r
247 *ShortNameChar = '1';\r
248 Retry = 0;\r
249 while (*FatShortNameHashSearch (Parent->ODir, ShortName) != NULL) {\r
250 *ShortNameChar = (CHAR8)(*ShortNameChar + 1);\r
251 if (++Retry == MAX_SPEC_RETRY) {\r
252 //\r
253 // We use new algorithm to generate 8.3 name\r
254 //\r
255 ASSERT (DirEnt->FileString != NULL);\r
256 gBS->CalculateCrc32 (DirEnt->FileString, StrSize (DirEnt->FileString), &HashValue.Crc);\r
257\r
258 if (BaseTagLen > HASH_BASE_TAG_LEN) {\r
259 BaseTagLen = HASH_BASE_TAG_LEN;\r
260 }\r
261\r
262 ShortNameChar = ShortName + BaseTagLen;\r
263 for (Index = 0; Index < HASH_VALUE_TAG_LEN; Index++) {\r
264 Segment = HashValue.Hex[Index].Segment;\r
265 if (Segment > 9) {\r
266 *ShortNameChar++ = (CHAR8)(Segment - 10 + 'A');\r
267 } else {\r
268 *ShortNameChar++ = (CHAR8)(Segment + '0');\r
269 }\r
270 }\r
271\r
272 *ShortNameChar++ = '~';\r
273 *ShortNameChar = '1';\r
274 }\r
275 }\r
276}\r
277\r
278STATIC\r
279UINT8\r
280FatCheckNameCase (\r
281 IN CHAR16 *Str,\r
282 IN UINT8 InCaseFlag\r
283 )\r
284/*++\r
285\r
286Routine Description:\r
287\r
288 Check the string is lower case or upper case\r
289 and it is used by fatname to dir entry count\r
290\r
291Arguments:\r
292\r
293 Str - The string which needs to be checked.\r
294 InCaseFlag - The input case flag which is returned when the string is lower case.\r
295\r
296Returns:\r
297\r
298 OutCaseFlag - The output case flag.\r
299\r
300--*/\r
301{\r
302 CHAR16 Buffer[FAT_MAIN_NAME_LEN + 1];\r
303 UINT8 OutCaseFlag;\r
304\r
305 ASSERT (StrSize (Str) <= sizeof (Buffer));\r
306 //\r
307 // Assume the case of input string is mixed\r
308 //\r
309 OutCaseFlag = FAT_CASE_MIXED;\r
310 //\r
311 // Lower case a copy of the string, if it matches the\r
312 // original then the string is lower case\r
313 //\r
314 StrCpy (Buffer, Str);\r
315 FatStrLwr (Buffer);\r
316 if (StrCmp (Str, Buffer) == 0) {\r
317 OutCaseFlag = InCaseFlag;\r
318 }\r
319 //\r
320 // Upper case a copy of the string, if it matches the\r
321 // original then the string is upper case\r
322 //\r
323 StrCpy (Buffer, Str);\r
324 FatStrUpr (Buffer);\r
325 if (StrCmp (Str, Buffer) == 0) {\r
326 OutCaseFlag = 0;\r
327 }\r
328\r
329 return OutCaseFlag;\r
330}\r
331\r
332VOID\r
333FatSetCaseFlag (\r
334 IN FAT_DIRENT *DirEnt\r
335 )\r
336/*++\r
337\r
338Routine Description:\r
339\r
340 Set the caseflag value for the directory entry.\r
341\r
342Arguments:\r
343\r
344 DirEnt - The logical directory entry whose caseflag value is to be set.\r
345\r
346Returns:\r
347\r
348 None.\r
349\r
350--*/\r
351{\r
352 CHAR16 LfnBuffer[FAT_MAIN_NAME_LEN + 1 + FAT_EXTEND_NAME_LEN + 1];\r
353 CHAR16 *TempCharPtr;\r
354 CHAR16 *ExtendName;\r
355 CHAR16 *FileNameCharPtr;\r
356 UINT8 CaseFlag;\r
357\r
358 ExtendName = NULL;\r
359 TempCharPtr = LfnBuffer;\r
360 FileNameCharPtr = DirEnt->FileString;\r
361 ASSERT (StrSize (DirEnt->FileString) <= sizeof (LfnBuffer));\r
362 while ((*TempCharPtr = *FileNameCharPtr) != 0) {\r
363 if (*TempCharPtr == L'.') {\r
364 ExtendName = TempCharPtr;\r
365 }\r
366\r
367 TempCharPtr++;\r
368 FileNameCharPtr++;\r
369 }\r
370\r
371 CaseFlag = 0;\r
372 if (ExtendName != NULL) {\r
373 *ExtendName = 0;\r
374 ExtendName++;\r
375 CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (ExtendName, FAT_CASE_EXT_LOWER));\r
376 }\r
377\r
378 CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (LfnBuffer, FAT_CASE_NAME_LOWER));\r
379 if ((CaseFlag & FAT_CASE_MIXED) == 0) {\r
380 //\r
381 // We just need one directory entry to store this file name entry\r
382 //\r
383 DirEnt->Entry.CaseFlag = CaseFlag;\r
384 } else {\r
385 //\r
386 // We need one extra directory entry to store the mixed case entry\r
387 //\r
388 DirEnt->Entry.CaseFlag = 0;\r
389 DirEnt->EntryCount++;\r
390 }\r
391}\r
392\r
393VOID\r
394FatGetFileNameViaCaseFlag (\r
395 IN FAT_DIRENT *DirEnt,\r
396 OUT CHAR16 *FileString\r
397 )\r
398/*++\r
399\r
400Routine Description:\r
401\r
402 Convert the 8.3 ASCII fat name to cased Unicode string according to case flag.\r
403\r
404Arguments:\r
405\r
406 DirEnt - The corresponding directory entry.\r
407 FileString - The output Unicode file name.\r
408\r
409Returns:\r
410\r
411 None.\r
412\r
413--*/\r
414{\r
415 UINT8 CaseFlag;\r
416 CHAR8 *File8Dot3Name;\r
417 CHAR16 TempExt[1 + FAT_EXTEND_NAME_LEN + 1];\r
418 //\r
419 // Store file extension like ".txt"\r
420 //\r
421 CaseFlag = DirEnt->Entry.CaseFlag;\r
422 File8Dot3Name = DirEnt->Entry.FileName;\r
423\r
424 FatNameToStr (File8Dot3Name, FAT_MAIN_NAME_LEN, CaseFlag & FAT_CASE_NAME_LOWER, FileString);\r
425 FatNameToStr (File8Dot3Name + FAT_MAIN_NAME_LEN, FAT_EXTEND_NAME_LEN, CaseFlag & FAT_CASE_EXT_LOWER, &TempExt[1]);\r
426 if (TempExt[1] != 0) {\r
427 TempExt[0] = L'.';\r
428 StrCat (FileString, TempExt);\r
429 }\r
430}\r
431\r
432UINT8\r
433FatCheckSum (\r
434 IN CHAR8 *ShortNameString\r
435 )\r
436/*++\r
437\r
438Routine Description:\r
439\r
440 Get the Check sum for a short name.\r
441\r
442Arguments:\r
443\r
444 ShortNameString - The short name for a file.\r
445\r
446Returns:\r
447\r
448 Sum - UINT8 checksum.\r
449\r
450--*/\r
451{\r
452 UINTN ShortNameLen;\r
453 UINT8 Sum;\r
454 Sum = 0;\r
455 for (ShortNameLen = FAT_NAME_LEN; ShortNameLen != 0; ShortNameLen--) {\r
456 Sum = (UINT8)(((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *ShortNameString++);\r
457 }\r
458\r
459 return Sum;\r
460}\r
461\r
462CHAR16 *\r
463FatGetNextNameComponent (\r
464 IN CHAR16 *Path,\r
465 OUT CHAR16 *Name\r
466 )\r
467/*++\r
468\r
469Routine Description:\r
470\r
471 Takes Path as input, returns the next name component\r
472 in Name, and returns the position after Name (e.g., the\r
473 start of the next name component)\r
474\r
475Arguments:\r
476\r
477 Path - The path of one file.\r
478 Name - The next name component in Path.\r
479\r
480Returns:\r
481\r
482 The position after Name in the Path\r
483\r
484--*/\r
485{\r
486 while (*Path != 0 && *Path != PATH_NAME_SEPARATOR) {\r
487 *Name++ = *Path++;\r
488 }\r
489 *Name = 0;\r
490 //\r
491 // Get off of trailing path name separator\r
492 //\r
493 while (*Path == PATH_NAME_SEPARATOR) {\r
494 Path++;\r
495 }\r
496\r
497 return Path;\r
498}\r
499\r
500BOOLEAN\r
501FatFileNameIsValid (\r
502 IN CHAR16 *InputFileName,\r
503 OUT CHAR16 *OutputFileName\r
504 )\r
505/*++\r
506\r
507Routine Description:\r
508\r
509 Check whether the IFileName is valid long file name. If the IFileName is a valid\r
510 long file name, then we trim the possible leading blanks and leading/trailing dots.\r
511 the trimmed filename is stored in OutputFileName\r
512\r
513Arguments:\r
514\r
515 InputFileName - The input file name.\r
516 OutputFileName - The output file name.\r
517\r
518\r
519Returns:\r
520\r
521 TRUE - The InputFileName is a valid long file name.\r
522 FALSE - The InputFileName is not a valid long file name.\r
523\r
524--*/\r
525{\r
526 CHAR16 *TempNamePointer;\r
527 CHAR16 TempChar;\r
528 //\r
529 // Trim Leading blanks\r
530 //\r
531 while (*InputFileName == L' ') {\r
532 InputFileName++;\r
533 }\r
534\r
535 TempNamePointer = OutputFileName;\r
536 while (*InputFileName != 0) {\r
537 *TempNamePointer++ = *InputFileName++;\r
538 }\r
539 //\r
540 // Trim Trailing blanks and dots\r
541 //\r
542 while (TempNamePointer > OutputFileName) {\r
543 TempChar = *(TempNamePointer - 1);\r
544 if (TempChar != L' ' && TempChar != L'.') {\r
545 break;\r
546 }\r
547\r
548 TempNamePointer--;\r
549 }\r
550\r
551 *TempNamePointer = 0;\r
552\r
553 //\r
554 // Per FAT Spec the file name should meet the following criteria:\r
555 // C1. Length (FileLongName) <= 255\r
556 // C2. Length (X:FileFullPath<NUL>) <= 260\r
557 // Here we check C1.\r
558 //\r
559 if (TempNamePointer - OutputFileName > EFI_FILE_STRING_LENGTH) {\r
560 return FALSE;\r
561 }\r
562 //\r
563 // See if there is any illegal characters within the name\r
564 //\r
565 do {\r
566 if (*OutputFileName < 0x20 ||\r
567 *OutputFileName == '\"' ||\r
568 *OutputFileName == '*' ||\r
569 *OutputFileName == '/' ||\r
570 *OutputFileName == ':' ||\r
571 *OutputFileName == '<' ||\r
572 *OutputFileName == '>' ||\r
573 *OutputFileName == '?' ||\r
574 *OutputFileName == '\\' ||\r
575 *OutputFileName == '|'\r
576 ) {\r
577 return FALSE;\r
578 }\r
579\r
580 OutputFileName++;\r
581 } while (*OutputFileName != 0);\r
582 return TRUE;\r
583}\r