update for HEAD-2003091401
[reactos.git] / 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
32 #include "mkhive.h"
33 #include "registry.h"
34 #include "infcache.h"
35
36
37
38 #define FLG_ADDREG_BINVALUETYPE           0x00000001
39 #define FLG_ADDREG_NOCLOBBER              0x00000002
40 #define FLG_ADDREG_DELVAL                 0x00000004
41 #define FLG_ADDREG_APPEND                 0x00000008
42 #define FLG_ADDREG_KEYONLY                0x00000010
43 #define FLG_ADDREG_OVERWRITEONLY          0x00000020
44 #define FLG_ADDREG_TYPE_SZ                0x00000000
45 #define FLG_ADDREG_TYPE_MULTI_SZ          0x00010000
46 #define FLG_ADDREG_TYPE_EXPAND_SZ         0x00020000
47 #define FLG_ADDREG_TYPE_BINARY           (0x00000000 | FLG_ADDREG_BINVALUETYPE)
48 #define FLG_ADDREG_TYPE_DWORD            (0x00010000 | FLG_ADDREG_BINVALUETYPE)
49 #define FLG_ADDREG_TYPE_NONE             (0x00020000 | FLG_ADDREG_BINVALUETYPE)
50 #define FLG_ADDREG_TYPE_MASK             (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
51
52
53 /* FUNCTIONS ****************************************************************/
54
55 static BOOL
56 GetRootKey (PCHAR Name)
57 {
58   if (!strcasecmp (Name, "HKCR"))
59     {
60       strcpy (Name, "\\Registry\\Machine\\SOFTWARE\\Classes\\");
61       return TRUE;
62     }
63
64   if (!strcasecmp (Name, "HKCU"))
65     {
66       strcpy (Name, "\\Registry\\User\\.DEFAULT\\");
67       return TRUE;
68     }
69
70   if (!strcasecmp (Name, "HKLM"))
71     {
72       strcpy (Name, "\\Registry\\Machine\\");
73       return TRUE;
74     }
75
76   if (!strcasecmp (Name, "HKU"))
77     {
78       strcpy (Name, "\\Registry\\User\\");
79       return TRUE;
80     }
81
82 #if 0
83   if (!strcasecmp (Name, "HKR"))
84     return FALSE;
85 #endif
86
87   return FALSE;
88 }
89
90
91 /***********************************************************************
92  * AppendMultiSzValue
93  *
94  * Append a multisz string to a multisz registry value.
95  */
96 static VOID
97 AppendMultiSzValue (HKEY KeyHandle,
98                     PCHAR ValueName,
99                     PCHAR Strings,
100                     ULONG StringSize)
101 {
102   ULONG Size;
103   ULONG Type;
104   ULONG Total;
105   PCHAR Buffer;
106   PCHAR p;
107   int len;
108   LONG Error;
109
110   Error = RegQueryValue (KeyHandle,
111                          ValueName,
112                          &Type,
113                          NULL,
114                          &Size);
115   if ((Error != ERROR_SUCCESS) ||
116       (Type != REG_MULTI_SZ))
117     return;
118
119   Buffer = malloc (Size + StringSize);
120   if (Buffer == NULL)
121      return;
122
123   Error = RegQueryValue (KeyHandle,
124                          ValueName,
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       RegSetValue (KeyHandle,
154                    ValueName,
155                    REG_MULTI_SZ,
156                    (PUCHAR)Buffer,
157                    Total);
158     }
159
160 done:
161   free (Buffer);
162 }
163
164
165 /***********************************************************************
166  *            do_reg_operation
167  *
168  * Perform an add/delete registry operation depending on the flags.
169  */
170 static BOOL
171 do_reg_operation(HKEY KeyHandle,
172                  PCHAR ValueName,
173                  PINFCONTEXT Context,
174                  ULONG Flags)
175 {
176   CHAR EmptyStr = (CHAR)0;
177   ULONG Type;
178   ULONG Size;
179   LONG Error;
180
181   if (Flags & FLG_ADDREG_DELVAL)  /* deletion */
182     {
183       if (ValueName)
184         {
185           RegDeleteValue (KeyHandle,
186                           ValueName);
187         }
188       else
189         {
190           RegDeleteKey (KeyHandle,
191                         NULL);
192         }
193
194       return TRUE;
195     }
196
197   if (Flags & FLG_ADDREG_KEYONLY)
198     return TRUE;
199
200   if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY))
201     {
202       Error = RegQueryValue (KeyHandle,
203                              ValueName,
204                              NULL,
205                              NULL,
206                              NULL);
207       if ((Error == ERROR_SUCCESS) &&
208           (Flags & FLG_ADDREG_NOCLOBBER))
209         return TRUE;
210
211       if ((Error != ERROR_SUCCESS) &&
212           (Flags & FLG_ADDREG_OVERWRITEONLY))
213         return TRUE;
214     }
215
216   switch (Flags & FLG_ADDREG_TYPE_MASK)
217     {
218       case FLG_ADDREG_TYPE_SZ:
219         Type = REG_SZ;
220         break;
221
222       case FLG_ADDREG_TYPE_MULTI_SZ:
223         Type = REG_MULTI_SZ;
224         break;
225
226       case FLG_ADDREG_TYPE_EXPAND_SZ:
227         Type = REG_EXPAND_SZ;
228         break;
229
230       case FLG_ADDREG_TYPE_BINARY:
231         Type = REG_BINARY;
232         break;
233
234       case FLG_ADDREG_TYPE_DWORD:
235         Type = REG_DWORD;
236         break;
237
238       case FLG_ADDREG_TYPE_NONE:
239         Type = REG_NONE;
240         break;
241
242       default:
243         Type = Flags >> 16;
244         break;
245     }
246
247   if (!(Flags & FLG_ADDREG_BINVALUETYPE) ||
248       (Type == REG_DWORD && InfGetFieldCount (Context) == 5))
249     {
250       PCHAR Str = NULL;
251
252       if (Type == REG_MULTI_SZ)
253         {
254           if (!InfGetMultiSzField (Context, 5, NULL, 0, &Size))
255             Size = 0;
256
257           if (Size)
258             {
259               Str = malloc (Size);
260               if (Str == NULL)
261                 return FALSE;
262
263               InfGetMultiSzField (Context, 5, Str, Size, NULL);
264             }
265
266           if (Flags & FLG_ADDREG_APPEND)
267             {
268               if (Str == NULL)
269                 return TRUE;
270
271               AppendMultiSzValue (KeyHandle,
272                                   ValueName,
273                                   Str,
274                                   Size);
275
276               free (Str);
277               return TRUE;
278             }
279           /* else fall through to normal string handling */
280         }
281       else
282         {
283           if (!InfGetStringField (Context, 5, NULL, 0, &Size))
284             Size = 0;
285
286           if (Size)
287             {
288               Str = malloc (Size);
289               if (Str == NULL)
290                 return FALSE;
291
292               InfGetStringField (Context, 5, Str, Size, NULL);
293             }
294         }
295
296       if (Type == REG_DWORD)
297         {
298           ULONG dw = Str ? strtoul (Str, NULL, 0) : 0;
299
300           DPRINT("setting dword %s to %lx\n", ValueName, dw);
301
302           RegSetValue (KeyHandle,
303                        ValueName,
304                        Type,
305                        (PVOID)&dw,
306                        sizeof(ULONG));
307         }
308       else
309         {
310           DPRINT ("setting value %s to %s\n", ValueName, Str);
311
312           if (Str)
313             {
314               RegSetValue (KeyHandle,
315                            ValueName,
316                            Type,
317                            (PVOID)Str,
318                            Size);
319             }
320           else
321             {
322               RegSetValue (KeyHandle,
323                            ValueName,
324                            Type,
325                            (PVOID)&EmptyStr,
326                            sizeof(CHAR));
327             }
328         }
329       free (Str);
330     }
331   else  /* get the binary data */
332     {
333       PUCHAR Data = NULL;
334
335       if (!InfGetBinaryField (Context, 5, NULL, 0, &Size))
336         Size = 0;
337
338       if (Size)
339         {
340           Data = malloc (Size);
341           if (Data == NULL)
342             return FALSE;
343
344           DPRINT("setting binary data %s len %lu\n", ValueName, Size);
345           InfGetBinaryField (Context, 5, Data, Size, NULL);
346         }
347
348       RegSetValue (KeyHandle,
349                    ValueName,
350                    Type,
351                    (PVOID)Data,
352                    Size);
353
354       free (Data);
355     }
356
357   return TRUE;
358 }
359
360
361 /***********************************************************************
362  *            registry_callback
363  *
364  * Called once for each AddReg and DelReg entry in a given section.
365  */
366 static BOOL
367 registry_callback (HINF hInf, PCHAR Section, BOOL Delete)
368 {
369   CHAR Buffer[MAX_INF_STRING_LENGTH];
370   PCHAR ValuePtr;
371   ULONG Flags;
372   ULONG Length;
373
374   INFCONTEXT Context;
375   HKEY KeyHandle;
376   BOOL Ok;
377
378
379   Ok = InfFindFirstLine (hInf, Section, NULL, &Context);
380   if (!Ok)
381     return FALSE;
382
383   for (;Ok; Ok = InfFindNextLine (&Context, &Context))
384     {
385       /* get root */
386       if (!InfGetStringField (&Context, 1, Buffer, MAX_INF_STRING_LENGTH, NULL))
387         continue;
388       if (!GetRootKey (Buffer))
389         continue;
390
391       /* get key */
392       Length = strlen (Buffer);
393       if (!InfGetStringField (&Context, 2, Buffer + Length, MAX_INF_STRING_LENGTH - Length, NULL))
394         *Buffer = 0;
395
396       DPRINT("KeyName: <%s>\n", Buffer);
397
398       /* get flags */
399       if (!InfGetIntField (&Context, 4, (PLONG)&Flags))
400         Flags = 0;
401
402       DPRINT("Flags: %lx\n", Flags);
403
404       if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
405         {
406           if (RegOpenKey (NULL, Buffer, &KeyHandle) != ERROR_SUCCESS)
407             {
408               DPRINT("RegOpenKey(%s) failed\n", Buffer);
409               continue;  /* ignore if it doesn't exist */
410             }
411         }
412       else
413         {
414           if (RegCreateKey (NULL, Buffer, &KeyHandle) != ERROR_SUCCESS)
415             {
416               DPRINT("RegCreateKey(%s) failed\n", Buffer);
417               continue;
418             }
419         }
420
421       /* get value name */
422       if (InfGetStringField (&Context, 3, Buffer, MAX_INF_STRING_LENGTH, NULL))
423         {
424           ValuePtr = Buffer;
425         }
426       else
427         {
428           ValuePtr = NULL;
429         }
430
431       /* and now do it */
432       if (!do_reg_operation (KeyHandle, ValuePtr, &Context, Flags))
433         {
434           return FALSE;
435         }
436     }
437
438   return TRUE;
439 }
440
441
442 BOOL
443 ImportRegistryFile(PCHAR FileName,
444                    PCHAR Section,
445                    BOOL Delete)
446 {
447   HINF hInf;
448   ULONG ErrorLine;
449
450   /* Load inf file from install media. */
451   if (!InfOpenFile(&hInf, FileName, &ErrorLine))
452     {
453       DPRINT1 ("InfOpenFile() failed\n");
454       return FALSE;
455     }
456
457   if (!registry_callback (hInf, "AddReg", FALSE))
458     {
459       DPRINT1 ("registry_callback() failed\n");
460     }
461
462   InfCloseFile (hInf);
463
464   return TRUE;
465 }
466
467 /* EOF */