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