896b30d0070fb83f1d82e6ab159bf2c3e3fe0529
[reactos.git] / reactos / lib / rtl / dos8dot3.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: lib/rtl/dos8dot3.c
24 * PURPOSE: Short name (8.3 name) functions
25 * PROGRAMMER: Eric Kohl
26 */
27
28 /* INCLUDES ******************************************************************/
29
30 #include "rtl.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35
36 /* CONSTANTS *****************************************************************/
37
38 const PCHAR RtlpShortIllegals = " ;+=[],\"*\\<>/?:|";
39
40
41 /* FUNCTIONS *****************************************************************/
42
43 static BOOLEAN
44 RtlpIsShortIllegal(CHAR Char)
45 {
46 return strchr(RtlpShortIllegals, Char) ? TRUE : FALSE;
47 }
48
49 static USHORT
50 RtlpGetCheckSum(PUNICODE_STRING Name)
51 {
52 USHORT Hash = 0;
53 ULONG Length;
54 PWCHAR c;
55
56 Length = Name->Length / sizeof(WCHAR);
57 c = Name->Buffer;
58 while(Length--)
59 {
60 Hash = (Hash + (*c << 4) + (*c >> 4)) * 11;
61 c++;
62 }
63 return Hash;
64 }
65
66 static ULONG
67 RtlpGetIndexLength(ULONG Index)
68 {
69 ULONG Length = 0;
70 while (Index)
71 {
72 Index /= 10;
73 Length++;
74 }
75 return Length ? Length : 1;
76 }
77
78
79 /*
80 * @implemented
81 */
82 VOID STDCALL
83 RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
84 IN BOOLEAN AllowExtendedCharacters,
85 IN OUT PGENERATE_NAME_CONTEXT Context,
86 OUT PUNICODE_STRING Name8dot3)
87 {
88 ULONG Count;
89 WCHAR NameBuffer[8];
90 WCHAR ExtBuffer[4];
91 ULONG StrLength;
92 ULONG NameLength;
93 ULONG ExtLength;
94 ULONG CopyLength;
95 ULONG DotPos;
96 ULONG i, j;
97 ULONG IndexLength;
98 ULONG CurrentIndex;
99 USHORT Checksum;
100 CHAR c;
101
102 StrLength = Name->Length / sizeof(WCHAR);
103 DPRINT("StrLength: %hu\n", StrLength);
104
105 /* Find last dot in Name */
106 DotPos = 0;
107 for (i = 0; i < StrLength; i++)
108 {
109 if (Name->Buffer[i] == L'.')
110 {
111 DotPos = i;
112 }
113 }
114
115 if (DotPos == 0)
116 {
117 DotPos = i;
118 }
119 DPRINT("DotPos: %hu\n", DotPos);
120
121 /* Copy name (6 valid characters max) */
122 for (i = 0, NameLength = 0; NameLength < 6 && i < DotPos; i++)
123 {
124 c = 0;
125 RtlUpcaseUnicodeToOemN(&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
126 if (Count != 1 || c == 0 || RtlpIsShortIllegal(c))
127 {
128 NameBuffer[NameLength++] = L'_';
129 }
130 else if (c != '.')
131 {
132 NameBuffer[NameLength++] = (WCHAR)c;
133 }
134 }
135
136 DPRINT("NameBuffer: '%.08S'\n", NameBuffer);
137 DPRINT("NameLength: %hu\n", NameLength);
138
139 /* Copy extension (4 valid characters max) */
140 if (DotPos < StrLength)
141 {
142 for (i = DotPos, ExtLength = 0; ExtLength < 4 && i < StrLength; i++)
143 {
144 c = 0;
145 RtlUpcaseUnicodeToOemN(&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
146 if (Count != 1 || c == 0 || RtlpIsShortIllegal(Name->Buffer[i]))
147 {
148 ExtBuffer[ExtLength++] = L'_';
149 }
150 else
151 {
152 ExtBuffer[ExtLength++] = c;
153 }
154 }
155 }
156 else
157 {
158 ExtLength = 0;
159 }
160 DPRINT("ExtBuffer: '%.04S'\n", ExtBuffer);
161 DPRINT("ExtLength: %hu\n", ExtLength);
162
163 /* Determine next index */
164 IndexLength = RtlpGetIndexLength(Context->LastIndexValue);
165 if (Context->CheckSumInserted)
166 {
167 CopyLength = min(NameLength, 8 - 4 - 1 - IndexLength);
168 Checksum = RtlpGetCheckSum(Name);
169 }
170 else
171 {
172 CopyLength = min(NameLength, 8 - 1 - IndexLength);
173 Checksum = 0;
174 }
175
176 DPRINT("CopyLength: %hu\n", CopyLength);
177
178 if ((Context->NameLength == CopyLength) &&
179 (wcsncmp(Context->NameBuffer, NameBuffer, CopyLength) == 0) &&
180 (Context->ExtensionLength == ExtLength) &&
181 (wcsncmp(Context->ExtensionBuffer, ExtBuffer, ExtLength) == 0) &&
182 (Checksum == Context->Checksum) &&
183 (Context->LastIndexValue < 999))
184 {
185 CHECKPOINT;
186 Context->LastIndexValue++;
187 if (Context->CheckSumInserted == FALSE &&
188 Context->LastIndexValue > 9)
189 {
190 Context->CheckSumInserted = TRUE;
191 Context->LastIndexValue = 1;
192 Context->Checksum = RtlpGetCheckSum(Name);
193 }
194 }
195 else
196 {
197 CHECKPOINT;
198 Context->LastIndexValue = 1;
199 Context->CheckSumInserted = FALSE;
200 }
201
202 IndexLength = RtlpGetIndexLength(Context->LastIndexValue);
203
204 DPRINT("CurrentIndex: %hu, IndexLength %hu\n", Context->LastIndexValue, IndexLength);
205
206 if (Context->CheckSumInserted)
207 {
208 CopyLength = min(NameLength, 8 - 4 - 1 - IndexLength);
209 }
210 else
211 {
212 CopyLength = min(NameLength, 8 - 1 - IndexLength);
213 }
214
215 /* Build the short name */
216 memcpy(Name8dot3->Buffer, NameBuffer, CopyLength * sizeof(WCHAR));
217 j = CopyLength;
218 if (Context->CheckSumInserted)
219 {
220 j += 3;
221 Checksum = Context->Checksum;
222 for (i = 0; i < 4; i++)
223 {
224 Name8dot3->Buffer[j--] = (Checksum % 16) > 9 ? (Checksum % 16) + L'A' - 10 : (Checksum % 16) + L'0';
225 Checksum /= 16;
226 }
227 j = CopyLength + 4;
228 }
229 Name8dot3->Buffer[j++] = L'~';
230 j += IndexLength - 1;
231 CurrentIndex = Context->LastIndexValue;
232 for (i = 0; i < IndexLength; i++)
233 {
234 Name8dot3->Buffer[j--] = (CurrentIndex % 10) + L'0';
235 CurrentIndex /= 10;
236 }
237 j += IndexLength + 1;
238
239 memcpy(Name8dot3->Buffer + j, ExtBuffer, ExtLength * sizeof(WCHAR));
240 Name8dot3->Length = (j + ExtLength) * sizeof(WCHAR);
241
242 DPRINT("Name8dot3: '%wZ'\n", Name8dot3);
243
244 /* Update context */
245 Context->NameLength = CopyLength;
246 Context->ExtensionLength = ExtLength;
247 memcpy(Context->NameBuffer, NameBuffer, CopyLength * sizeof(WCHAR));
248 memcpy(Context->ExtensionBuffer, ExtBuffer, ExtLength * sizeof(WCHAR));
249 }
250
251
252 /*
253 * @implemented
254 */
255 BOOLEAN STDCALL
256 RtlIsNameLegalDOS8Dot3(IN PUNICODE_STRING UnicodeName,
257 IN PANSI_STRING AnsiName,
258 OUT PBOOLEAN SpacesFound)
259 {
260 PANSI_STRING name = AnsiName;
261 ANSI_STRING DummyString;
262 CHAR Buffer[12];
263 char *str;
264 ULONG Length;
265 ULONG i;
266 NTSTATUS Status;
267 BOOLEAN HasSpace = FALSE;
268 BOOLEAN HasDot = FALSE;
269
270 if (UnicodeName->Length > 24)
271 {
272 return(FALSE); /* name too long */
273 }
274
275 if (!name)
276 {
277 name = &DummyString;
278 name->Length = 0;
279 name->MaximumLength = 12;
280 name->Buffer = Buffer;
281 }
282
283 Status = RtlUpcaseUnicodeStringToCountedOemString(name,
284 UnicodeName,
285 FALSE);
286 if (!NT_SUCCESS(Status))
287 {
288 return(FALSE);
289 }
290
291 Length = name->Length;
292 str = name->Buffer;
293
294 if (!(Length == 1 && *str == '.') &&
295 !(Length == 2 && *str == '.' && *(str + 1) == '.'))
296 {
297 for (i = 0; i < Length; i++, str++)
298 {
299 switch (*str)
300 {
301 case ' ':
302 HasSpace = TRUE;
303 break;
304
305 case '.':
306 if ((HasDot) || /* two or more dots */
307 (i == 0) || /* dot is first char */
308 (i + 1 == Length) || /* dot is last char */
309 (Length - i > 4) || /* more than 3 chars of extension */
310 (HasDot == FALSE && i > 8)) /* name is longer than 8 chars */
311 return(FALSE);
312 HasDot = TRUE;
313 break;
314 default:
315 if (RtlpIsShortIllegal(*str))
316 {
317 return(FALSE);
318 }
319 }
320 }
321 }
322
323 /* Name is longer than 8 chars and does not have an extension */
324 if (Length > 8 && HasDot == FALSE)
325 {
326 return(FALSE);
327 }
328
329 if (SpacesFound)
330 *SpacesFound = HasSpace;
331
332 return(TRUE);
333 }
334
335 /*
336 * @unimplemented
337 */
338 NTSTATUS
339 STDCALL
340 RtlVolumeDeviceToDosName(
341 IN PVOID VolumeDeviceObject,
342 OUT PUNICODE_STRING DosName
343 )
344 {
345 UNIMPLEMENTED;
346 return STATUS_NOT_IMPLEMENTED;
347 }
348
349 /* EOF */