fixed some warnings with gcc4 (mostly assignment differs in signedness warnings)
[reactos.git] / reactos / tools / mkhive / reginf.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2003 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 /* $Id$
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS hive maker
22 * FILE: tools/mkhive/reginf.h
23 * PURPOSE: Inf file import code
24 * PROGRAMMER: Eric Kohl
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32
33 #include "mkhive.h"
34 #include "registry.h"
35 #include "infcache.h"
36
37
38
39 #define FLG_ADDREG_BINVALUETYPE 0x00000001
40 #define FLG_ADDREG_NOCLOBBER 0x00000002
41 #define FLG_ADDREG_DELVAL 0x00000004
42 #define FLG_ADDREG_APPEND 0x00000008
43 #define FLG_ADDREG_KEYONLY 0x00000010
44 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
45 #define FLG_ADDREG_TYPE_SZ 0x00000000
46 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
47 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
48 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
49 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
50 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
51 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
52
53
54 /* FUNCTIONS ****************************************************************/
55
56 static BOOL
57 GetRootKey (PCHAR Name)
58 {
59 if (!strcasecmp (Name, "HKCR"))
60 {
61 strcpy (Name, "\\Registry\\Machine\\SOFTWARE\\Classes\\");
62 return TRUE;
63 }
64
65 if (!strcasecmp (Name, "HKCU"))
66 {
67 strcpy (Name, "\\Registry\\User\\.DEFAULT\\");
68 return TRUE;
69 }
70
71 if (!strcasecmp (Name, "HKLM"))
72 {
73 strcpy (Name, "\\Registry\\Machine\\");
74 return TRUE;
75 }
76
77 if (!strcasecmp (Name, "HKU"))
78 {
79 strcpy (Name, "\\Registry\\User\\");
80 return TRUE;
81 }
82
83 #if 0
84 if (!strcasecmp (Name, "HKR"))
85 return FALSE;
86 #endif
87
88 return FALSE;
89 }
90
91
92 /***********************************************************************
93 * AppendMultiSzValue
94 *
95 * Append a multisz string to a multisz registry value.
96 */
97 static VOID
98 AppendMultiSzValue (HKEY KeyHandle,
99 PCHAR ValueName,
100 PCHAR Strings,
101 ULONG StringSize)
102 {
103 ULONG Size;
104 ULONG Type;
105 ULONG Total;
106 PCHAR Buffer;
107 PCHAR p;
108 int len;
109 LONG Error;
110
111 Error = RegQueryValue (KeyHandle,
112 ValueName,
113 &Type,
114 NULL,
115 &Size);
116 if ((Error != ERROR_SUCCESS) ||
117 (Type != REG_MULTI_SZ))
118 return;
119
120 Buffer = malloc (Size + StringSize);
121 if (Buffer == NULL)
122 return;
123
124 Error = RegQueryValue (KeyHandle,
125 ValueName,
126 NULL,
127 (PCHAR)Buffer,
128 &Size);
129 if (Error != ERROR_SUCCESS)
130 goto done;
131
132 /* compare each string against all the existing ones */
133 Total = Size;
134 while (*Strings != 0)
135 {
136 len = strlen (Strings) + 1;
137
138 for (p = Buffer; *p != 0; p += strlen (p) + 1)
139 if (!strcasecmp (p, Strings))
140 break;
141
142 if (*p == 0) /* not found, need to append it */
143 {
144 memcpy (p, Strings, len);
145 p[len] = 0;
146 Total += len;
147 }
148 Strings += len;
149 }
150
151 if (Total != Size)
152 {
153 DPRINT ("setting value %s to %s\n", ValueName, Buffer);
154 RegSetValue (KeyHandle,
155 ValueName,
156 REG_MULTI_SZ,
157 (PCHAR)Buffer,
158 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 ULONG Size;
180 LONG Error;
181
182 if (Flags & FLG_ADDREG_DELVAL) /* deletion */
183 {
184 if (ValueName)
185 {
186 RegDeleteValue (KeyHandle,
187 ValueName);
188 }
189 else
190 {
191 RegDeleteKey (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 = RegQueryValue (KeyHandle,
204 ValueName,
205 NULL,
206 NULL,
207 NULL);
208 if ((Error == ERROR_SUCCESS) &&
209 (Flags & FLG_ADDREG_NOCLOBBER))
210 return TRUE;
211
212 if ((Error != ERROR_SUCCESS) &&
213 (Flags & FLG_ADDREG_OVERWRITEONLY))
214 return TRUE;
215 }
216
217 switch (Flags & FLG_ADDREG_TYPE_MASK)
218 {
219 case FLG_ADDREG_TYPE_SZ:
220 Type = REG_SZ;
221 break;
222
223 case FLG_ADDREG_TYPE_MULTI_SZ:
224 Type = REG_MULTI_SZ;
225 break;
226
227 case FLG_ADDREG_TYPE_EXPAND_SZ:
228 Type = REG_EXPAND_SZ;
229 break;
230
231 case FLG_ADDREG_TYPE_BINARY:
232 Type = REG_BINARY;
233 break;
234
235 case FLG_ADDREG_TYPE_DWORD:
236 Type = REG_DWORD;
237 break;
238
239 case FLG_ADDREG_TYPE_NONE:
240 Type = REG_NONE;
241 break;
242
243 default:
244 Type = Flags >> 16;
245 break;
246 }
247
248 if (!(Flags & FLG_ADDREG_BINVALUETYPE) ||
249 (Type == REG_DWORD && InfGetFieldCount (Context) == 5))
250 {
251 PCHAR Str = NULL;
252
253 if (Type == REG_MULTI_SZ)
254 {
255 if (!InfGetMultiSzField (Context, 5, NULL, 0, &Size))
256 Size = 0;
257
258 if (Size)
259 {
260 Str = malloc (Size);
261 if (Str == NULL)
262 return FALSE;
263
264 InfGetMultiSzField (Context, 5, Str, Size, NULL);
265 }
266
267 if (Flags & FLG_ADDREG_APPEND)
268 {
269 if (Str == NULL)
270 return TRUE;
271
272 AppendMultiSzValue (KeyHandle,
273 ValueName,
274 Str,
275 Size);
276
277 free (Str);
278 return TRUE;
279 }
280 /* else fall through to normal string handling */
281 }
282 else
283 {
284 if (!InfGetStringField (Context, 5, NULL, 0, &Size))
285 Size = 0;
286
287 if (Size)
288 {
289 Str = malloc (Size);
290 if (Str == NULL)
291 return FALSE;
292
293 InfGetStringField (Context, 5, Str, Size, NULL);
294 }
295 }
296
297 if (Type == REG_DWORD)
298 {
299 ULONG dw = Str ? strtoul (Str, NULL, 0) : 0;
300
301 DPRINT("setting dword %s to %lx\n", ValueName, dw);
302
303 RegSetValue (KeyHandle,
304 ValueName,
305 Type,
306 (PVOID)&dw,
307 sizeof(ULONG));
308 }
309 else
310 {
311 DPRINT("setting value %s to %s\n", ValueName, Str);
312
313 if (Str)
314 {
315 RegSetValue (KeyHandle,
316 ValueName,
317 Type,
318 (PVOID)Str,
319 Size);
320 }
321 else
322 {
323 RegSetValue (KeyHandle,
324 ValueName,
325 Type,
326 (PVOID)&EmptyStr,
327 sizeof(CHAR));
328 }
329 }
330 free (Str);
331 }
332 else /* get the binary data */
333 {
334 PCHAR Data = NULL;
335
336 if (!InfGetBinaryField (Context, 5, NULL, 0, &Size))
337 Size = 0;
338
339 if (Size)
340 {
341 Data = malloc (Size);
342 if (Data == NULL)
343 return FALSE;
344
345 DPRINT("setting binary data %s len %lu\n", ValueName, Size);
346 InfGetBinaryField (Context, 5, Data, Size, NULL);
347 }
348
349 RegSetValue (KeyHandle,
350 ValueName,
351 Type,
352 (PVOID)Data,
353 Size);
354
355 free (Data);
356 }
357
358 return TRUE;
359 }
360
361
362 /***********************************************************************
363 * registry_callback
364 *
365 * Called once for each AddReg and DelReg entry in a given section.
366 */
367 static BOOL
368 registry_callback (HINF hInf, PCHAR Section, BOOL Delete)
369 {
370 CHAR Buffer[MAX_INF_STRING_LENGTH];
371 PCHAR ValuePtr;
372 ULONG Flags;
373 ULONG Length;
374
375 INFCONTEXT Context;
376 HKEY KeyHandle;
377 BOOL Ok;
378
379
380 Ok = InfFindFirstLine (hInf, Section, NULL, &Context);
381 if (!Ok)
382 return TRUE; /* Don't fail if the section isn't present */
383
384 for (;Ok; Ok = InfFindNextLine (&Context, &Context))
385 {
386 /* get root */
387 if (!InfGetStringField (&Context, 1, Buffer, MAX_INF_STRING_LENGTH, NULL))
388 continue;
389 if (!GetRootKey (Buffer))
390 continue;
391
392 /* get key */
393 Length = strlen (Buffer);
394 if (!InfGetStringField (&Context, 2, Buffer + Length, MAX_INF_STRING_LENGTH - Length, NULL))
395 *Buffer = 0;
396
397 DPRINT("KeyName: <%s>\n", Buffer);
398
399 if (Delete)
400 {
401 Flags = FLG_ADDREG_DELVAL;
402 }
403 else
404 {
405 /* get flags */
406 if (!InfGetIntField (&Context, 4, (PLONG)&Flags))
407 Flags = 0;
408 }
409
410 DPRINT("Flags: %lx\n", Flags);
411
412 if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
413 {
414 if (RegOpenKey (NULL, Buffer, &KeyHandle) != ERROR_SUCCESS)
415 {
416 DPRINT("RegOpenKey(%s) failed\n", Buffer);
417 continue; /* ignore if it doesn't exist */
418 }
419 }
420 else
421 {
422 if (RegCreateKey (NULL, Buffer, &KeyHandle) != ERROR_SUCCESS)
423 {
424 DPRINT("RegCreateKey(%s) failed\n", Buffer);
425 continue;
426 }
427 }
428
429 /* get value name */
430 if (InfGetStringField (&Context, 3, Buffer, MAX_INF_STRING_LENGTH, NULL))
431 {
432 ValuePtr = Buffer;
433 }
434 else
435 {
436 ValuePtr = NULL;
437 }
438
439 /* and now do it */
440 if (!do_reg_operation (KeyHandle, ValuePtr, &Context, Flags))
441 {
442 return FALSE;
443 }
444 }
445
446 return TRUE;
447 }
448
449
450 BOOL
451 ImportRegistryFile(PCHAR FileName,
452 PCHAR Section,
453 BOOL Delete)
454 {
455 HINF hInf;
456 ULONG ErrorLine;
457
458 /* Load inf file from install media. */
459 if (!InfOpenFile(&hInf, FileName, &ErrorLine))
460 {
461 DPRINT1 ("InfOpenFile() failed\n");
462 return FALSE;
463 }
464
465 if (!registry_callback (hInf, "DelReg", TRUE))
466 {
467 DPRINT1 ("registry_callback() failed\n");
468 }
469
470 if (!registry_callback (hInf, "AddReg", FALSE))
471 {
472 DPRINT1 ("registry_callback() failed\n");
473 }
474
475 InfCloseFile (hInf);
476
477 return TRUE;
478 }
479
480 /* EOF */