[MMIXER] Fix additional data size initialization for different audio formats (#6753)
[reactos.git] / sdk / lib / rtl / dos8dot3.c
1 /*
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
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <rtl.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 extern PUSHORT NlsUnicodeToMbOemTable;
17
18 /* CONSTANTS *****************************************************************/
19
20 const ULONG RtlpShortIllegals[] = { 0xFFFFFFFF, 0xFC009C04, 0x38000000, 0x10000000 };
21
22 /* FUNCTIONS *****************************************************************/
23
24 BOOLEAN
25 NTAPI
26 RtlIsValidOemCharacter(IN PWCHAR Char);
27
28 static BOOLEAN
29 RtlpIsShortIllegal(const WCHAR Char)
30 {
31 return (Char < 128 && (RtlpShortIllegals[Char / 32] & (1 << (Char % 32))));
32 }
33
34 static USHORT
35 RtlpGetCheckSum(PUNICODE_STRING Name)
36 {
37 PWCHAR CurrentChar;
38 USHORT Hash;
39 USHORT Saved;
40 USHORT Length;
41
42 if (!Name->Length)
43 return 0;
44
45 if (Name->Length == sizeof(WCHAR))
46 return Name->Buffer[0];
47
48 CurrentChar = Name->Buffer;
49 Hash = (*CurrentChar << 8) + *(CurrentChar + 1);
50
51 if (Name->Length == 2 * sizeof(WCHAR))
52 return Hash;
53
54 Saved = Hash;
55 Length = 2;
56
57 do
58 {
59 CurrentChar += 2;
60 Hash = (Hash << 7) + *CurrentChar;
61 Hash = (Saved >> 1) + (Hash << 8);
62
63 if (Length + 1 < Name->Length / sizeof(WCHAR))
64 {
65 Hash += *(CurrentChar + 1);
66 }
67
68 Saved = Hash;
69 Length += 2;
70 }
71 while (Length < Name->Length / sizeof(WCHAR));
72
73 return Hash;
74 }
75
76 /*
77 * @implemented
78 */
79 VOID
80 NTAPI
81 RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
82 IN BOOLEAN AllowExtendedCharacters,
83 IN OUT PGENERATE_NAME_CONTEXT Context,
84 OUT PUNICODE_STRING Name8dot3)
85 {
86 ULONG Length = Name->Length / sizeof(WCHAR);
87 ULONG IndexLength;
88 ULONG Index;
89 ULONG DotPos;
90 WCHAR IndexBuffer[8];
91 WCHAR Char;
92 USHORT Checksum;
93
94 if (!Context->NameLength)
95 {
96 DotPos = Length;
97
98 /* Find last dot in Name */
99 for (Index = 0; Index < Length; Index++)
100 {
101 if (Name->Buffer[Index] == L'.')
102 DotPos = Index;
103 }
104
105 /* Copy name (6 valid characters max) */
106 for (Index = 0; Index < DotPos && Context->NameLength < 6; Index++)
107 {
108 Char = Name->Buffer[Index];
109
110 if ((Char > L' ') && (Char != L'.') &&
111 ((Char < 127) || (AllowExtendedCharacters && RtlIsValidOemCharacter(&Char))))
112 {
113 if (RtlpIsShortIllegal(Char))
114 Char = L'_';
115 else if (Char >= L'a' && Char <= L'z')
116 Char = RtlpUpcaseUnicodeChar(Char);
117
118 Context->NameBuffer[Context->NameLength] = Char;
119 ++Context->NameLength;
120 }
121 }
122
123 /* Copy extension (4 valid characters max) */
124 Context->ExtensionLength = 0;
125 if (DotPos < Length)
126 {
127 Context->ExtensionBuffer[0] = L'.';
128 Context->ExtensionLength = 1;
129
130 while (DotPos < Length && Context->ExtensionLength < 4)
131 {
132 Char = Name->Buffer[DotPos];
133
134 if ((Char > L' ') && (Char != L'.') &&
135 ((Char < 127) || (AllowExtendedCharacters && RtlIsValidOemCharacter(&Char))))
136 {
137 if (RtlpIsShortIllegal(Char))
138 Char = L'_';
139 else if (Char >= L'a' && Char <= L'z')
140 Char = RtlpUpcaseUnicodeChar(Char);
141
142 Context->ExtensionBuffer[Context->ExtensionLength++] = Char;
143 }
144
145 Char = UNICODE_NULL;
146 ++DotPos;
147 }
148
149 if (Char != UNICODE_NULL)
150 Context->ExtensionBuffer[Context->ExtensionLength - 1] = L'~';
151 }
152
153 if (Context->NameLength <= 2)
154 {
155 Checksum = Context->Checksum = RtlpGetCheckSum(Name);
156
157 for (Index = 0; Index < 4; Index++)
158 {
159 Context->NameBuffer[Context->NameLength + Index] =
160 (Checksum & 0xF) > 9 ? (Checksum & 0xF) + L'A' - 10 : (Checksum & 0xF) + L'0';
161 Checksum >>= 4;
162 }
163
164 Context->CheckSumInserted = TRUE;
165 Context->NameLength += 4;
166 }
167 }
168
169 ++Context->LastIndexValue;
170
171 if (Context->LastIndexValue > 4 && !Context->CheckSumInserted)
172 {
173 Checksum = Context->Checksum = RtlpGetCheckSum(Name);
174
175 for (Index = 2; Index < 6; Index++)
176 {
177 Context->NameBuffer[Index] =
178 (Checksum & 0xF) > 9 ? (Checksum & 0xF) + L'A' - 10 : (Checksum & 0xF) + L'0';
179 Checksum >>= 4;
180 }
181
182 Context->CheckSumInserted = TRUE;
183 Context->NameLength = 6;
184 Context->LastIndexValue = 1;
185 }
186
187 /* Calculate index length and index buffer */
188 Index = Context->LastIndexValue;
189 for (IndexLength = 1; IndexLength <= 7 && Index > 0; IndexLength++)
190 {
191 IndexBuffer[8 - IndexLength] = L'0' + (Index % 10);
192 Index /= 10;
193 }
194
195 IndexBuffer[8 - IndexLength] = L'~';
196
197 /* Reset name length */
198 Name8dot3->Length = 0;
199
200 /* If name present */
201 if (Context->NameLength)
202 {
203 /* Copy name buffer */
204 Length = Context->NameLength * sizeof(WCHAR);
205 RtlCopyMemory(Name8dot3->Buffer, Context->NameBuffer, Length);
206 Name8dot3->Length = Length;
207 }
208
209 /* Copy index buffer */
210 Length = IndexLength * sizeof(WCHAR);
211 RtlCopyMemory(Name8dot3->Buffer + (Name8dot3->Length / sizeof(WCHAR)),
212 IndexBuffer + (8 - IndexLength),
213 Length);
214 Name8dot3->Length += Length;
215
216 /* If extension present */
217 if (Context->ExtensionLength)
218 {
219 /* Copy extension buffer */
220 Length = Context->ExtensionLength * sizeof(WCHAR);
221 RtlCopyMemory(Name8dot3->Buffer + (Name8dot3->Length / sizeof(WCHAR)),
222 Context->ExtensionBuffer,
223 Length);
224 Name8dot3->Length += Length;
225 }
226 }
227
228
229 /*
230 * @implemented
231 * Note: the function does not conform to the annotations.
232 * SpacesFound is not always set!
233 */
234 _IRQL_requires_max_(PASSIVE_LEVEL)
235 _Must_inspect_result_
236 NTSYSAPI
237 BOOLEAN
238 NTAPI
239 RtlIsNameLegalDOS8Dot3(IN PCUNICODE_STRING Name,
240 IN OUT POEM_STRING OemName,
241 OUT PBOOLEAN NameContainsSpaces OPTIONAL)
242 {
243 static const char Illegal[] = "*?<>|\"+=,;[]:/\\\345";
244 int Dot = -1;
245 int i;
246 char Buffer[12];
247 OEM_STRING OemString;
248 BOOLEAN GotSpace = FALSE;
249 NTSTATUS Status;
250
251 if (!OemName)
252 {
253 OemString.Length = sizeof(Buffer);
254 OemString.MaximumLength = sizeof(Buffer);
255 OemString.Buffer = Buffer;
256 OemName = &OemString;
257 }
258
259 Status = RtlUpcaseUnicodeStringToCountedOemString(OemName, Name, FALSE);
260 if (!NT_SUCCESS(Status))
261 return FALSE;
262
263 if ((OemName->Length > 12) || (OemName->Buffer == NULL)) return FALSE;
264
265 /* a starting . is invalid, except for . and .. */
266 if (OemName->Buffer[0] == '.')
267 {
268 if (OemName->Length != 1 && (OemName->Length != 2 || OemName->Buffer[1] != '.')) return FALSE;
269 if (NameContainsSpaces) *NameContainsSpaces = FALSE;
270
271 return TRUE;
272 }
273
274 for (i = 0; i < OemName->Length; i++)
275 {
276 switch (OemName->Buffer[i])
277 {
278 case ' ':
279 /* leading/trailing spaces not allowed */
280 if (!i || i == OemName->Length-1 || OemName->Buffer[i+1] == '.') return FALSE;
281 GotSpace = TRUE;
282 break;
283
284 case '.':
285 if (Dot != -1) return FALSE;
286 Dot = i;
287 break;
288
289 default:
290 if (strchr(Illegal, OemName->Buffer[i])) return FALSE;
291 break;
292 }
293 }
294 /* check file part is shorter than 8, extension shorter than 3
295 * dot cannot be last in string
296 */
297 if (Dot == -1)
298 {
299 if (OemName->Length > 8) return FALSE;
300 }
301 else
302 {
303 if (Dot > 8 || (OemName->Length - Dot > 4) || Dot == OemName->Length - 1) return FALSE;
304 }
305
306 if (NameContainsSpaces) *NameContainsSpaces = GotSpace;
307
308 return TRUE;
309 }
310
311 /* EOF */