update for HEAD-2003091401
[reactos.git] / ntoskrnl / 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:            ntoskrnl/rtl/dos8dot3.c
24  * PURPOSE:         Short name (8.3 name) functions
25  * PROGRAMMER:      Eric Kohl
26  */
27
28 /* INCLUDES ******************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <ntos/minmax.h>
32
33 #define NDEBUG
34 #include <internal/debug.h>
35
36
37 /* CONSTANTS *****************************************************************/
38
39 const PWCHAR RtlpShortIllegals = L" ;+=[]',\"*\\<>/?:|";
40
41
42 /* FUNCTIONS *****************************************************************/
43
44 static BOOLEAN
45 RtlpIsShortIllegal(WCHAR Char)
46 {
47   int i;
48
49   for (i = 0; RtlpShortIllegals[i]; i++)
50     {
51       if (Char == RtlpShortIllegals[i])
52         return(TRUE);
53     }
54
55   return(FALSE);
56 }
57
58
59 /*
60  * @implemented
61  */
62 VOID STDCALL
63 RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
64                      IN BOOLEAN AllowExtendedCharacters,
65                      IN OUT PGENERATE_NAME_CONTEXT Context,
66                      OUT PUNICODE_STRING Name8dot3)
67 {
68   WCHAR NameBuffer[8];
69   WCHAR ExtBuffer[4];
70   USHORT StrLength;
71   USHORT NameLength;
72   USHORT ExtLength;
73   USHORT CopyLength;
74   USHORT DotPos;
75   USHORT i, j;
76   USHORT CurrentIndex;
77
78   memset(NameBuffer, 0, sizeof(NameBuffer));
79   memset(ExtBuffer, 0, sizeof(ExtBuffer));
80
81   StrLength = Name->Length / sizeof(WCHAR);
82   DPRINT("StrLength: %hu\n", StrLength);
83
84   /* Find last dot in Name */
85   DotPos = 0;
86   for (i = 0; i < StrLength; i++)
87     {
88       if (Name->Buffer[i] == L'.')
89         {
90           DotPos = i;
91         }
92     }
93
94   if (DotPos == 0)
95     {
96       DotPos = i;
97     }
98   DPRINT("DotPos: %hu\n", DotPos);
99
100   /* Copy name (6 valid characters max) */
101   for (i = 0, NameLength = 0; NameLength < 6 && i < DotPos; i++)
102     {
103       if ((!RtlpIsShortIllegal(Name->Buffer[i])) &&
104           (Name->Buffer[i] != L'.'))
105         {
106           NameBuffer[NameLength++] = RtlUpcaseUnicodeChar(Name->Buffer[i]);
107         }
108     }
109   DPRINT("NameBuffer: '%.08S'\n", NameBuffer);
110   DPRINT("NameLength: %hu\n", NameLength);
111
112   /* Copy extension (4 valid characters max) */
113   if (DotPos < StrLength)
114     {
115       for (i = DotPos, ExtLength = 0; ExtLength < 4 && i < StrLength; i++)
116         {
117           if (!RtlpIsShortIllegal(Name->Buffer[i]))
118             {
119               ExtBuffer[ExtLength++] = RtlUpcaseUnicodeChar(Name->Buffer[i]);
120             }
121         }
122     }
123   else
124     {
125       ExtLength = 0;
126     }
127   DPRINT("ExtBuffer: '%.04S'\n", ExtBuffer);
128   DPRINT("ExtLength: %hu\n", ExtLength);
129
130   /* Determine next index */
131   CurrentIndex = Context->LastIndexValue;
132   CopyLength = min(NameLength, (CurrentIndex < 10) ? 6 : 5);
133   DPRINT("CopyLength: %hu\n", CopyLength);
134
135   if ((Context->NameLength == CopyLength) &&
136       (wcsncmp(Context->NameBuffer, NameBuffer, CopyLength) == 0) &&
137       (Context->ExtensionLength == ExtLength) &&
138       (wcsncmp(Context->ExtensionBuffer, ExtBuffer, ExtLength) == 0))
139     CurrentIndex++;
140   else
141     CurrentIndex = 1;
142   DPRINT("CurrentIndex: %hu\n", CurrentIndex);
143
144   /* Build the short name */
145   for (i = 0; i < CopyLength; i++)
146     {
147       Name8dot3->Buffer[i] = NameBuffer[i];
148     }
149
150   Name8dot3->Buffer[i++] = L'~';
151   if (CurrentIndex >= 10)
152     Name8dot3->Buffer[i++] = (CurrentIndex / 10) + L'0';
153   Name8dot3->Buffer[i++] = (CurrentIndex % 10) + L'0';
154
155   for (j = 0; j < ExtLength; i++, j++)
156     {
157       Name8dot3->Buffer[i] = ExtBuffer[j];
158     }
159
160   Name8dot3->Length = i * sizeof(WCHAR);
161
162   DPRINT("Name8dot3: '%wZ'\n", Name8dot3);
163
164   /* Update context */
165   Context->NameLength = CopyLength;
166   for (i = 0; i < CopyLength; i++)
167     {
168       Context->NameBuffer[i] = NameBuffer[i];
169     }
170
171   Context->ExtensionLength = ExtLength;
172   for (i = 0; i < ExtLength; i++)
173     {
174       Context->ExtensionBuffer[i] = ExtBuffer[i];
175     }
176
177   Context->LastIndexValue = CurrentIndex;
178 }
179
180
181 /*
182  * @implemented
183  */
184 BOOLEAN STDCALL
185 RtlIsNameLegalDOS8Dot3(IN PUNICODE_STRING UnicodeName,
186                        IN PANSI_STRING AnsiName,
187                        OUT PBOOLEAN SpacesFound)
188 {
189   PANSI_STRING name = AnsiName;
190   ANSI_STRING DummyString;
191   CHAR Buffer[12];
192   char *str;
193   ULONG Length;
194   ULONG i;
195   NTSTATUS Status;
196   BOOLEAN HasSpace = FALSE;
197   BOOLEAN HasDot = FALSE;
198
199   if (UnicodeName->Length > 24)
200     {
201       return(FALSE); /* name too long */
202     }
203
204   if (!name)
205     {
206       name = &DummyString;
207       name->Length = 0;
208       name->MaximumLength = 12;
209       name->Buffer = Buffer;
210     }
211
212   Status = RtlUpcaseUnicodeStringToCountedOemString(name,
213                                                     UnicodeName,
214                                                     FALSE);
215   if (!NT_SUCCESS(Status))
216     {
217       return(FALSE);
218     }
219
220   Length = name->Length;
221   str = name->Buffer;
222
223   if (!(Length == 1 && *str == '.') &&
224       !(Length == 2 && *str == '.' && *(str + 1) == '.'))
225     {
226       for (i = 0; i < Length; i++, str++)
227         {
228           switch (*str)
229             {
230               case ' ':
231                 HasSpace = TRUE;
232                 break;
233
234               case '.':
235                 if ((HasDot) ||                 /* two or more dots */
236                     (i == 0) ||                 /* dot is first char */
237                     (i + 1 == Length) ||        /* dot is last char */
238                     (Length - i > 4) ||         /* more than 3 chars of extension */
239                     (HasDot == FALSE && i > 8)) /* name is longer than 8 chars */
240                   return(FALSE);
241                 HasDot = TRUE;
242                 break;
243             }
244         }
245     }
246
247   /* Name is longer than 8 chars and does not have an extension */
248   if (Length > 8 && HasDot == FALSE)
249     {
250       return(FALSE);
251     }
252
253   if (SpacesFound)
254     *SpacesFound = HasSpace;
255
256   return(TRUE);
257 }
258
259 /* EOF */