1 /* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS system libraries
3 * FILE: lib/rtl/dos8dot3.c
4 * PURPOSE: Short name (8.3 name) functions
5 * PROGRAMMER: Eric Kohl
8 /* INCLUDES ******************************************************************/
16 /* CONSTANTS *****************************************************************/
18 const PCHAR RtlpShortIllegals
= ";+=[],\"*\\<>/?:|";
21 /* FUNCTIONS *****************************************************************/
24 RtlpIsShortIllegal(CHAR Char
)
26 return strchr(RtlpShortIllegals
, Char
) ? TRUE
: FALSE
;
30 RtlpGetCheckSum(PUNICODE_STRING Name
)
36 Length
= Name
->Length
/ sizeof(WCHAR
);
40 Hash
= (Hash
+ (*c
<< 4) + (*c
>> 4)) * 11;
47 RtlpGetIndexLength(ULONG Index
)
55 return Length
? Length
: 1;
63 RtlGenerate8dot3Name(IN PUNICODE_STRING Name
,
64 IN BOOLEAN AllowExtendedCharacters
,
65 IN OUT PGENERATE_NAME_CONTEXT Context
,
66 OUT PUNICODE_STRING Name8dot3
)
82 StrLength
= Name
->Length
/ sizeof(WCHAR
);
83 DPRINT("StrLength: %lu\n", StrLength
);
85 /* Find last dot in Name */
87 for (i
= 0; i
< StrLength
; i
++)
89 if (Name
->Buffer
[i
] == L
'.')
95 DPRINT("DotPos: %lu\n", DotPos
);
97 /* Copy name (6 valid characters max) */
98 for (i
= 0, NameLength
= 0; NameLength
< 6 && i
< DotPos
; i
++)
101 RtlUpcaseUnicodeToOemN(&c
, sizeof(CHAR
), &Count
, &Name
->Buffer
[i
], sizeof(WCHAR
));
102 if (Count
!= 1 || c
== 0 || RtlpIsShortIllegal(c
))
104 NameBuffer
[NameLength
++] = L
'_';
106 else if (c
!= '.' && c
!= ' ')
108 NameBuffer
[NameLength
++] = (WCHAR
)c
;
112 DPRINT("NameBuffer: '%.08S'\n", NameBuffer
);
113 DPRINT("NameLength: %lu\n", NameLength
);
115 /* Copy extension (4 valid characters max) */
116 if (DotPos
< StrLength
)
118 for (i
= DotPos
, ExtLength
= 0; ExtLength
< 4 && i
< StrLength
; i
++)
121 RtlUpcaseUnicodeToOemN(&c
, sizeof(CHAR
), &Count
, &Name
->Buffer
[i
], sizeof(WCHAR
));
122 if (Count
!= 1 || c
== 0 || RtlpIsShortIllegal(c
))
124 ExtBuffer
[ExtLength
++] = L
'_';
128 ExtBuffer
[ExtLength
++] = c
;
136 DPRINT("ExtBuffer: '%.04S'\n", ExtBuffer
);
137 DPRINT("ExtLength: %lu\n", ExtLength
);
139 /* Determine next index */
140 IndexLength
= RtlpGetIndexLength(Context
->LastIndexValue
);
141 if (Context
->CheckSumInserted
)
143 CopyLength
= min(NameLength
, 8 - 4 - 1 - IndexLength
);
144 Checksum
= RtlpGetCheckSum(Name
);
148 CopyLength
= min(NameLength
, 8 - 1 - IndexLength
);
152 DPRINT("CopyLength: %lu\n", CopyLength
);
154 if ((Context
->NameLength
== CopyLength
) &&
155 (wcsncmp(Context
->NameBuffer
, NameBuffer
, CopyLength
) == 0) &&
156 (Context
->ExtensionLength
== ExtLength
) &&
157 (wcsncmp(Context
->ExtensionBuffer
, ExtBuffer
, ExtLength
) == 0) &&
158 (Checksum
== Context
->Checksum
) &&
159 (Context
->LastIndexValue
< 999))
161 Context
->LastIndexValue
++;
162 if (Context
->CheckSumInserted
== FALSE
&&
163 Context
->LastIndexValue
> 9)
165 Context
->CheckSumInserted
= TRUE
;
166 Context
->LastIndexValue
= 1;
167 Context
->Checksum
= RtlpGetCheckSum(Name
);
172 Context
->LastIndexValue
= 1;
173 Context
->CheckSumInserted
= FALSE
;
176 IndexLength
= RtlpGetIndexLength(Context
->LastIndexValue
);
178 DPRINT("CurrentIndex: %lu, IndexLength %lu\n", Context
->LastIndexValue
, IndexLength
);
180 if (Context
->CheckSumInserted
)
182 CopyLength
= min(NameLength
, 8 - 4 - 1 - IndexLength
);
186 CopyLength
= min(NameLength
, 8 - 1 - IndexLength
);
189 /* Build the short name */
190 memcpy(Name8dot3
->Buffer
, NameBuffer
, CopyLength
* sizeof(WCHAR
));
192 if (Context
->CheckSumInserted
)
195 Checksum
= Context
->Checksum
;
196 for (i
= 0; i
< 4; i
++)
198 Name8dot3
->Buffer
[j
--] = (Checksum
% 16) > 9 ? (Checksum
% 16) + L
'A' - 10 : (Checksum
% 16) + L
'0';
203 Name8dot3
->Buffer
[j
++] = L
'~';
204 j
+= IndexLength
- 1;
205 CurrentIndex
= Context
->LastIndexValue
;
206 for (i
= 0; i
< IndexLength
; i
++)
208 Name8dot3
->Buffer
[j
--] = (CurrentIndex
% 10) + L
'0';
211 j
+= IndexLength
+ 1;
213 memcpy(Name8dot3
->Buffer
+ j
, ExtBuffer
, ExtLength
* sizeof(WCHAR
));
214 Name8dot3
->Length
= (USHORT
)(j
+ ExtLength
) * sizeof(WCHAR
);
216 DPRINT("Name8dot3: '%wZ'\n", Name8dot3
);
219 Context
->NameLength
= (UCHAR
)CopyLength
;
220 Context
->ExtensionLength
= ExtLength
;
221 memcpy(Context
->NameBuffer
, NameBuffer
, CopyLength
* sizeof(WCHAR
));
222 memcpy(Context
->ExtensionBuffer
, ExtBuffer
, ExtLength
* sizeof(WCHAR
));
231 RtlIsNameLegalDOS8Dot3(IN PCUNICODE_STRING UnicodeName
,
232 IN OUT POEM_STRING AnsiName OPTIONAL
,
233 IN OUT PBOOLEAN SpacesFound OPTIONAL
)
235 static const char Illegal
[] = "*?<>|\"+=,;[]:/\\\345";
239 OEM_STRING OemString
;
240 BOOLEAN GotSpace
= FALSE
;
243 if (SpacesFound
) *SpacesFound
= FALSE
;
247 OemString
.Length
= sizeof(Buffer
);
248 OemString
.MaximumLength
= sizeof(Buffer
);
249 OemString
.Buffer
= Buffer
;
250 AnsiName
= &OemString
;
253 Status
= RtlUpcaseUnicodeStringToCountedOemString(AnsiName
, UnicodeName
, FALSE
);
254 if (!NT_SUCCESS(Status
))
257 if ((AnsiName
->Length
> 12) || (AnsiName
->Buffer
== NULL
)) return FALSE
;
259 /* a starting . is invalid, except for . and .. */
260 if (AnsiName
->Buffer
[0] == '.')
262 if (AnsiName
->Length
!= 1 && (AnsiName
->Length
!= 2 || AnsiName
->Buffer
[1] != '.')) return FALSE
;
266 for (i
= 0; i
< AnsiName
->Length
; i
++)
268 switch (AnsiName
->Buffer
[i
])
271 /* leading/trailing spaces not allowed */
272 if (!i
|| i
== AnsiName
->Length
-1 || AnsiName
->Buffer
[i
+1] == '.') return FALSE
;
276 if (Dot
!= -1) return FALSE
;
280 if (strchr(Illegal
, AnsiName
->Buffer
[i
])) return FALSE
;
284 /* check file part is shorter than 8, extension shorter than 3
285 * dot cannot be last in string
289 if (AnsiName
->Length
> 8) return FALSE
;
293 if (Dot
> 8 || (AnsiName
->Length
- Dot
> 4) || Dot
== AnsiName
->Length
- 1) return FALSE
;
295 if (SpacesFound
) *SpacesFound
= GotSpace
;