2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/rtl/dos8dot3.c
5 * PURPOSE: Short name (8.3 name) functions
6 * PROGRAMMER: Eric Kohl
9 /* INCLUDES ******************************************************************/
16 extern PUSHORT NlsUnicodeToMbOemTable
;
18 /* CONSTANTS *****************************************************************/
20 const ULONG RtlpShortIllegals
[] = { 0xFFFFFFFF, 0xFC009C04, 0x38000000, 0x10000000 };
22 /* FUNCTIONS *****************************************************************/
26 RtlIsValidOemCharacter(IN PWCHAR Char
);
29 RtlpIsShortIllegal(const WCHAR Char
)
31 return (Char
< 128 && (RtlpShortIllegals
[Char
/ 32] & (1 << (Char
% 32))));
35 RtlpGetCheckSum(PUNICODE_STRING Name
)
45 if (Name
->Length
== sizeof(WCHAR
))
46 return Name
->Buffer
[0];
48 CurrentChar
= Name
->Buffer
;
49 Hash
= (*CurrentChar
<< 8) + *(CurrentChar
+ 1);
51 if (Name
->Length
== 2 * sizeof(WCHAR
))
60 Hash
= (Hash
<< 7) + *CurrentChar
;
61 Hash
= (Saved
>> 1) + (Hash
<< 8);
63 if (Length
+ 1 < Name
->Length
/ sizeof(WCHAR
))
65 Hash
+= *(CurrentChar
+ 1);
71 while (Length
< Name
->Length
/ sizeof(WCHAR
));
81 RtlGenerate8dot3Name(IN PUNICODE_STRING Name
,
82 IN BOOLEAN AllowExtendedCharacters
,
83 IN OUT PGENERATE_NAME_CONTEXT Context
,
84 OUT PUNICODE_STRING Name8dot3
)
86 ULONG Length
= Name
->Length
/ sizeof(WCHAR
);
94 if (!Context
->NameLength
)
98 /* Find last dot in Name */
99 for (Index
= 0; Index
< Length
; Index
++)
101 if (Name
->Buffer
[Index
] == L
'.')
105 /* Copy name (6 valid characters max) */
106 for (Index
= 0; Index
< DotPos
&& Context
->NameLength
< 6; Index
++)
108 Char
= Name
->Buffer
[Index
];
110 if ((Char
> L
' ') && (Char
!= L
'.') &&
111 ((Char
< 127) || (AllowExtendedCharacters
&& RtlIsValidOemCharacter(&Char
))))
113 if (RtlpIsShortIllegal(Char
))
115 else if (Char
>= L
'a' && Char
<= L
'z')
116 Char
= RtlpUpcaseUnicodeChar(Char
);
118 Context
->NameBuffer
[Context
->NameLength
] = Char
;
119 ++Context
->NameLength
;
123 /* Copy extension (4 valid characters max) */
124 Context
->ExtensionLength
= 0;
127 Context
->ExtensionBuffer
[0] = L
'.';
128 Context
->ExtensionLength
= 1;
130 while (DotPos
< Length
&& Context
->ExtensionLength
< 4)
132 Char
= Name
->Buffer
[DotPos
];
134 if ((Char
> L
' ') && (Char
!= L
'.') &&
135 ((Char
< 127) || (AllowExtendedCharacters
&& RtlIsValidOemCharacter(&Char
))))
137 if (RtlpIsShortIllegal(Char
))
139 else if (Char
>= L
'a' && Char
<= L
'z')
140 Char
= RtlpUpcaseUnicodeChar(Char
);
142 Context
->ExtensionBuffer
[Context
->ExtensionLength
++] = Char
;
149 if (Char
!= UNICODE_NULL
)
150 Context
->ExtensionBuffer
[Context
->ExtensionLength
- 1] = L
'~';
153 if (Context
->NameLength
<= 2)
155 Checksum
= Context
->Checksum
= RtlpGetCheckSum(Name
);
157 for (Index
= 0; Index
< 4; Index
++)
159 Context
->NameBuffer
[Context
->NameLength
+ Index
] =
160 (Checksum
& 0xF) > 9 ? (Checksum
& 0xF) + L
'A' - 10 : (Checksum
& 0xF) + L
'0';
164 Context
->CheckSumInserted
= TRUE
;
165 Context
->NameLength
+= 4;
169 ++Context
->LastIndexValue
;
171 if (Context
->LastIndexValue
> 4 && !Context
->CheckSumInserted
)
173 Checksum
= Context
->Checksum
= RtlpGetCheckSum(Name
);
175 for (Index
= 2; Index
< 6; Index
++)
177 Context
->NameBuffer
[Index
] =
178 (Checksum
& 0xF) > 9 ? (Checksum
& 0xF) + L
'A' - 10 : (Checksum
& 0xF) + L
'0';
182 Context
->CheckSumInserted
= TRUE
;
183 Context
->NameLength
= 6;
184 Context
->LastIndexValue
= 1;
187 /* Calculate index length and index buffer */
188 Index
= Context
->LastIndexValue
;
189 for (IndexLength
= 1; IndexLength
<= 7 && Index
> 0; IndexLength
++)
191 IndexBuffer
[8 - IndexLength
] = L
'0' + (Index
% 10);
195 IndexBuffer
[8 - IndexLength
] = L
'~';
197 /* Reset name length */
198 Name8dot3
->Length
= 0;
200 /* If name present */
201 if (Context
->NameLength
)
203 /* Copy name buffer */
204 Length
= Context
->NameLength
* sizeof(WCHAR
);
205 RtlCopyMemory(Name8dot3
->Buffer
, Context
->NameBuffer
, Length
);
206 Name8dot3
->Length
= Length
;
209 /* Copy index buffer */
210 Length
= IndexLength
* sizeof(WCHAR
);
211 RtlCopyMemory(Name8dot3
->Buffer
+ (Name8dot3
->Length
/ sizeof(WCHAR
)),
212 IndexBuffer
+ (8 - IndexLength
),
214 Name8dot3
->Length
+= Length
;
216 /* If extension present */
217 if (Context
->ExtensionLength
)
219 /* Copy extension buffer */
220 Length
= Context
->ExtensionLength
* sizeof(WCHAR
);
221 RtlCopyMemory(Name8dot3
->Buffer
+ (Name8dot3
->Length
/ sizeof(WCHAR
)),
222 Context
->ExtensionBuffer
,
224 Name8dot3
->Length
+= Length
;
231 * Note: the function does not conform to the annotations.
232 * SpacesFound is not always set!
234 _IRQL_requires_max_(PASSIVE_LEVEL
)
235 _Must_inspect_result_
239 RtlIsNameLegalDOS8Dot3(IN PCUNICODE_STRING Name
,
240 IN OUT POEM_STRING OemName
,
241 OUT PBOOLEAN NameContainsSpaces OPTIONAL
)
243 static const char Illegal
[] = "*?<>|\"+=,;[]:/\\\345";
247 OEM_STRING OemString
;
248 BOOLEAN GotSpace
= FALSE
;
253 OemString
.Length
= sizeof(Buffer
);
254 OemString
.MaximumLength
= sizeof(Buffer
);
255 OemString
.Buffer
= Buffer
;
256 OemName
= &OemString
;
259 Status
= RtlUpcaseUnicodeStringToCountedOemString(OemName
, Name
, FALSE
);
260 if (!NT_SUCCESS(Status
))
263 if ((OemName
->Length
> 12) || (OemName
->Buffer
== NULL
)) return FALSE
;
265 /* a starting . is invalid, except for . and .. */
266 if (OemName
->Buffer
[0] == '.')
268 if (OemName
->Length
!= 1 && (OemName
->Length
!= 2 || OemName
->Buffer
[1] != '.')) return FALSE
;
269 if (NameContainsSpaces
) *NameContainsSpaces
= FALSE
;
274 for (i
= 0; i
< OemName
->Length
; i
++)
276 switch (OemName
->Buffer
[i
])
279 /* leading/trailing spaces not allowed */
280 if (!i
|| i
== OemName
->Length
-1 || OemName
->Buffer
[i
+1] == '.') return FALSE
;
285 if (Dot
!= -1) return FALSE
;
290 if (strchr(Illegal
, OemName
->Buffer
[i
])) return FALSE
;
294 /* check file part is shorter than 8, extension shorter than 3
295 * dot cannot be last in string
299 if (OemName
->Length
> 8) return FALSE
;
303 if (Dot
> 8 || (OemName
->Length
- Dot
> 4) || Dot
== OemName
->Length
- 1) return FALSE
;
306 if (NameContainsSpaces
) *NameContainsSpaces
= GotSpace
;