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 ******************************************************************/
17 /* CONSTANTS *****************************************************************/
19 const PCHAR RtlpShortIllegals
= ";+=[],\"*\\<>/?:|";
22 /* FUNCTIONS *****************************************************************/
25 RtlpIsShortIllegal(CHAR Char
)
27 return strchr(RtlpShortIllegals
, Char
) ? TRUE
: FALSE
;
31 RtlpGetCheckSum(PUNICODE_STRING Name
)
37 Length
= Name
->Length
/ sizeof(WCHAR
);
41 Hash
= (Hash
+ (*c
<< 4) + (*c
>> 4)) * 11;
48 RtlpGetIndexLength(ULONG Index
)
56 return Length
? Length
: 1;
64 RtlGenerate8dot3Name(IN PUNICODE_STRING Name
,
65 IN BOOLEAN AllowExtendedCharacters
,
66 IN OUT PGENERATE_NAME_CONTEXT Context
,
67 OUT PUNICODE_STRING Name8dot3
)
83 StrLength
= Name
->Length
/ sizeof(WCHAR
);
84 DPRINT("StrLength: %lu\n", StrLength
);
86 /* Find last dot in Name */
88 for (i
= 0; i
< StrLength
; i
++)
90 if (Name
->Buffer
[i
] == L
'.')
96 DPRINT("DotPos: %lu\n", DotPos
);
98 /* Copy name (6 valid characters max) */
99 for (i
= 0, NameLength
= 0; NameLength
< 6 && i
< DotPos
; i
++)
102 RtlUpcaseUnicodeToOemN(&c
, sizeof(CHAR
), &Count
, &Name
->Buffer
[i
], sizeof(WCHAR
));
103 if (Count
!= 1 || c
== 0 || RtlpIsShortIllegal(c
))
105 NameBuffer
[NameLength
++] = L
'_';
107 else if (c
!= '.' && c
!= ' ')
109 NameBuffer
[NameLength
++] = (WCHAR
)c
;
113 DPRINT("NameBuffer: '%.08S'\n", NameBuffer
);
114 DPRINT("NameLength: %lu\n", NameLength
);
116 /* Copy extension (4 valid characters max) */
117 if (DotPos
< StrLength
)
119 for (i
= DotPos
, ExtLength
= 0; ExtLength
< 4 && i
< StrLength
; i
++)
122 RtlUpcaseUnicodeToOemN(&c
, sizeof(CHAR
), &Count
, &Name
->Buffer
[i
], sizeof(WCHAR
));
123 if (Count
!= 1 || c
== 0 || RtlpIsShortIllegal(c
))
125 ExtBuffer
[ExtLength
++] = L
'_';
129 ExtBuffer
[ExtLength
++] = c
;
137 DPRINT("ExtBuffer: '%.04S'\n", ExtBuffer
);
138 DPRINT("ExtLength: %lu\n", ExtLength
);
140 /* Determine next index */
141 IndexLength
= RtlpGetIndexLength(Context
->LastIndexValue
);
142 if (Context
->CheckSumInserted
)
144 CopyLength
= min(NameLength
, 8 - 4 - 1 - IndexLength
);
145 Checksum
= RtlpGetCheckSum(Name
);
149 CopyLength
= min(NameLength
, 8 - 1 - IndexLength
);
153 DPRINT("CopyLength: %lu\n", CopyLength
);
155 if ((Context
->NameLength
== CopyLength
) &&
156 (wcsncmp(Context
->NameBuffer
, NameBuffer
, CopyLength
) == 0) &&
157 (Context
->ExtensionLength
== ExtLength
) &&
158 (wcsncmp(Context
->ExtensionBuffer
, ExtBuffer
, ExtLength
) == 0) &&
159 (Checksum
== Context
->Checksum
) &&
160 (Context
->LastIndexValue
< 999))
162 Context
->LastIndexValue
++;
163 if (Context
->CheckSumInserted
== FALSE
&&
164 Context
->LastIndexValue
> 9)
166 Context
->CheckSumInserted
= TRUE
;
167 Context
->LastIndexValue
= 1;
168 Context
->Checksum
= RtlpGetCheckSum(Name
);
173 Context
->LastIndexValue
= 1;
174 Context
->CheckSumInserted
= FALSE
;
177 IndexLength
= RtlpGetIndexLength(Context
->LastIndexValue
);
179 DPRINT("CurrentIndex: %lu, IndexLength %lu\n", Context
->LastIndexValue
, IndexLength
);
181 if (Context
->CheckSumInserted
)
183 CopyLength
= min(NameLength
, 8 - 4 - 1 - IndexLength
);
187 CopyLength
= min(NameLength
, 8 - 1 - IndexLength
);
190 /* Build the short name */
191 memcpy(Name8dot3
->Buffer
, NameBuffer
, CopyLength
* sizeof(WCHAR
));
193 if (Context
->CheckSumInserted
)
196 Checksum
= Context
->Checksum
;
197 for (i
= 0; i
< 4; i
++)
199 Name8dot3
->Buffer
[j
--] = (Checksum
% 16) > 9 ? (Checksum
% 16) + L
'A' - 10 : (Checksum
% 16) + L
'0';
204 Name8dot3
->Buffer
[j
++] = L
'~';
205 j
+= IndexLength
- 1;
206 CurrentIndex
= Context
->LastIndexValue
;
207 for (i
= 0; i
< IndexLength
; i
++)
209 Name8dot3
->Buffer
[j
--] = (CurrentIndex
% 10) + L
'0';
212 j
+= IndexLength
+ 1;
214 memcpy(Name8dot3
->Buffer
+ j
, ExtBuffer
, ExtLength
* sizeof(WCHAR
));
215 Name8dot3
->Length
= (USHORT
)(j
+ ExtLength
) * sizeof(WCHAR
);
217 DPRINT("Name8dot3: '%wZ'\n", Name8dot3
);
220 Context
->NameLength
= (UCHAR
)CopyLength
;
221 Context
->ExtensionLength
= ExtLength
;
222 memcpy(Context
->NameBuffer
, NameBuffer
, CopyLength
* sizeof(WCHAR
));
223 memcpy(Context
->ExtensionBuffer
, ExtBuffer
, ExtLength
* sizeof(WCHAR
));
229 * Note: the function does not conform to the annotations.
230 * SpacesFound is not always set!
232 _IRQL_requires_max_(PASSIVE_LEVEL
)
233 _Must_inspect_result_
237 RtlIsNameLegalDOS8Dot3 (
238 _In_ PCUNICODE_STRING Name
,
239 _Inout_opt_ POEM_STRING OemName
,
240 _Out_opt_ PBOOLEAN NameContainsSpaces
)
242 static const char Illegal
[] = "*?<>|\"+=,;[]:/\\\345";
246 OEM_STRING OemString
;
247 BOOLEAN GotSpace
= FALSE
;
252 OemString
.Length
= sizeof(Buffer
);
253 OemString
.MaximumLength
= sizeof(Buffer
);
254 OemString
.Buffer
= Buffer
;
255 OemName
= &OemString
;
258 Status
= RtlUpcaseUnicodeStringToCountedOemString(OemName
, Name
, FALSE
);
259 if (!NT_SUCCESS(Status
))
262 if ((OemName
->Length
> 12) || (OemName
->Buffer
== NULL
)) return FALSE
;
264 /* a starting . is invalid, except for . and .. */
265 if (OemName
->Buffer
[0] == '.')
267 if (OemName
->Length
!= 1 && (OemName
->Length
!= 2 || OemName
->Buffer
[1] != '.')) return FALSE
;
268 if (NameContainsSpaces
) *NameContainsSpaces
= FALSE
;
272 for (i
= 0; i
< OemName
->Length
; i
++)
274 switch (OemName
->Buffer
[i
])
277 /* leading/trailing spaces not allowed */
278 if (!i
|| i
== OemName
->Length
-1 || OemName
->Buffer
[i
+1] == '.') return FALSE
;
282 if (Dot
!= -1) return FALSE
;
286 if (strchr(Illegal
, OemName
->Buffer
[i
])) return FALSE
;
290 /* check file part is shorter than 8, extension shorter than 3
291 * dot cannot be last in string
295 if (OemName
->Length
> 8) return FALSE
;
299 if (Dot
> 8 || (OemName
->Length
- Dot
> 4) || Dot
== OemName
->Length
- 1) return FALSE
;
301 if (NameContainsSpaces
) *NameContainsSpaces
= GotSpace
;