2 Functions for manipulating file names.
4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
13 This function checks whether the input FileName is a valid 8.3 short name.
14 If the input FileName is a valid 8.3, the output is the 8.3 short name;
15 otherwise, the output is the base tag of 8.3 short name.
17 @param FileName - The input unicode filename.
18 @param File8Dot3Name - The output ascii 8.3 short name or base tag of 8.3 short name.
20 @retval TRUE - The input unicode filename is a valid 8.3 short name.
21 @retval FALSE - The input unicode filename is not a valid 8.3 short name.
27 OUT CHAR8
*File8Dot3Name
30 BOOLEAN PossibleShortName
;
37 PossibleShortName
= TRUE
;
39 SetMem (File8Dot3Name
, FAT_NAME_LEN
, ' ');
40 for (TempName
= FileName
; *TempName
!= '\0'; TempName
++) {
41 if (*TempName
== L
'.') {
42 SeparateDot
= TempName
;
46 if (SeparateDot
== NULL
) {
48 // Extended filename is not detected
50 MainNameLen
= TempName
- FileName
;
51 ExtendName
= TempName
;
55 // Extended filename is detected
57 MainNameLen
= SeparateDot
- FileName
;
58 ExtendName
= SeparateDot
+ 1;
59 ExtendNameLen
= TempName
- ExtendName
;
62 // We scan the filename for the second time
63 // to check if there exists any extra blanks and dots
65 while (--TempName
>= FileName
) {
66 if ((*TempName
== L
'.' || *TempName
== L
' ') && (TempName
!= SeparateDot
)) {
68 // There exist extra blanks and dots
70 PossibleShortName
= FALSE
;
74 if (MainNameLen
== 0) {
75 PossibleShortName
= FALSE
;
78 if (MainNameLen
> FAT_MAIN_NAME_LEN
) {
79 PossibleShortName
= FALSE
;
80 MainNameLen
= FAT_MAIN_NAME_LEN
;
83 if (ExtendNameLen
> FAT_EXTEND_NAME_LEN
) {
84 PossibleShortName
= FALSE
;
85 ExtendNameLen
= FAT_EXTEND_NAME_LEN
;
88 if (FatStrToFat (FileName
, MainNameLen
, File8Dot3Name
)) {
89 PossibleShortName
= FALSE
;
92 if (FatStrToFat (ExtendName
, ExtendNameLen
, File8Dot3Name
+ FAT_MAIN_NAME_LEN
)) {
93 PossibleShortName
= FALSE
;
96 return PossibleShortName
;
101 Trim the trailing blanks of fat name.
103 @param Name - The Char8 string needs to be trimmed.
104 @param Len - The length of the fat name.
106 The real length of the fat name after the trailing blanks are trimmed.
111 FatTrimAsciiTrailingBlanks (
116 while (Len
> 0 && Name
[Len
- 1] == ' ') {
125 Convert the ascii fat name to the unicode string and strip trailing spaces,
126 and if necessary, convert the unicode string to lower case.
128 @param FatName - The Char8 string needs to be converted.
129 @param Len - The length of the fat name.
130 @param LowerCase - Indicate whether to convert the string to lower case.
131 @param Str - The result of the conversion.
143 // First, trim the trailing blanks
145 Len
= FatTrimAsciiTrailingBlanks (FatName
, Len
);
147 // Convert fat string to unicode string
149 FatFatToStr (Len
, FatName
, Str
);
152 // If the name is to be lower cased, do it now
154 if (LowerCase
!= 0) {
161 This function generates 8Dot3 name from user specified name for a newly created file.
163 @param Parent - The parent directory.
164 @param DirEnt - The directory entry whose 8Dot3Name needs to be generated.
169 IN FAT_OFILE
*Parent
,
170 IN FAT_DIRENT
*DirEnt
174 CHAR8
*ShortNameChar
;
182 UINT8 Segment
: HASH_VALUE_TAG_LEN
;
183 } Hex
[HASH_VALUE_TAG_LEN
];
186 // Make sure the whole directory has been loaded
188 ASSERT (Parent
->ODir
->EndOfDir
);
189 ShortName
= DirEnt
->Entry
.FileName
;
192 // Trim trailing blanks of 8.3 name
194 BaseTagLen
= FatTrimAsciiTrailingBlanks (ShortName
, FAT_MAIN_NAME_LEN
);
195 if (BaseTagLen
> SPEC_BASE_TAG_LEN
) {
196 BaseTagLen
= SPEC_BASE_TAG_LEN
;
199 // We first use the algorithm described by spec.
201 ShortNameChar
= ShortName
+ BaseTagLen
;
202 *ShortNameChar
++ = '~';
203 *ShortNameChar
= '1';
205 while (*FatShortNameHashSearch (Parent
->ODir
, ShortName
) != NULL
) {
206 *ShortNameChar
= (CHAR8
)(*ShortNameChar
+ 1);
207 if (++Retry
== MAX_SPEC_RETRY
) {
209 // We use new algorithm to generate 8.3 name
211 ASSERT (DirEnt
->FileString
!= NULL
);
212 gBS
->CalculateCrc32 (DirEnt
->FileString
, StrSize (DirEnt
->FileString
), &HashValue
.Crc
);
214 if (BaseTagLen
> HASH_BASE_TAG_LEN
) {
215 BaseTagLen
= HASH_BASE_TAG_LEN
;
218 ShortNameChar
= ShortName
+ BaseTagLen
;
219 for (Index
= 0; Index
< HASH_VALUE_TAG_LEN
; Index
++) {
220 Segment
= HashValue
.Hex
[Index
].Segment
;
222 *ShortNameChar
++ = (CHAR8
)(Segment
- 10 + 'A');
224 *ShortNameChar
++ = (CHAR8
)(Segment
+ '0');
228 *ShortNameChar
++ = '~';
229 *ShortNameChar
= '1';
236 Check the string is lower case or upper case
237 and it is used by fatname to dir entry count
239 @param Str - The string which needs to be checked.
240 @param InCaseFlag - The input case flag which is returned when the string is lower case.
242 @retval OutCaseFlag - The output case flag.
252 CHAR16 Buffer
[FAT_MAIN_NAME_LEN
+ 1 + FAT_EXTEND_NAME_LEN
+ 1];
256 // Assume the case of input string is mixed
258 OutCaseFlag
= FAT_CASE_MIXED
;
260 // Lower case a copy of the string, if it matches the
261 // original then the string is lower case
263 StrCpyS (Buffer
, ARRAY_SIZE (Buffer
), Str
);
265 if (StrCmp (Str
, Buffer
) == 0) {
266 OutCaseFlag
= InCaseFlag
;
269 // Upper case a copy of the string, if it matches the
270 // original then the string is upper case
272 StrCpyS (Buffer
, ARRAY_SIZE (Buffer
), Str
);
274 if (StrCmp (Str
, Buffer
) == 0) {
283 Set the caseflag value for the directory entry.
285 @param DirEnt - The logical directory entry whose caseflag value is to be set.
290 IN FAT_DIRENT
*DirEnt
293 CHAR16 LfnBuffer
[FAT_MAIN_NAME_LEN
+ 1 + FAT_EXTEND_NAME_LEN
+ 1];
296 CHAR16
*FileNameCharPtr
;
300 TempCharPtr
= LfnBuffer
;
301 FileNameCharPtr
= DirEnt
->FileString
;
302 ASSERT (StrSize (DirEnt
->FileString
) <= sizeof (LfnBuffer
));
303 while ((*TempCharPtr
= *FileNameCharPtr
) != 0) {
304 if (*TempCharPtr
== L
'.') {
305 ExtendName
= TempCharPtr
;
313 if (ExtendName
!= NULL
) {
316 CaseFlag
= (UINT8
)(CaseFlag
| FatCheckNameCase (ExtendName
, FAT_CASE_EXT_LOWER
));
319 CaseFlag
= (UINT8
)(CaseFlag
| FatCheckNameCase (LfnBuffer
, FAT_CASE_NAME_LOWER
));
320 if ((CaseFlag
& FAT_CASE_MIXED
) == 0) {
322 // We just need one directory entry to store this file name entry
324 DirEnt
->Entry
.CaseFlag
= CaseFlag
;
327 // We need one extra directory entry to store the mixed case entry
329 DirEnt
->Entry
.CaseFlag
= 0;
330 DirEnt
->EntryCount
++;
336 Convert the 8.3 ASCII fat name to cased Unicode string according to case flag.
338 @param DirEnt - The corresponding directory entry.
339 @param FileString - The output Unicode file name.
340 @param FileStringMax The max length of FileString.
344 FatGetFileNameViaCaseFlag (
345 IN FAT_DIRENT
*DirEnt
,
346 IN OUT CHAR16
*FileString
,
347 IN UINTN FileStringMax
351 CHAR8
*File8Dot3Name
;
352 CHAR16 TempExt
[1 + FAT_EXTEND_NAME_LEN
+ 1];
354 // Store file extension like ".txt"
356 CaseFlag
= DirEnt
->Entry
.CaseFlag
;
357 File8Dot3Name
= DirEnt
->Entry
.FileName
;
359 FatNameToStr (File8Dot3Name
, FAT_MAIN_NAME_LEN
, CaseFlag
& FAT_CASE_NAME_LOWER
, FileString
);
360 FatNameToStr (File8Dot3Name
+ FAT_MAIN_NAME_LEN
, FAT_EXTEND_NAME_LEN
, CaseFlag
& FAT_CASE_EXT_LOWER
, &TempExt
[1]);
361 if (TempExt
[1] != 0) {
363 StrCatS (FileString
, FileStringMax
, TempExt
);
369 Get the Check sum for a short name.
371 @param ShortNameString - The short name for a file.
373 @retval Sum - UINT8 checksum.
378 IN CHAR8
*ShortNameString
384 for (ShortNameLen
= FAT_NAME_LEN
; ShortNameLen
!= 0; ShortNameLen
--) {
385 Sum
= (UINT8
)((((Sum
& 1) != 0) ? 0x80 : 0) + (Sum
>> 1) + *ShortNameString
++);
393 Takes Path as input, returns the next name component
394 in Name, and returns the position after Name (e.g., the
395 start of the next name component)
397 @param Path - The path of one file.
398 @param Name - The next name component in Path.
400 The position after Name in the Path
404 FatGetNextNameComponent (
409 while (*Path
!= 0 && *Path
!= PATH_NAME_SEPARATOR
) {
414 // Get off of trailing path name separator
416 while (*Path
== PATH_NAME_SEPARATOR
) {
425 Check whether the IFileName is valid long file name. If the IFileName is a valid
426 long file name, then we trim the possible leading blanks and leading/trailing dots.
427 the trimmed filename is stored in OutputFileName
429 @param InputFileName - The input file name.
430 @param OutputFileName - The output file name.
432 @retval TRUE - The InputFileName is a valid long file name.
433 @retval FALSE - The InputFileName is not a valid long file name.
438 IN CHAR16
*InputFileName
,
439 OUT CHAR16
*OutputFileName
442 CHAR16
*TempNamePointer
;
445 // Trim Leading blanks
447 while (*InputFileName
== L
' ') {
451 TempNamePointer
= OutputFileName
;
452 while (*InputFileName
!= 0) {
453 *TempNamePointer
++ = *InputFileName
++;
456 // Trim Trailing blanks and dots
458 while (TempNamePointer
> OutputFileName
) {
459 TempChar
= *(TempNamePointer
- 1);
460 if (TempChar
!= L
' ' && TempChar
!= L
'.') {
467 *TempNamePointer
= 0;
470 // Per FAT Spec the file name should meet the following criteria:
471 // C1. Length (FileLongName) <= 255
472 // C2. Length (X:FileFullPath<NUL>) <= 260
475 if (TempNamePointer
- OutputFileName
> EFI_FILE_STRING_LENGTH
) {
479 // See if there is any illegal characters within the name
482 if (*OutputFileName
< 0x20 ||
483 *OutputFileName
== '\"' ||
484 *OutputFileName
== '*' ||
485 *OutputFileName
== '/' ||
486 *OutputFileName
== ':' ||
487 *OutputFileName
== '<' ||
488 *OutputFileName
== '>' ||
489 *OutputFileName
== '?' ||
490 *OutputFileName
== '\\' ||
491 *OutputFileName
== '|'
497 } while (*OutputFileName
!= 0);