Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[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 append_multi_sz_value(KeyHandle,
294 ValueName,
295 Str,
296 Size);
297
298 free(Str);
299 return TRUE;
300 }
301 /* else fall through to normal string handling */
302 }
303 else
304 {
305 if (InfHostGetStringField(Context, 5, NULL, 0, &Size) != 0)
306 Size = 0;
307
308 if (Size)
309 {
310 Str = malloc(Size * sizeof(WCHAR));
311 if (Str == NULL)
312 return FALSE;
313
314 InfHostGetStringField(Context, 5, Str, Size, NULL);
315 }
316 }
317
318 if (Type == REG_DWORD)
319 {
320 ULONG dw = Str ? strtoulW(Str, NULL, 0) : 0;
321
322 DPRINT("setting dword %S to %x\n", ValueName, dw);
323
324 RegSetValueExW(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(KeyHandle,
338 ValueName,
339 0,
340 Type,
341 (PVOID)Str,
342 Size * sizeof(WCHAR));
343 }
344 else
345 {
346 RegSetValueExW(KeyHandle,
347 ValueName,
348 0,
349 Type,
350 (PVOID)&EmptyStr,
351 sizeof(WCHAR));
352 }
353 }
354 free(Str);
355 }
356 else /* get the binary data */
357 {
358 PUCHAR Data = NULL;
359
360 if (InfHostGetBinaryField(Context, 5, NULL, 0, &Size) != 0)
361 Size = 0;
362
363 if (Size)
364 {
365 Data = malloc(Size);
366 if (Data == NULL)
367 return FALSE;
368
369 DPRINT("setting binary data %S len %d\n", ValueName, Size);
370 InfHostGetBinaryField(Context, 5, Data, Size, NULL);
371 }
372
373 RegSetValueExW(KeyHandle,
374 ValueName,
375 0,
376 Type,
377 (PVOID)Data,
378 Size);
379
380 free(Data);
381 }
382
383 return TRUE;
384 }
385
386 /***********************************************************************
387 * registry_callback
388 *
389 * Called once for each AddReg and DelReg entry in a given section.
390 */
391 static BOOL
392 registry_callback(HINF hInf, PWCHAR Section, BOOL Delete)
393 {
394 WCHAR Buffer[MAX_INF_STRING_LENGTH];
395 PWCHAR ValuePtr;
396 ULONG Flags;
397 size_t Length;
398
399 PINFCONTEXT Context = NULL;
400 HKEY KeyHandle;
401 BOOL Ok;
402
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 return FALSE;
467 }
468 }
469
470 InfHostFreeContext(Context);
471
472 return TRUE;
473 }
474
475
476 BOOL
477 ImportRegistryFile(PCHAR FileName)
478 {
479 HINF hInf;
480 ULONG ErrorLine;
481
482 /* Load inf file from install media. */
483 if (InfHostOpenFile(&hInf, FileName, 0, &ErrorLine) != 0)
484 {
485 DPRINT1("InfHostOpenFile(%s) failed\n", FileName);
486 return FALSE;
487 }
488
489 if (!registry_callback(hInf, (PWCHAR)DelReg, TRUE))
490 {
491 DPRINT1("registry_callback() for DelReg failed\n");
492 InfHostCloseFile(hInf);
493 return FALSE;
494 }
495
496 if (!registry_callback(hInf, (PWCHAR)AddReg, FALSE))
497 {
498 DPRINT1("registry_callback() for AddReg failed\n");
499 InfHostCloseFile(hInf);
500 return FALSE;
501 }
502
503 InfHostCloseFile(hInf);
504
505 return TRUE;
506 }
507
508 /* EOF */