Added import of REG_EXPAND_SZ registry values.
[reactos.git] / reactos / ntoskrnl / cm / import.c
1 /* $Id: import.c,v 1.6 2002/05/24 07:42:19 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/import.c
6 * PURPOSE: Registry functions
7 * PROGRAMMERS: Rex Jolliff
8 */
9
10 #include <ctype.h>
11
12 #include <ddk/ntddk.h>
13 #include <roscfg.h>
14 #include <internal/ob.h>
15 #include <limits.h>
16 #include <string.h>
17 #include <internal/pool.h>
18 #include <internal/registry.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 #include "cm.h"
24
25 static PCHAR
26 checkAndSkipMagic (PCHAR regChunk)
27 {
28 if (strncmp (regChunk,
29 REGISTRY_FILE_MAGIC,
30 strlen (REGISTRY_FILE_MAGIC)) != 0)
31 {
32 CPRINT ("incorrect magic number in registry chunk. expected: %s got:%.*s\n",
33 REGISTRY_FILE_MAGIC,
34 strlen (REGISTRY_FILE_MAGIC),
35 regChunk);
36 return 0;
37 }
38 regChunk += strlen (REGISTRY_FILE_MAGIC);
39 DPRINT ("Found regsitry chunk magic value\n");
40
41 return regChunk;
42 }
43
44 static PCHAR
45 skipWhitespaceInChunk (PCHAR regChunk)
46 {
47 while (*regChunk && isspace (*regChunk))
48 regChunk++;
49
50 return *regChunk ? regChunk : 0;
51 }
52
53 static int
54 computeKeyNameSize (PCHAR regChunk)
55 {
56 int copyCount = 0;
57
58 while (*regChunk != 0 && *regChunk != ']')
59 {
60 copyCount++;
61 regChunk++;
62 }
63
64 return copyCount;
65 }
66
67 static BOOLEAN
68 allocateKeyName (PUNICODE_STRING newKeyName, int newKeySize)
69 {
70 if (newKeyName->MaximumLength < (newKeySize + 1) * sizeof (WCHAR))
71 {
72 if (newKeyName->Buffer != 0)
73 ExFreePool (newKeyName->Buffer);
74 newKeyName->Length = 0;
75 newKeyName->MaximumLength = (newKeySize + 1) * sizeof (WCHAR);
76 newKeyName->Buffer = ExAllocatePool (NonPagedPool, newKeyName->MaximumLength);
77 if (newKeyName->Buffer == 0)
78 {
79 CPRINT ("Could not allocate space for key name\n");
80 return FALSE;
81 }
82 newKeyName->Buffer [0] = 0;
83 }
84 else
85 {
86 newKeyName->Length = 0;
87 newKeyName->Buffer [0] = 0;
88 }
89
90 return TRUE;
91 }
92
93 static PCHAR
94 skipToNextKeyInChunk (PCHAR regChunk)
95 {
96 while (*regChunk != 0 && *regChunk != '[')
97 {
98 while (*regChunk != 0 && *regChunk != '\n')
99 {
100 regChunk++;
101 }
102 regChunk++;
103 }
104
105 return *regChunk ? regChunk : 0;
106 }
107
108 static PCHAR
109 getKeyNameFromChunk (PCHAR regChunk, PUNICODE_STRING newKeyName)
110 {
111 int index = 0;
112
113 while (*regChunk != 0 && *regChunk != ']')
114 {
115 newKeyName->Buffer [index++] = *regChunk++;
116 }
117 newKeyName->Buffer [index] = '\0';
118 newKeyName->Length = index * sizeof (WCHAR);
119
120 return *regChunk ? regChunk : 0;
121 }
122
123 static HANDLE
124 createNewKey (PUNICODE_STRING newKeyName)
125 {
126 NTSTATUS status;
127 OBJECT_ATTRIBUTES attributes;
128 HANDLE handleToReturn;
129
130 DPRINT ("Creating key (%wZ)\n", newKeyName);
131 InitializeObjectAttributes (&attributes,
132 newKeyName,
133 0,
134 0,
135 NULL);
136 status = NtCreateKey (&handleToReturn,
137 KEY_ALL_ACCESS,
138 &attributes,
139 0,
140 NULL,
141 REG_OPTION_VOLATILE,
142 NULL);
143 if (!NT_SUCCESS(status))
144 {
145 CPRINT ("Could not crete key (%wZ)\n", newKeyName);
146 return INVALID_HANDLE_VALUE;
147 }
148
149 return handleToReturn;
150 }
151
152 static PCHAR
153 skipToNextKeyValueInChunk (PCHAR regChunk)
154 {
155 while (*regChunk != 0 && *regChunk != '\n')
156 regChunk++;
157 regChunk = skipWhitespaceInChunk (regChunk);
158
159 return regChunk;
160 }
161
162 static int
163 computeKeyValueNameSize (PCHAR regChunk)
164 {
165 int size = 0;
166
167 if (*regChunk != '\"')
168 return 0;
169 regChunk++;
170 while (*regChunk != 0 && *regChunk != '\"')
171 {
172 size++;
173 regChunk++;
174 }
175
176 return regChunk ? size : 0;
177 }
178
179 static PCHAR
180 getKeyValueNameFromChunk (PCHAR regChunk, PUNICODE_STRING newKeyName)
181 {
182 int index = 0;
183
184 regChunk++;
185 while (*regChunk != 0 && *regChunk != '\"')
186 {
187 newKeyName->Buffer [index++] = *regChunk++;
188 }
189 newKeyName->Buffer [index] = '\0';
190 newKeyName->Length = index * sizeof (WCHAR);
191 regChunk++;
192
193 return *regChunk ? regChunk : 0;
194 }
195
196 static PCHAR
197 getKeyValueTypeFromChunk (PCHAR regChunk, PCHAR dataFormat, int *keyValueType)
198 {
199 if (*regChunk == '\"')
200 {
201 strcpy (dataFormat, "string");
202 *keyValueType = REG_SZ;
203 }
204 else if (strncmp (regChunk, "hex", 3) == 0)
205 {
206 strcpy (dataFormat, "hex");
207 regChunk += 3;
208 if (*regChunk == '(')
209 {
210 regChunk++;
211 *keyValueType = atoi (regChunk);
212 while (*regChunk != 0 && *regChunk != ')')
213 regChunk++;
214 regChunk++;
215 }
216 else
217 *keyValueType = REG_BINARY;
218 if (*regChunk == ':')
219 regChunk++;
220 }
221 else if (strncmp (regChunk, "dword", 5) == 0)
222 {
223 strcpy (dataFormat, "dword");
224 *keyValueType = REG_DWORD;
225 regChunk += 5;
226 if (*regChunk == ':')
227 regChunk++;
228 }
229 else if (strncmp (regChunk, "multi", 5) == 0)
230 {
231 strcpy (dataFormat, "multi");
232 *keyValueType = REG_MULTI_SZ;
233 regChunk += 5;
234 if (*regChunk == ':')
235 regChunk++;
236 }
237 else if (strncmp (regChunk, "expand", 6) == 0)
238 {
239 strcpy (dataFormat, "expand");
240 *keyValueType = REG_EXPAND_SZ;
241 regChunk += 6;
242 if (*regChunk == ':')
243 regChunk++;
244 }
245 else
246 {
247 UNIMPLEMENTED;
248 }
249
250 return *regChunk ? regChunk : 0;
251 }
252
253 static int
254 computeKeyValueDataSize (PCHAR regChunk, PCHAR dataFormat)
255 {
256 int dataSize = 0;
257
258 if (strcmp (dataFormat, "string") == 0)
259 {
260 regChunk++;
261 while (*regChunk != 0 && *regChunk != '\"')
262 {
263 dataSize++;
264 dataSize++;
265 regChunk++;
266 }
267 dataSize++;
268 dataSize++;
269 }
270 else if (strcmp (dataFormat, "hex") == 0)
271 {
272 while (*regChunk != 0 && isxdigit(*regChunk))
273 {
274 regChunk++;
275 regChunk++;
276 dataSize++;
277 if (*regChunk == ',')
278 {
279 regChunk++;
280 if (*regChunk == '\\')
281 {
282 regChunk++;
283 regChunk = skipWhitespaceInChunk (regChunk);
284 }
285 }
286 }
287 }
288 else if (strcmp (dataFormat, "dword") == 0)
289 {
290 dataSize = sizeof(DWORD);
291 while (*regChunk != 0 && isxdigit(*regChunk))
292 {
293 regChunk++;
294 }
295 }
296 else if (strcmp (dataFormat, "multi") == 0)
297 {
298 while (*regChunk == '\"')
299 {
300 regChunk++;
301 while (*regChunk != 0 && *regChunk != '\"')
302 {
303 dataSize++;
304 dataSize++;
305 regChunk++;
306 }
307 regChunk++;
308 dataSize++;
309 dataSize++;
310 if (*regChunk == ',')
311 {
312 regChunk++;
313 regChunk = skipWhitespaceInChunk (regChunk);
314 if (*regChunk == '\\')
315 {
316 regChunk++;
317 regChunk = skipWhitespaceInChunk (regChunk);
318 }
319 }
320 else
321 break;
322 }
323 dataSize++;
324 dataSize++;
325 }
326 else if (strcmp (dataFormat, "expand") == 0)
327 {
328 regChunk++;
329 while (*regChunk != 0 && *regChunk != '\"')
330 {
331 dataSize++;
332 dataSize++;
333 regChunk++;
334 }
335 dataSize++;
336 dataSize++;
337 }
338 else
339 {
340 UNIMPLEMENTED;
341 }
342
343 return dataSize;
344 }
345
346 static BOOLEAN
347 allocateDataBuffer (PVOID * data, int * dataBufferSize, int dataSize)
348 {
349 if (*dataBufferSize < dataSize)
350 {
351 if (*dataBufferSize > 0)
352 ExFreePool (*data);
353 *data = ExAllocatePool (NonPagedPool, dataSize);
354 *dataBufferSize = dataSize;
355 }
356
357 return TRUE;
358 }
359
360 static PCHAR
361 getKeyValueDataFromChunk (PCHAR regChunk, PCHAR dataFormat, PCHAR data)
362 {
363 char dataValue;
364 ULONG ulValue;
365 PWCHAR ptr;
366
367 if (strcmp (dataFormat, "string") == 0)
368 {
369 /* convert quoted string to zero-terminated Unicode string */
370 ptr = (PWCHAR)data;
371 regChunk++;
372 while (*regChunk != 0 && *regChunk != '\"')
373 {
374 *ptr++ = (WCHAR)*regChunk++;
375 }
376 *ptr = 0;
377 regChunk++;
378 }
379 else if (strcmp (dataFormat, "hex") == 0)
380 {
381 while (*regChunk != 0 && isxdigit (*regChunk))
382 {
383 dataValue = (isdigit (*regChunk) ? *regChunk - '0' :
384 tolower(*regChunk) - 'a') << 4;
385 regChunk++;
386 dataValue += (isdigit (*regChunk) ? *regChunk - '0' :
387 tolower(*regChunk) - 'a');
388 regChunk++;
389 *data++ = dataValue;
390 if (*regChunk == ',')
391 {
392 regChunk++;
393 if (*regChunk == '\\')
394 {
395 regChunk++;
396 regChunk = skipWhitespaceInChunk (regChunk);
397 }
398 }
399 }
400 }
401 else if (strcmp (dataFormat, "dword") == 0)
402 {
403 ulValue = 0;
404 while (*regChunk != 0 && isxdigit(*regChunk))
405 {
406 dataValue = (isdigit (*regChunk) ? *regChunk - '0' :
407 tolower(*regChunk) - 'a');
408 ulValue = (ulValue << 4) + dataValue;
409 regChunk++;
410 }
411 memcpy(data, &ulValue, sizeof(ULONG));
412 }
413 else if (strcmp (dataFormat, "multi") == 0)
414 {
415 ptr = (PWCHAR)data;
416 while (*regChunk == '\"')
417 {
418 regChunk++;
419 while (*regChunk != 0 && *regChunk != '\"')
420 {
421 *ptr++ = (WCHAR)*regChunk++;
422 }
423 regChunk++;
424 *ptr++ = 0;
425 if (*regChunk == ',')
426 {
427 regChunk++;
428 regChunk = skipWhitespaceInChunk (regChunk);
429 if (*regChunk == '\\')
430 {
431 regChunk++;
432 regChunk = skipWhitespaceInChunk (regChunk);
433 }
434 }
435 else
436 break;
437 }
438 *ptr = 0;
439 }
440 else if (strcmp (dataFormat, "expand") == 0)
441 {
442 /* convert quoted string to zero-terminated Unicode string */
443 ptr = (PWCHAR)data;
444 regChunk++;
445 while (*regChunk != 0 && *regChunk != '\"')
446 {
447 *ptr++ = (WCHAR)*regChunk++;
448 }
449 *ptr = 0;
450 regChunk++;
451 }
452 else
453 {
454 UNIMPLEMENTED;
455 }
456
457 return *regChunk ? regChunk : 0;
458 }
459
460 static BOOLEAN
461 setKeyValue (HANDLE currentKey,
462 PUNICODE_STRING newValueName,
463 ULONG keyValueType,
464 PVOID data,
465 ULONG dataSize)
466 {
467 NTSTATUS status;
468
469 DPRINT ("Adding value (%wZ) to current key, with data type %d size %d\n",
470 newValueName,
471 keyValueType,
472 dataSize);
473 status = NtSetValueKey (currentKey,
474 newValueName,
475 0,
476 keyValueType,
477 data,
478 dataSize);
479 if (!NT_SUCCESS(status))
480 {
481 CPRINT ("could not set key value, rc:%08x\n", status);
482 return FALSE;
483 }
484
485 return TRUE;
486 }
487
488 VOID
489 CmImportHive(PCHAR ChunkBase,
490 ULONG ChunkSize)
491 {
492 HANDLE currentKey = INVALID_HANDLE_VALUE;
493 int newKeySize;
494 UNICODE_STRING newKeyName = {0, 0, 0};
495 char dataFormat [10];
496 int keyValueType;
497 int dataSize = 0;
498 int dataBufferSize = 0;
499 PVOID data = 0;
500 PCHAR regChunk;
501
502 DPRINT("ChunkBase %p ChunkSize %lx\n", ChunkBase, ChunkSize);
503
504 regChunk = checkAndSkipMagic (ChunkBase);
505 if (regChunk == 0)
506 return;
507
508 while (regChunk != 0 && *regChunk != 0 && (((ULONG)regChunk-(ULONG)ChunkBase) < ChunkSize))
509 {
510 regChunk = skipWhitespaceInChunk (regChunk);
511 if (regChunk == 0)
512 continue;
513
514 if (*regChunk == '[')
515 {
516 if (currentKey != INVALID_HANDLE_VALUE)
517 {
518 DPRINT("Closing current key: 0x%lx\n", currentKey);
519 NtClose (currentKey);
520 currentKey = INVALID_HANDLE_VALUE;
521 }
522
523 regChunk++;
524
525 newKeySize = computeKeyNameSize (regChunk);
526 if (!allocateKeyName (&newKeyName, newKeySize))
527 {
528 regChunk = 0;
529 continue;
530 }
531
532 regChunk = getKeyNameFromChunk (regChunk, &newKeyName);
533 if (regChunk == 0)
534 continue;
535
536 currentKey = createNewKey (&newKeyName);
537 if (currentKey == INVALID_HANDLE_VALUE)
538 {
539 regChunk = skipToNextKeyInChunk (regChunk);
540 continue;
541 }
542
543 regChunk++;
544 }
545 else
546 {
547 if (currentKey == INVALID_HANDLE_VALUE)
548 {
549 regChunk = skipToNextKeyInChunk (regChunk);
550 continue;
551 }
552
553 newKeySize = computeKeyValueNameSize (regChunk);
554 if (!allocateKeyName (&newKeyName, newKeySize))
555 {
556 regChunk = 0;
557 continue;
558 }
559
560 regChunk = getKeyValueNameFromChunk (regChunk, &newKeyName);
561 if (regChunk == 0)
562 continue;
563
564 if (*regChunk != '=')
565 {
566 regChunk = skipToNextKeyValueInChunk (regChunk);
567 continue;
568 }
569 regChunk++;
570
571 regChunk = getKeyValueTypeFromChunk (regChunk, dataFormat, &keyValueType);
572 if (regChunk == 0)
573 continue;
574
575 dataSize = computeKeyValueDataSize (regChunk, dataFormat);
576 if (!allocateDataBuffer (&data, &dataBufferSize, dataSize))
577 {
578 regChunk = 0;
579 continue;
580 }
581
582 regChunk = getKeyValueDataFromChunk (regChunk, dataFormat, data);
583 if (regChunk == 0)
584 continue;
585
586 if (!setKeyValue (currentKey, &newKeyName, keyValueType, data, dataSize))
587 {
588 regChunk = 0;
589 continue;
590 }
591 }
592 }
593
594 if (currentKey != INVALID_HANDLE_VALUE)
595 {
596 NtClose (currentKey);
597 }
598 if (newKeyName.Buffer != 0)
599 {
600 ExFreePool (newKeyName.Buffer);
601 }
602 if (data != 0)
603 {
604 ExFreePool (data);
605 }
606
607 return;
608 }
609
610