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