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