2 Functions for manipulating file names.
4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 This function checks whether the input FileName is a valid 8.3 short name.
20 If the input FileName is a valid 8.3, the output is the 8.3 short name;
21 otherwise, the output is the base tag of 8.3 short name.
23 @param FileName - The input unicode filename.
24 @param File8Dot3Name - The output ascii 8.3 short name or base tag of 8.3 short name.
26 @retval TRUE - The input unicode filename is a valid 8.3 short name.
27 @retval FALSE - The input unicode filename is not a valid 8.3 short name.
33 OUT CHAR8
*File8Dot3Name
36 BOOLEAN PossibleShortName
;
43 PossibleShortName
= TRUE
;
45 SetMem (File8Dot3Name
, FAT_NAME_LEN
, ' ');
46 for (TempName
= FileName
; *TempName
!= '\0'; TempName
++) {
47 if (*TempName
== L
'.') {
48 SeparateDot
= TempName
;
52 if (SeparateDot
== NULL
) {
54 // Extended filename is not detected
56 MainNameLen
= TempName
- FileName
;
57 ExtendName
= TempName
;
61 // Extended filename is detected
63 MainNameLen
= SeparateDot
- FileName
;
64 ExtendName
= SeparateDot
+ 1;
65 ExtendNameLen
= TempName
- ExtendName
;
68 // We scan the filename for the second time
69 // to check if there exists any extra blanks and dots
71 while (--TempName
>= FileName
) {
72 if ((*TempName
== L
'.' || *TempName
== L
' ') && (TempName
!= SeparateDot
)) {
74 // There exist extra blanks and dots
76 PossibleShortName
= FALSE
;
80 if (MainNameLen
== 0) {
81 PossibleShortName
= FALSE
;
84 if (MainNameLen
> FAT_MAIN_NAME_LEN
) {
85 PossibleShortName
= FALSE
;
86 MainNameLen
= FAT_MAIN_NAME_LEN
;
89 if (ExtendNameLen
> FAT_EXTEND_NAME_LEN
) {
90 PossibleShortName
= FALSE
;
91 ExtendNameLen
= FAT_EXTEND_NAME_LEN
;
94 if (FatStrToFat (FileName
, MainNameLen
, File8Dot3Name
)) {
95 PossibleShortName
= FALSE
;
98 if (FatStrToFat (ExtendName
, ExtendNameLen
, File8Dot3Name
+ FAT_MAIN_NAME_LEN
)) {
99 PossibleShortName
= FALSE
;
102 return PossibleShortName
;
107 Trim the trailing blanks of fat name.
109 @param Name - The Char8 string needs to be trimed.
110 @param Len - The length of the fat name.
112 The real length of the fat name after the trailing blanks are trimmed.
117 FatTrimAsciiTrailingBlanks (
122 while (Len
> 0 && Name
[Len
- 1] == ' ') {
131 Convert the ascii fat name to the unicode string and strip trailing spaces,
132 and if necessary, convert the unicode string to lower case.
134 @param FatName - The Char8 string needs to be converted.
135 @param Len - The length of the fat name.
136 @param LowerCase - Indicate whether to convert the string to lower case.
137 @param Str - The result of the convertion.
149 // First, trim the trailing blanks
151 Len
= FatTrimAsciiTrailingBlanks (FatName
, Len
);
153 // Convert fat string to unicode string
155 FatFatToStr (Len
, FatName
, Str
);
158 // If the name is to be lower cased, do it now
160 if (LowerCase
!= 0) {
167 This function generates 8Dot3 name from user specified name for a newly created file.
169 @param Parent - The parent directory.
170 @param DirEnt - The directory entry whose 8Dot3Name needs to be generated.
175 IN FAT_OFILE
*Parent
,
176 IN FAT_DIRENT
*DirEnt
180 CHAR8
*ShortNameChar
;
188 UINT8 Segment
: HASH_VALUE_TAG_LEN
;
189 } Hex
[HASH_VALUE_TAG_LEN
];
192 // Make sure the whole directory has been loaded
194 ASSERT (Parent
->ODir
->EndOfDir
);
195 ShortName
= DirEnt
->Entry
.FileName
;
198 // Trim trailing blanks of 8.3 name
200 BaseTagLen
= FatTrimAsciiTrailingBlanks (ShortName
, FAT_MAIN_NAME_LEN
);
201 if (BaseTagLen
> SPEC_BASE_TAG_LEN
) {
202 BaseTagLen
= SPEC_BASE_TAG_LEN
;
205 // We first use the algorithm described by spec.
207 ShortNameChar
= ShortName
+ BaseTagLen
;
208 *ShortNameChar
++ = '~';
209 *ShortNameChar
= '1';
211 while (*FatShortNameHashSearch (Parent
->ODir
, ShortName
) != NULL
) {
212 *ShortNameChar
= (CHAR8
)(*ShortNameChar
+ 1);
213 if (++Retry
== MAX_SPEC_RETRY
) {
215 // We use new algorithm to generate 8.3 name
217 ASSERT (DirEnt
->FileString
!= NULL
);
218 gBS
->CalculateCrc32 (DirEnt
->FileString
, StrSize (DirEnt
->FileString
), &HashValue
.Crc
);
220 if (BaseTagLen
> HASH_BASE_TAG_LEN
) {
221 BaseTagLen
= HASH_BASE_TAG_LEN
;
224 ShortNameChar
= ShortName
+ BaseTagLen
;
225 for (Index
= 0; Index
< HASH_VALUE_TAG_LEN
; Index
++) {
226 Segment
= HashValue
.Hex
[Index
].Segment
;
228 *ShortNameChar
++ = (CHAR8
)(Segment
- 10 + 'A');
230 *ShortNameChar
++ = (CHAR8
)(Segment
+ '0');
234 *ShortNameChar
++ = '~';
235 *ShortNameChar
= '1';
242 Check the string is lower case or upper case
243 and it is used by fatname to dir entry count
245 @param Str - The string which needs to be checked.
246 @param InCaseFlag - The input case flag which is returned when the string is lower case.
248 @retval OutCaseFlag - The output case flag.
258 CHAR16 Buffer
[FAT_MAIN_NAME_LEN
+ 1 + FAT_EXTEND_NAME_LEN
+ 1];
262 // Assume the case of input string is mixed
264 OutCaseFlag
= FAT_CASE_MIXED
;
266 // Lower case a copy of the string, if it matches the
267 // original then the string is lower case
269 StrCpyS (Buffer
, ARRAY_SIZE (Buffer
), Str
);
271 if (StrCmp (Str
, Buffer
) == 0) {
272 OutCaseFlag
= InCaseFlag
;
275 // Upper case a copy of the string, if it matches the
276 // original then the string is upper case
278 StrCpyS (Buffer
, ARRAY_SIZE (Buffer
), Str
);
280 if (StrCmp (Str
, Buffer
) == 0) {
289 Set the caseflag value for the directory entry.
291 @param DirEnt - The logical directory entry whose caseflag value is to be set.
296 IN FAT_DIRENT
*DirEnt
299 CHAR16 LfnBuffer
[FAT_MAIN_NAME_LEN
+ 1 + FAT_EXTEND_NAME_LEN
+ 1];
302 CHAR16
*FileNameCharPtr
;
306 TempCharPtr
= LfnBuffer
;
307 FileNameCharPtr
= DirEnt
->FileString
;
308 ASSERT (StrSize (DirEnt
->FileString
) <= sizeof (LfnBuffer
));
309 while ((*TempCharPtr
= *FileNameCharPtr
) != 0) {
310 if (*TempCharPtr
== L
'.') {
311 ExtendName
= TempCharPtr
;
319 if (ExtendName
!= NULL
) {
322 CaseFlag
= (UINT8
)(CaseFlag
| FatCheckNameCase (ExtendName
, FAT_CASE_EXT_LOWER
));
325 CaseFlag
= (UINT8
)(CaseFlag
| FatCheckNameCase (LfnBuffer
, FAT_CASE_NAME_LOWER
));
326 if ((CaseFlag
& FAT_CASE_MIXED
) == 0) {
328 // We just need one directory entry to store this file name entry
330 DirEnt
->Entry
.CaseFlag
= CaseFlag
;
333 // We need one extra directory entry to store the mixed case entry
335 DirEnt
->Entry
.CaseFlag
= 0;
336 DirEnt
->EntryCount
++;
342 Convert the 8.3 ASCII fat name to cased Unicode string according to case flag.
344 @param DirEnt - The corresponding directory entry.
345 @param FileString - The output Unicode file name.
346 @param FileStringMax The max length of FileString.
350 FatGetFileNameViaCaseFlag (
351 IN FAT_DIRENT
*DirEnt
,
352 IN OUT CHAR16
*FileString
,
353 IN UINTN FileStringMax
357 CHAR8
*File8Dot3Name
;
358 CHAR16 TempExt
[1 + FAT_EXTEND_NAME_LEN
+ 1];
360 // Store file extension like ".txt"
362 CaseFlag
= DirEnt
->Entry
.CaseFlag
;
363 File8Dot3Name
= DirEnt
->Entry
.FileName
;
365 FatNameToStr (File8Dot3Name
, FAT_MAIN_NAME_LEN
, CaseFlag
& FAT_CASE_NAME_LOWER
, FileString
);
366 FatNameToStr (File8Dot3Name
+ FAT_MAIN_NAME_LEN
, FAT_EXTEND_NAME_LEN
, CaseFlag
& FAT_CASE_EXT_LOWER
, &TempExt
[1]);
367 if (TempExt
[1] != 0) {
369 StrCatS (FileString
, FileStringMax
, TempExt
);
375 Get the Check sum for a short name.
377 @param ShortNameString - The short name for a file.
379 @retval Sum - UINT8 checksum.
384 IN CHAR8
*ShortNameString
390 for (ShortNameLen
= FAT_NAME_LEN
; ShortNameLen
!= 0; ShortNameLen
--) {
391 Sum
= (UINT8
)((((Sum
& 1) != 0) ? 0x80 : 0) + (Sum
>> 1) + *ShortNameString
++);
399 Takes Path as input, returns the next name component
400 in Name, and returns the position after Name (e.g., the
401 start of the next name component)
403 @param Path - The path of one file.
404 @param Name - The next name component in Path.
406 The position after Name in the Path
410 FatGetNextNameComponent (
415 while (*Path
!= 0 && *Path
!= PATH_NAME_SEPARATOR
) {
420 // Get off of trailing path name separator
422 while (*Path
== PATH_NAME_SEPARATOR
) {
431 Check whether the IFileName is valid long file name. If the IFileName is a valid
432 long file name, then we trim the possible leading blanks and leading/trailing dots.
433 the trimmed filename is stored in OutputFileName
435 @param InputFileName - The input file name.
436 @param OutputFileName - The output file name.
438 @retval TRUE - The InputFileName is a valid long file name.
439 @retval FALSE - The InputFileName is not a valid long file name.
444 IN CHAR16
*InputFileName
,
445 OUT CHAR16
*OutputFileName
448 CHAR16
*TempNamePointer
;
451 // Trim Leading blanks
453 while (*InputFileName
== L
' ') {
457 TempNamePointer
= OutputFileName
;
458 while (*InputFileName
!= 0) {
459 *TempNamePointer
++ = *InputFileName
++;
462 // Trim Trailing blanks and dots
464 while (TempNamePointer
> OutputFileName
) {
465 TempChar
= *(TempNamePointer
- 1);
466 if (TempChar
!= L
' ' && TempChar
!= L
'.') {
473 *TempNamePointer
= 0;
476 // Per FAT Spec the file name should meet the following criteria:
477 // C1. Length (FileLongName) <= 255
478 // C2. Length (X:FileFullPath<NUL>) <= 260
481 if (TempNamePointer
- OutputFileName
> EFI_FILE_STRING_LENGTH
) {
485 // See if there is any illegal characters within the name
488 if (*OutputFileName
< 0x20 ||
489 *OutputFileName
== '\"' ||
490 *OutputFileName
== '*' ||
491 *OutputFileName
== '/' ||
492 *OutputFileName
== ':' ||
493 *OutputFileName
== '<' ||
494 *OutputFileName
== '>' ||
495 *OutputFileName
== '?' ||
496 *OutputFileName
== '\\' ||
497 *OutputFileName
== '|'
503 } while (*OutputFileName
!= 0);