[TOOLS]
[reactos.git] / reactos / tools / mkhive / reginf.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2003, 2006 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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS hive maker
21 * FILE: tools/mkhive/reginf.h
22 * PURPOSE: Inf file import code
23 * PROGRAMMER: Eric Kohl
24 * Hervé Poussineau
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32
33 #define NDEBUG
34 #include "mkhive.h"
35
36 #define FLG_ADDREG_BINVALUETYPE 0x00000001
37 #define FLG_ADDREG_NOCLOBBER 0x00000002
38 #define FLG_ADDREG_DELVAL 0x00000004
39 #define FLG_ADDREG_APPEND 0x00000008
40 #define FLG_ADDREG_KEYONLY 0x00000010
41 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
42 #define FLG_ADDREG_TYPE_SZ 0x00000000
43 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
44 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
45 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
46 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
47 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
48 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
49
50
51 static const WCHAR HKCR[] = {'H','K','C','R',0};
52 static const WCHAR HKCU[] = {'H','K','C','U',0};
53 static const WCHAR HKLM[] = {'H','K','L','M',0};
54 static const WCHAR HKU[] = {'H','K','U',0};
55 static const WCHAR HKR[] = {'H','K','R',0};
56
57 static const WCHAR HKCRPath[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\','S','O','F','T','W','A','R','E','\\','C','l','a','s','s','e','s','\\',0};
58 static const WCHAR HKCUPath[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\','.','D','E','F','A','U','L','T','\\',0};
59 static const WCHAR HKLMPath[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',0};
60 static const WCHAR HKUPath[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',0};
61
62 static const WCHAR AddReg[] = {'A','d','d','R','e','g',0};
63 static const WCHAR DelReg[] = {'D','e','l','R','e','g',0};
64
65 /* FUNCTIONS ****************************************************************/
66
67 static BOOL
68 GetRootKey (PWCHAR Name)
69 {
70 if (!strcmpiW (Name, HKCR))
71 {
72 strcpyW (Name, HKCRPath);
73 return TRUE;
74 }
75
76 if (!strcmpiW (Name, HKCU))
77 {
78 strcpyW (Name, HKCUPath);
79 return TRUE;
80 }
81
82 if (!strcmpiW (Name, HKLM))
83 {
84 strcpyW (Name, HKLMPath);
85 return TRUE;
86 }
87
88 if (!strcmpiW (Name, HKU))
89 {
90 strcpyW (Name, HKUPath);
91 return TRUE;
92 }
93
94 #if 0
95 if (!strcmpiW (Name, HKR))
96 return FALSE;
97 #endif
98
99 return FALSE;
100 }
101
102
103 /***********************************************************************
104 * AppendMultiSzValue
105 *
106 * Append a multisz string to a multisz registry value.
107 */
108 static VOID
109 AppendMultiSzValue (
110 IN HKEY KeyHandle,
111 IN PWCHAR ValueName,
112 IN PWCHAR Strings,
113 IN SIZE_T StringSize)
114 {
115 SIZE_T Size;
116 ULONG Type;
117 size_t Total;
118 PWCHAR Buffer;
119 PWCHAR p;
120 size_t len;
121 LONG Error;
122
123 Error = RegQueryValueExW (
124 KeyHandle,
125 ValueName,
126 NULL,
127 &Type,
128 NULL,
129 &Size);
130 if ((Error != ERROR_SUCCESS) ||
131 (Type != REG_MULTI_SZ))
132 return;
133
134 Buffer = malloc ((Size + StringSize) * sizeof(WCHAR));
135 if (Buffer == NULL)
136 return;
137
138 Error = RegQueryValueExW (
139 KeyHandle,
140 ValueName,
141 NULL,
142 NULL,
143 (PUCHAR)Buffer,
144 &Size);
145 if (Error != ERROR_SUCCESS)
146 goto done;
147
148 /* compare each string against all the existing ones */
149 Total = Size;
150 while (*Strings != 0)
151 {
152 len = strlenW(Strings) + 1;
153
154 for (p = Buffer; *p != 0; p += strlenW(p) + 1)
155 if (!strcmpiW(p, Strings))
156 break;
157
158 if (*p == 0) /* not found, need to append it */
159 {
160 memcpy (p, Strings, len);
161 p[len] = 0;
162 Total += len;
163 }
164 Strings += len;
165 }
166
167 if (Total != Size)
168 {
169 DPRINT ("setting value %S to %S\n", ValueName, Buffer);
170 RegSetValueExW (
171 KeyHandle,
172 ValueName,
173 0,
174 REG_MULTI_SZ,
175 (PUCHAR)Buffer,
176 (ULONG)Total * sizeof(WCHAR));
177 }
178
179 done:
180 free (Buffer);
181 }
182
183
184 /***********************************************************************
185 * do_reg_operation
186 *
187 * Perform an add/delete registry operation depending on the flags.
188 */
189 static BOOL
190 do_reg_operation(
191 IN HKEY KeyHandle,
192 IN PWCHAR ValueName,
193 IN PINFCONTEXT Context,
194 IN ULONG Flags)
195 {
196 WCHAR EmptyStr = (CHAR)0;
197 ULONG Type;
198 ULONG Size;
199 LONG Error;
200
201 if (Flags & FLG_ADDREG_DELVAL) /* deletion */
202 {
203 if (ValueName)
204 {
205 RegDeleteValueW (KeyHandle, ValueName);
206 }
207 else
208 {
209 RegDeleteKeyW (KeyHandle, NULL);
210 }
211
212 return TRUE;
213 }
214
215 if (Flags & FLG_ADDREG_KEYONLY)
216 return TRUE;
217
218 if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY))
219 {
220 Error = RegQueryValueExW (
221 KeyHandle,
222 ValueName,
223 NULL,
224 NULL,
225 NULL,
226 NULL);
227 if ((Error == ERROR_SUCCESS) &&
228 (Flags & FLG_ADDREG_NOCLOBBER))
229 return TRUE;
230
231 if ((Error != ERROR_SUCCESS) &&
232 (Flags & FLG_ADDREG_OVERWRITEONLY))
233 return TRUE;
234 }
235
236 switch (Flags & FLG_ADDREG_TYPE_MASK)
237 {
238 case FLG_ADDREG_TYPE_SZ:
239 Type = REG_SZ;
240 break;
241
242 case FLG_ADDREG_TYPE_MULTI_SZ:
243 Type = REG_MULTI_SZ;
244 break;
245
246 case FLG_ADDREG_TYPE_EXPAND_SZ:
247 Type = REG_EXPAND_SZ;
248 break;
249
250 case FLG_ADDREG_TYPE_BINARY:
251 Type = REG_BINARY;
252 break;
253
254 case FLG_ADDREG_TYPE_DWORD:
255 Type = REG_DWORD;
256 break;
257
258 case FLG_ADDREG_TYPE_NONE:
259 Type = REG_NONE;
260 break;
261
262 default:
263 Type = Flags >> 16;
264 break;
265 }
266
267 if (!(Flags & FLG_ADDREG_BINVALUETYPE) ||
268 (Type == REG_DWORD && InfHostGetFieldCount (Context) == 5))
269 {
270 PWCHAR Str = NULL;
271
272 if (Type == REG_MULTI_SZ)
273 {
274 if (InfHostGetMultiSzField (Context, 5, NULL, 0, &Size) != 0)
275 Size = 0;
276
277 if (Size)
278 {
279 Str = malloc (Size * sizeof(WCHAR));
280 if (Str == NULL)
281 return FALSE;
282
283 InfHostGetMultiSzField (Context, 5, Str, (ULONG)Size, NULL);
284 }
285
286 if (Flags & FLG_ADDREG_APPEND)
287 {
288 if (Str == NULL)
289 return TRUE;
290
291 AppendMultiSzValue (
292 KeyHandle,
293 ValueName,
294 Str,
295 Size);
296
297 free (Str);
298 return TRUE;
299 }
300 /* else fall through to normal string handling */
301 }
302 else
303 {
304 if (InfHostGetStringField (Context, 5, NULL, 0, &Size) != 0)
305 Size = 0;
306
307 if (Size)
308 {
309 Str = malloc (Size * sizeof(WCHAR));
310 if (Str == NULL)
311 return FALSE;
312
313 InfHostGetStringField (Context, 5, Str, (ULONG)Size, NULL);
314 }
315 }
316
317 if (Type == REG_DWORD)
318 {
319 ULONG dw = Str ? strtoulW (Str, NULL, 0) : 0;
320
321 DPRINT("setting dword %S to %x\n", ValueName, dw);
322
323 RegSetValueExW (
324 KeyHandle,
325 ValueName,
326 0,
327 Type,
328 (const PUCHAR)&dw,
329 sizeof(ULONG));
330 }
331 else
332 {
333 DPRINT("setting value %S to %S\n", ValueName, Str);
334
335 if (Str)
336 {
337 RegSetValueExW (
338 KeyHandle,
339 ValueName,
340 0,
341 Type,
342 (PVOID)Str,
343 (ULONG)Size * sizeof(WCHAR));
344 }
345 else
346 {
347 RegSetValueExW (
348 KeyHandle,
349 ValueName,
350 0,
351 Type,
352 (PVOID)&EmptyStr,
353 (ULONG)sizeof(WCHAR));
354 }
355 }
356 free (Str);
357 }
358 else /* get the binary data */
359 {
360 PUCHAR Data = NULL;
361
362 if (InfHostGetBinaryField (Context, 5, NULL, 0, &Size) != 0)
363 Size = 0;
364
365 if (Size)
366 {
367 Data = malloc (Size);
368 if (Data == NULL)
369 return FALSE;
370
371 DPRINT("setting binary data %S len %d\n", ValueName, Size);
372 InfHostGetBinaryField (Context, 5, Data, Size, NULL);
373 }
374
375 RegSetValueExW (
376 KeyHandle,
377 ValueName,
378 0,
379 Type,
380 (PVOID)Data,
381 (ULONG)Size);
382
383 free (Data);
384 }
385
386 return TRUE;
387 }
388
389 /***********************************************************************
390 * registry_callback
391 *
392 * Called once for each AddReg and DelReg entry in a given section.
393 */
394 static BOOL
395 registry_callback (HINF hInf, PWCHAR Section, BOOL Delete)
396 {
397 WCHAR Buffer[MAX_INF_STRING_LENGTH];
398 PWCHAR ValuePtr;
399 ULONG Flags;
400 size_t Length;
401
402 PINFCONTEXT Context = NULL;
403 HKEY KeyHandle;
404 BOOL Ok;
405
406
407 Ok = InfHostFindFirstLine (hInf, Section, NULL, &Context) == 0;
408 if (!Ok)
409 return TRUE; /* Don't fail if the section isn't present */
410
411 for (;Ok; Ok = (InfHostFindNextLine (Context, Context) == 0))
412 {
413 /* get root */
414 if (InfHostGetStringField (Context, 1, Buffer, MAX_INF_STRING_LENGTH, NULL) != 0)
415 continue;
416 if (!GetRootKey (Buffer))
417 continue;
418
419 /* get key */
420 Length = strlenW (Buffer);
421 if (InfHostGetStringField (Context, 2, Buffer + Length, MAX_INF_STRING_LENGTH - (ULONG)Length, NULL) != 0)
422 *Buffer = 0;
423
424 DPRINT("KeyName: <%S>\n", Buffer);
425
426 if (Delete)
427 {
428 Flags = FLG_ADDREG_DELVAL;
429 }
430 else
431 {
432 /* get flags */
433 if (InfHostGetIntField (Context, 4, (INT *)&Flags) != 0)
434 Flags = 0;
435 }
436
437 DPRINT("Flags: 0x%x\n", Flags);
438
439 if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
440 {
441 if (RegOpenKeyW (NULL, Buffer, &KeyHandle) != ERROR_SUCCESS)
442 {
443 DPRINT("RegOpenKey(%S) failed\n", Buffer);
444 continue; /* ignore if it doesn't exist */
445 }
446 }
447 else
448 {
449 if (RegCreateKeyW (NULL, Buffer, &KeyHandle) != ERROR_SUCCESS)
450 {
451 DPRINT("RegCreateKey(%S) failed\n", Buffer);
452 continue;
453 }
454 }
455
456 /* get value name */
457 if (InfHostGetStringField (Context, 3, Buffer, MAX_INF_STRING_LENGTH, NULL) == 0)
458 {
459 ValuePtr = Buffer;
460 }
461 else
462 {
463 ValuePtr = NULL;
464 }
465
466 /* and now do it */
467 if (!do_reg_operation (KeyHandle, ValuePtr, Context, Flags))
468 {
469 return FALSE;
470 }
471 }
472
473 InfHostFreeContext(Context);
474
475 return TRUE;
476 }
477
478
479 BOOL
480 ImportRegistryFile(PCHAR FileName)
481 {
482 HINF hInf;
483 ULONG ErrorLine;
484
485 /* Load inf file from install media. */
486 if (InfHostOpenFile(&hInf, FileName, 0, &ErrorLine) != 0)
487 {
488 DPRINT1 ("InfHostOpenFile(%s) failed\n", FileName);
489 return FALSE;
490 }
491
492 if (!registry_callback (hInf, (PWCHAR)DelReg, TRUE))
493 {
494 DPRINT1 ("registry_callback() for DelReg failed\n");
495 }
496
497 if (!registry_callback (hInf, (PWCHAR)AddReg, FALSE))
498 {
499 DPRINT1 ("registry_callback() for AddReg failed\n");
500 }
501
502 InfHostCloseFile (hInf);
503
504 return TRUE;
505 }
506
507 /* EOF */