urlmon: Don't create stgmed_obj for binding to object.
[wine] / programs / regedit / regproc.c
1 /*
2  * Registry processing routines. Routines, common for registry
3  * processing frontends.
4  *
5  * Copyright 1999 Sylvain St-Germain
6  * Copyright 2002 Andriy Palamarchuk
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include <limits.h>
24 #include <stdio.h>
25 #include <windows.h>
26 #include <winnt.h>
27 #include <winreg.h>
28 #include <assert.h>
29 #include "regproc.h"
30
31 #define REG_VAL_BUF_SIZE        4096
32
33 /* maximal number of characters in hexadecimal data line,
34    not including '\' character */
35 #define REG_FILE_HEX_LINE_LEN   76
36
37 static const CHAR *reg_class_names[] = {
38                                      "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CLASSES_ROOT",
39                                      "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA"
40                                  };
41
42 #define REG_CLASS_NUMBER (sizeof(reg_class_names) / sizeof(reg_class_names[0]))
43
44 static HKEY reg_class_keys[REG_CLASS_NUMBER] = {
45             HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
46             HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA
47         };
48
49 /* return values */
50 #define NOT_ENOUGH_MEMORY     1
51 #define IO_ERROR              2
52
53 /* processing macros */
54
55 /* common check of memory allocation results */
56 #define CHECK_ENOUGH_MEMORY(p) \
57 if (!(p)) \
58 { \
59     fprintf(stderr,"%s: file %s, line %d: Not enough memory\n", \
60             getAppName(), __FILE__, __LINE__); \
61     exit(NOT_ENOUGH_MEMORY); \
62 }
63
64 /******************************************************************************
65  * Converts a hex representation of a DWORD into a DWORD.
66  */
67 static BOOL convertHexToDWord(char* str, DWORD *dw)
68 {
69     char dummy;
70     if (strlen(str) > 8 || sscanf(str, "%x%c", dw, &dummy) != 1) {
71         fprintf(stderr,"%s: ERROR, invalid hex value\n", getAppName());
72         return FALSE;
73     }
74     return TRUE;
75 }
76
77 /******************************************************************************
78  * Converts a hex comma separated values list into a binary string.
79  */
80 static BYTE* convertHexCSVToHex(char *str, DWORD *size)
81 {
82     char *s;
83     BYTE *d, *data;
84
85     /* The worst case is 1 digit + 1 comma per byte */
86     *size=(strlen(str)+1)/2;
87     data=HeapAlloc(GetProcessHeap(), 0, *size);
88     CHECK_ENOUGH_MEMORY(data);
89
90     s = str;
91     d = data;
92     *size=0;
93     while (*s != '\0') {
94         UINT wc;
95         char *end;
96
97         wc = strtoul(s,&end,16);
98         if (end == s || wc > 0xff || (*end && *end != ',')) {
99             fprintf(stderr,"%s: ERROR converting CSV hex stream. Invalid value at '%s'\n",
100                     getAppName(), s);
101             HeapFree(GetProcessHeap(), 0, data);
102             return NULL;
103         }
104         *d++ =(BYTE)wc;
105         (*size)++;
106         if (*end) end++;
107         s = end;
108     }
109
110     return data;
111 }
112
113 /******************************************************************************
114  * This function returns the HKEY associated with the data type encoded in the
115  * value.  It modifies the input parameter (key value) in order to skip this
116  * "now useless" data type information.
117  *
118  * Note: Updated based on the algorithm used in 'server/registry.c'
119  */
120 static DWORD getDataType(LPSTR *lpValue, DWORD* parse_type)
121 {
122     struct data_type { const char *tag; int len; int type; int parse_type; };
123
124     static const struct data_type data_types[] = {                   /* actual type */  /* type to assume for parsing */
125                 { "\"",        1,   REG_SZ,              REG_SZ },
126                 { "str:\"",    5,   REG_SZ,              REG_SZ },
127                 { "str(2):\"", 8,   REG_EXPAND_SZ,       REG_SZ },
128                 { "hex:",      4,   REG_BINARY,          REG_BINARY },
129                 { "dword:",    6,   REG_DWORD,           REG_DWORD },
130                 { "hex(",      4,   -1,                  REG_BINARY },
131                 { NULL,        0,    0,                  0 }
132             };
133
134     const struct data_type *ptr;
135     int type;
136
137     for (ptr = data_types; ptr->tag; ptr++) {
138         if (memcmp( ptr->tag, *lpValue, ptr->len ))
139             continue;
140
141         /* Found! */
142         *parse_type = ptr->parse_type;
143         type=ptr->type;
144         *lpValue+=ptr->len;
145         if (type == -1) {
146             char* end;
147             /* "hex(xx):" is special */
148             type = (int)strtoul( *lpValue , &end, 16 );
149             if (**lpValue=='\0' || *end!=')' || *(end+1)!=':') {
150                 type=REG_NONE;
151             } else {
152                 *lpValue=end+2;
153             }
154         }
155         return type;
156     }
157     *parse_type=REG_NONE;
158     return REG_NONE;
159 }
160
161 /******************************************************************************
162  * Replaces escape sequences with the characters.
163  */
164 static void REGPROC_unescape_string(LPSTR str)
165 {
166     int str_idx = 0;            /* current character under analysis */
167     int val_idx = 0;            /* the last character of the unescaped string */
168     int len = strlen(str);
169     for (str_idx = 0; str_idx < len; str_idx++, val_idx++) {
170         if (str[str_idx] == '\\') {
171             str_idx++;
172             switch (str[str_idx]) {
173             case 'n':
174                 str[val_idx] = '\n';
175                 break;
176             case '\\':
177             case '"':
178                 str[val_idx] = str[str_idx];
179                 break;
180             default:
181                 fprintf(stderr,"Warning! Unrecognized escape sequence: \\%c'\n",
182                         str[str_idx]);
183                 str[val_idx] = str[str_idx];
184                 break;
185             }
186         } else {
187             str[val_idx] = str[str_idx];
188         }
189     }
190     str[val_idx] = '\0';
191 }
192
193 /******************************************************************************
194  * Parses HKEY_SOME_ROOT\some\key\path to get the root key handle and
195  * extract the key path (what comes after the first '\').
196  */
197 static BOOL parseKeyName(LPSTR lpKeyName, HKEY *hKey, LPSTR *lpKeyPath)
198 {
199     LPSTR lpSlash;
200     unsigned int i, len;
201
202     if (lpKeyName == NULL)
203         return FALSE;
204
205     lpSlash = strchr(lpKeyName, '\\');
206     if (lpSlash)
207     {
208         len = lpSlash-lpKeyName;
209     }
210     else
211     {
212         len = strlen(lpKeyName);
213         lpSlash = lpKeyName+len;
214     }
215     *hKey = NULL;
216     for (i = 0; i < REG_CLASS_NUMBER; i++) {
217         if (strncmp(lpKeyName, reg_class_names[i], len) == 0 &&
218             len == strlen(reg_class_names[i])) {
219             *hKey = reg_class_keys[i];
220             break;
221         }
222     }
223     if (*hKey == NULL)
224         return FALSE;
225
226     if (*lpSlash != '\0')
227         lpSlash++;
228     *lpKeyPath = lpSlash;
229     return TRUE;
230 }
231
232 /* Globals used by the setValue() & co */
233 static LPSTR currentKeyName;
234 static HKEY  currentKeyHandle = NULL;
235
236 /******************************************************************************
237  * Sets the value with name val_name to the data in val_data for the currently
238  * opened key.
239  *
240  * Parameters:
241  * val_name - name of the registry value
242  * val_data - registry value data
243  */
244 static LONG setValue(LPSTR val_name, LPSTR val_data)
245 {
246     LONG res;
247     DWORD  dwDataType, dwParseType;
248     LPBYTE lpbData;
249     DWORD  dwData, dwLen;
250
251     if ( (val_name == NULL) || (val_data == NULL) )
252         return ERROR_INVALID_PARAMETER;
253
254     if (strcmp(val_data, "-") == 0)
255     {
256         res=RegDeleteValue(currentKeyHandle,val_name);
257         return (res == ERROR_FILE_NOT_FOUND ? ERROR_SUCCESS : res);
258     }
259
260     /* Get the data type stored into the value field */
261     dwDataType = getDataType(&val_data, &dwParseType);
262
263     if (dwParseType == REG_SZ)          /* no conversion for string */
264     {
265         REGPROC_unescape_string(val_data);
266         /* Compute dwLen after REGPROC_unescape_string because it may
267          * have changed the string length and we don't want to store
268          * the extra garbage in the registry.
269          */
270         dwLen = strlen(val_data);
271         if (dwLen>0 && val_data[dwLen-1]=='"')
272         {
273             dwLen--;
274             val_data[dwLen]='\0';
275         }
276         lpbData = (BYTE*) val_data;
277     }
278     else if (dwParseType == REG_DWORD)  /* Convert the dword types */
279     {
280         if (!convertHexToDWord(val_data, &dwData))
281             return ERROR_INVALID_DATA;
282         lpbData = (BYTE*)&dwData;
283         dwLen = sizeof(dwData);
284     }
285     else if (dwParseType == REG_BINARY) /* Convert the binary data */
286     {
287         lpbData = convertHexCSVToHex(val_data, &dwLen);
288         if (!lpbData)
289             return ERROR_INVALID_DATA;
290     }
291     else                                /* unknown format */
292     {
293         fprintf(stderr,"%s: ERROR, unknown data format\n", getAppName());
294         return ERROR_INVALID_DATA;
295     }
296
297     res = RegSetValueEx(
298                currentKeyHandle,
299                val_name,
300                0,                  /* Reserved */
301                dwDataType,
302                lpbData,
303                dwLen);
304     if (dwParseType == REG_BINARY)
305         HeapFree(GetProcessHeap(), 0, lpbData);
306     return res;
307 }
308
309 /******************************************************************************
310  * A helper function for processRegEntry() that opens the current key.
311  * That key must be closed by calling closeKey().
312  */
313 static LONG openKey(LPSTR stdInput)
314 {
315     HKEY keyClass;
316     LPSTR keyPath;
317     DWORD dwDisp;
318     LONG res;
319
320     /* Sanity checks */
321     if (stdInput == NULL)
322         return ERROR_INVALID_PARAMETER;
323
324     /* Get the registry class */
325     if (!parseKeyName(stdInput, &keyClass, &keyPath))
326         return ERROR_INVALID_PARAMETER;
327
328     res = RegCreateKeyEx(
329                keyClass,                 /* Class     */
330                keyPath,                  /* Sub Key   */
331                0,                        /* MUST BE 0 */
332                NULL,                     /* object type */
333                REG_OPTION_NON_VOLATILE,  /* option, REG_OPTION_NON_VOLATILE ... */
334                KEY_ALL_ACCESS,           /* access mask, KEY_ALL_ACCESS */
335                NULL,                     /* security attribute */
336                &currentKeyHandle,        /* result */
337                &dwDisp);                 /* disposition, REG_CREATED_NEW_KEY or
338                                                         REG_OPENED_EXISTING_KEY */
339
340     if (res == ERROR_SUCCESS)
341     {
342         currentKeyName = HeapAlloc(GetProcessHeap(), 0, strlen(stdInput)+1);
343         CHECK_ENOUGH_MEMORY(currentKeyName);
344         strcpy(currentKeyName, stdInput);
345     }
346     else
347     {
348         currentKeyHandle = NULL;
349     }
350
351     return res;
352
353 }
354
355 /******************************************************************************
356  * Close the currently opened key.
357  */
358 static void closeKey(void)
359 {
360     if (currentKeyHandle)
361     {
362         HeapFree(GetProcessHeap(), 0, currentKeyName);
363         RegCloseKey(currentKeyHandle);
364         currentKeyHandle = NULL;
365     }
366 }
367
368 /******************************************************************************
369  * This function is a wrapper for the setValue function.  It prepares the
370  * land and cleans the area once completed.
371  * Note: this function modifies the line parameter.
372  *
373  * line - registry file unwrapped line. Should have the registry value name and
374  *      complete registry value data.
375  */
376 static void processSetValue(LPSTR line)
377 {
378     LPSTR val_name;                   /* registry value name   */
379     LPSTR val_data;                   /* registry value data   */
380
381     int line_idx = 0;                 /* current character under analysis */
382     LONG res;
383
384     /* get value name */
385     if (line[line_idx] == '@' && line[line_idx + 1] == '=') {
386         line[line_idx] = '\0';
387         val_name = line;
388         line_idx++;
389     } else if (line[line_idx] == '\"') {
390         line_idx++;
391         val_name = line + line_idx;
392         while (TRUE) {
393             if (line[line_idx] == '\\')   /* skip escaped character */
394             {
395                 line_idx += 2;
396             } else {
397                 if (line[line_idx] == '\"') {
398                     line[line_idx] = '\0';
399                     line_idx++;
400                     break;
401                 } else {
402                     line_idx++;
403                 }
404             }
405         }
406         if (line[line_idx] != '=') {
407             line[line_idx] = '\"';
408             fprintf(stderr,"Warning! unrecognized line:\n%s\n", line);
409             return;
410         }
411
412     } else {
413         fprintf(stderr,"Warning! unrecognized line:\n%s\n", line);
414         return;
415     }
416     line_idx++;                   /* skip the '=' character */
417     val_data = line + line_idx;
418
419     REGPROC_unescape_string(val_name);
420     res = setValue(val_name, val_data);
421     if ( res != ERROR_SUCCESS )
422         fprintf(stderr,"%s: ERROR Key %s not created. Value: %s, Data: %s\n",
423                 getAppName(),
424                 currentKeyName,
425                 val_name,
426                 val_data);
427 }
428
429 /******************************************************************************
430  * This function receives the currently read entry and performs the
431  * corresponding action.
432  */
433 static void processRegEntry(LPSTR stdInput)
434 {
435     /*
436      * We encountered the end of the file, make sure we
437      * close the opened key and exit
438      */
439     if (stdInput == NULL) {
440         closeKey();
441         return;
442     }
443
444     if      ( stdInput[0] == '[')      /* We are reading a new key */
445     {
446         LPSTR keyEnd;
447         closeKey();                    /* Close the previous key */
448
449         /* Get rid of the square brackets */
450         stdInput++;
451         keyEnd = strrchr(stdInput, ']');
452         if (keyEnd)
453             *keyEnd='\0';
454
455         /* delete the key if we encounter '-' at the start of reg key */
456         if ( stdInput[0] == '-')
457             delete_registry_key(stdInput+1);
458         else if ( openKey(stdInput) != ERROR_SUCCESS )
459             fprintf(stderr,"%s: setValue failed to open key %s\n",
460                     getAppName(), stdInput);
461     } else if( currentKeyHandle &&
462                (( stdInput[0] == '@') || /* reading a default @=data pair */
463                 ( stdInput[0] == '\"'))) /* reading a new value=data pair */
464     {
465         processSetValue(stdInput);
466     } else
467     {
468         /* Since we are assuming that the file format is valid we must be
469          * reading a blank line which indicates the end of this key processing
470          */
471         closeKey();
472     }
473 }
474
475 /******************************************************************************
476  * Processes a registry file.
477  * Correctly processes comments (in # form), line continuation.
478  *
479  * Parameters:
480  *   in - input stream to read from
481  */
482 void processRegLines(FILE *in)
483 {
484     LPSTR line           = NULL;  /* line read from input stream */
485     ULONG lineSize       = REG_VAL_BUF_SIZE;
486     BYTE  uni[2];
487
488     line = HeapAlloc(GetProcessHeap(), 0, lineSize);
489     CHECK_ENOUGH_MEMORY(line);
490
491     if (fread(uni, 2, 1, in) == 1) {
492         if (uni[0] == 0xff && uni[1] == 0xfe) {
493             printf("Trying to import from a unicode file: this isn't supported yet.\n"
494                    "Please use export as Win 9x/NT4 files from native regedit\n");
495             return;
496         }
497         fseek(in, -2, SEEK_CUR);
498     }
499     while (!feof(in)) {
500         LPSTR s; /* The pointer into line for where the current fgets should read */
501         s = line;
502         for (;;) {
503             size_t size_remaining;
504             int size_to_get;
505             char *s_eol; /* various local uses */
506
507             /* Do we need to expand the buffer ? */
508             assert (s >= line && s <= line + lineSize);
509             size_remaining = lineSize - (s-line);
510             if (size_remaining < 2) /* room for 1 character and the \0 */
511             {
512                 char *new_buffer;
513                 size_t new_size = lineSize + REG_VAL_BUF_SIZE;
514                 if (new_size > lineSize) /* no arithmetic overflow */
515                     new_buffer = HeapReAlloc (GetProcessHeap(), 0, line, new_size);
516                 else
517                     new_buffer = NULL;
518                 CHECK_ENOUGH_MEMORY(new_buffer);
519                 line = new_buffer;
520                 s = line + lineSize - size_remaining;
521                 lineSize = new_size;
522                 size_remaining = lineSize - (s-line);
523             }
524
525             /* Get as much as possible into the buffer, terminated either by
526              * eof, error, eol or getting the maximum amount.  Abort on error.
527              */
528             size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
529             if (NULL == fgets (s, size_to_get, in)) {
530                 if (ferror(in)) {
531                     perror ("While reading input");
532                     exit (IO_ERROR);
533                 } else {
534                     assert (feof(in));
535                     *s = '\0';
536                     /* It is not clear to me from the definition that the
537                      * contents of the buffer are well defined on detecting
538                      * an eof without managing to read anything.
539                      */
540                 }
541             }
542
543             /* If we didn't read the eol nor the eof go around for the rest */
544             s_eol = strchr (s, '\n');
545             if (!feof (in) && !s_eol) {
546                 s = strchr (s, '\0');
547                 /* It should be s + size_to_get - 1 but this is safer */
548                 continue;
549             }
550
551             /* If it is a comment line then discard it and go around again */
552             if (line [0] == '#') {
553                 s = line;
554                 continue;
555             }
556
557             /* Remove any line feed.  Leave s_eol on the \0 */
558             if (s_eol) {
559                 *s_eol = '\0';
560                 if (s_eol > line && *(s_eol-1) == '\r')
561                     *--s_eol = '\0';
562             } else
563                 s_eol = strchr (s, '\0');
564
565             /* If there is a concatenating \\ then go around again */
566             if (s_eol > line && *(s_eol-1) == '\\') {
567                 int c;
568                 s = s_eol-1;
569                 /* The following error protection could be made more self-
570                  * correcting but I thought it not worth trying.
571                  */
572                 if ((c = fgetc (in)) == EOF || c != ' ' ||
573                         (c = fgetc (in)) == EOF || c != ' ')
574                     fprintf(stderr,"%s: ERROR - invalid continuation.\n",
575                             getAppName());
576                 continue;
577             }
578
579             break; /* That is the full virtual line */
580         }
581
582         processRegEntry(line);
583     }
584     processRegEntry(NULL);
585
586     HeapFree(GetProcessHeap(), 0, line);
587 }
588
589 /****************************************************************************
590  * REGPROC_print_error
591  *
592  * Print the message for GetLastError
593  */
594
595 static void REGPROC_print_error(void)
596 {
597     LPVOID lpMsgBuf;
598     DWORD error_code;
599     int status;
600
601     error_code = GetLastError ();
602     status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
603                            NULL, error_code, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
604     if (!status) {
605         fprintf(stderr,"%s: Cannot display message for error %d, status %d\n",
606                 getAppName(), error_code, GetLastError());
607         exit(1);
608     }
609     puts(lpMsgBuf);
610     LocalFree((HLOCAL)lpMsgBuf);
611     exit(1);
612 }
613
614 /******************************************************************************
615  * Checks whether the buffer has enough room for the string or required size.
616  * Resizes the buffer if necessary.
617  *
618  * Parameters:
619  * buffer - pointer to a buffer for string
620  * len - current length of the buffer in characters.
621  * required_len - length of the string to place to the buffer in characters.
622  *   The length does not include the terminating null character.
623  */
624 static void REGPROC_resize_char_buffer(CHAR **buffer, DWORD *len, DWORD required_len)
625 {
626     required_len++;
627     if (required_len > *len) {
628         *len = required_len;
629         if (!*buffer)
630             *buffer = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(**buffer));
631         else
632             *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *len * sizeof(**buffer));
633         CHECK_ENOUGH_MEMORY(*buffer);
634     }
635 }
636
637 /******************************************************************************
638  * Prints string str to file
639  */
640 static void REGPROC_export_string(FILE *file, CHAR *str)
641 {
642     size_t len = strlen(str);
643     size_t i;
644
645     /* escaping characters */
646     for (i = 0; i < len; i++) {
647         CHAR c = str[i];
648         switch (c) {
649         case '\\':
650             fputs("\\\\", file);
651             break;
652         case '\"':
653             fputs("\\\"", file);
654             break;
655         case '\n':
656             fputs("\\\n", file);
657             break;
658         default:
659             fputc(c, file);
660             break;
661         }
662     }
663 }
664
665 /******************************************************************************
666  * Writes contents of the registry key to the specified file stream.
667  *
668  * Parameters:
669  * file - writable file stream to export registry branch to.
670  * key - registry branch to export.
671  * reg_key_name_buf - name of the key with registry class.
672  *      Is resized if necessary.
673  * reg_key_name_len - length of the buffer for the registry class in characters.
674  * val_name_buf - buffer for storing value name.
675  *      Is resized if necessary.
676  * val_name_len - length of the buffer for storing value names in characters.
677  * val_buf - buffer for storing values while extracting.
678  *      Is resized if necessary.
679  * val_size - size of the buffer for storing values in bytes.
680  */
681 static void export_hkey(FILE *file, HKEY key,
682                  CHAR **reg_key_name_buf, DWORD *reg_key_name_len,
683                  CHAR **val_name_buf, DWORD *val_name_len,
684                  BYTE **val_buf, DWORD *val_size)
685 {
686     DWORD max_sub_key_len;
687     DWORD max_val_name_len;
688     DWORD max_val_size;
689     DWORD curr_len;
690     DWORD i;
691     BOOL more_data;
692     LONG ret;
693
694     /* get size information and resize the buffers if necessary */
695     if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL,
696                         &max_sub_key_len, NULL,
697                         NULL, &max_val_name_len, &max_val_size, NULL, NULL
698                        ) != ERROR_SUCCESS) {
699         REGPROC_print_error();
700     }
701     curr_len = strlen(*reg_key_name_buf);
702     REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_len,
703                                max_sub_key_len + curr_len + 1);
704     REGPROC_resize_char_buffer(val_name_buf, val_name_len,
705                                max_val_name_len);
706     if (max_val_size > *val_size) {
707         *val_size = max_val_size;
708         if (!*val_buf) *val_buf = HeapAlloc(GetProcessHeap(), 0, *val_size);
709         else *val_buf = HeapReAlloc(GetProcessHeap(), 0, *val_buf, *val_size);
710         CHECK_ENOUGH_MEMORY(val_buf);
711     }
712
713     /* output data for the current key */
714     fputs("\n[", file);
715     fputs(*reg_key_name_buf, file);
716     fputs("]\n", file);
717     /* print all the values */
718     i = 0;
719     more_data = TRUE;
720     while(more_data) {
721         DWORD value_type;
722         DWORD val_name_len1 = *val_name_len;
723         DWORD val_size1 = *val_size;
724         ret = RegEnumValue(key, i, *val_name_buf, &val_name_len1, NULL,
725                            &value_type, *val_buf, &val_size1);
726         if (ret != ERROR_SUCCESS) {
727             more_data = FALSE;
728             if (ret != ERROR_NO_MORE_ITEMS) {
729                 REGPROC_print_error();
730             }
731         } else {
732             i++;
733
734             if ((*val_name_buf)[0]) {
735                 fputs("\"", file);
736                 REGPROC_export_string(file, *val_name_buf);
737                 fputs("\"=", file);
738             } else {
739                 fputs("@=", file);
740             }
741
742             switch (value_type) {
743             case REG_SZ:
744             case REG_EXPAND_SZ:
745                 fputs("\"", file);
746                 REGPROC_export_string(file, (char*) *val_buf);
747                 fputs("\"\n", file);
748                 break;
749
750             case REG_DWORD:
751                 fprintf(file, "dword:%08x\n", *((DWORD *)*val_buf));
752                 break;
753
754             default:
755                 fprintf(stderr,"%s: warning - unsupported registry format '%d', "
756                         "treat as binary\n",
757                         getAppName(), value_type);
758                 fprintf(stderr,"key name: \"%s\"\n", *reg_key_name_buf);
759                 fprintf(stderr,"value name:\"%s\"\n\n", *val_name_buf);
760                 /* falls through */
761             case REG_MULTI_SZ:
762                 /* falls through */
763             case REG_BINARY: {
764                     DWORD i1;
765                     const CHAR *hex_prefix;
766                     CHAR buf[20];
767                     int cur_pos;
768
769                     if (value_type == REG_BINARY) {
770                         hex_prefix = "hex:";
771                     } else {
772                         hex_prefix = buf;
773                         sprintf(buf, "hex(%d):", value_type);
774                     }
775
776                     /* position of where the next character will be printed */
777                     /* NOTE: yes, strlen("hex:") is used even for hex(x): */
778                     cur_pos = strlen("\"\"=") + strlen("hex:") +
779                               strlen(*val_name_buf);
780
781                     fputs(hex_prefix, file);
782                     for (i1 = 0; i1 < val_size1; i1++) {
783                         fprintf(file, "%02x", (unsigned int)(*val_buf)[i1]);
784                         if (i1 + 1 < val_size1) {
785                             fputs(",", file);
786                         }
787                         cur_pos += 3;
788
789                         /* wrap the line */
790                         if (cur_pos > REG_FILE_HEX_LINE_LEN) {
791                             fputs("\\\n  ", file);
792                             cur_pos = 2;
793                         }
794                     }
795                     fputs("\n", file);
796                     break;
797                 }
798             }
799         }
800     }
801
802     i = 0;
803     more_data = TRUE;
804     (*reg_key_name_buf)[curr_len] = '\\';
805     while(more_data) {
806         DWORD buf_len = *reg_key_name_len - curr_len;
807
808         ret = RegEnumKeyEx(key, i, *reg_key_name_buf + curr_len + 1, &buf_len,
809                            NULL, NULL, NULL, NULL);
810         if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
811             more_data = FALSE;
812             if (ret != ERROR_NO_MORE_ITEMS) {
813                 REGPROC_print_error();
814             }
815         } else {
816             HKEY subkey;
817
818             i++;
819             if (RegOpenKey(key, *reg_key_name_buf + curr_len + 1,
820                            &subkey) == ERROR_SUCCESS) {
821                 export_hkey(file, subkey, reg_key_name_buf, reg_key_name_len,
822                             val_name_buf, val_name_len, val_buf, val_size);
823                 RegCloseKey(subkey);
824             } else {
825                 REGPROC_print_error();
826             }
827         }
828     }
829     (*reg_key_name_buf)[curr_len] = '\0';
830 }
831
832 /******************************************************************************
833  * Open file for export.
834  */
835 static FILE *REGPROC_open_export_file(CHAR *file_name)
836 {
837     FILE *file;
838
839     if (strcmp(file_name,"-")==0)
840         file=stdout;
841     else
842     {
843         file = fopen(file_name, "w");
844         if (!file) {
845             perror("");
846             fprintf(stderr,"%s: Can't open file \"%s\"\n", getAppName(), file_name);
847             exit(1);
848         }
849     }
850     fputs("REGEDIT4\n", file);
851     return file;
852 }
853
854 /******************************************************************************
855  * Writes contents of the registry key to the specified file stream.
856  *
857  * Parameters:
858  * file_name - name of a file to export registry branch to.
859  * reg_key_name - registry branch to export. The whole registry is exported if
860  *      reg_key_name is NULL or contains an empty string.
861  */
862 BOOL export_registry_key(CHAR *file_name, CHAR *reg_key_name)
863 {
864     CHAR *reg_key_name_buf;
865     CHAR *val_name_buf;
866     BYTE *val_buf;
867     DWORD reg_key_name_len = KEY_MAX_LEN;
868     DWORD val_name_len = KEY_MAX_LEN;
869     DWORD val_size = REG_VAL_BUF_SIZE;
870     FILE *file = NULL;
871
872     reg_key_name_buf = HeapAlloc(GetProcessHeap(), 0,
873                                  reg_key_name_len  * sizeof(*reg_key_name_buf));
874     val_name_buf = HeapAlloc(GetProcessHeap(), 0,
875                              val_name_len * sizeof(*val_name_buf));
876     val_buf = HeapAlloc(GetProcessHeap(), 0, val_size);
877     CHECK_ENOUGH_MEMORY(reg_key_name_buf && val_name_buf && val_buf);
878
879     if (reg_key_name && reg_key_name[0]) {
880         HKEY reg_key_class;
881         CHAR *branch_name;
882         HKEY key;
883
884         REGPROC_resize_char_buffer(&reg_key_name_buf, &reg_key_name_len,
885                                    strlen(reg_key_name));
886         strcpy(reg_key_name_buf, reg_key_name);
887
888         /* open the specified key */
889         if (!parseKeyName(reg_key_name, &reg_key_class, &branch_name)) {
890             fprintf(stderr,"%s: Incorrect registry class specification in '%s'\n",
891                     getAppName(), reg_key_name);
892             exit(1);
893         }
894         if (!branch_name[0]) {
895             /* no branch - registry class is specified */
896             file = REGPROC_open_export_file(file_name);
897             export_hkey(file, reg_key_class,
898                         &reg_key_name_buf, &reg_key_name_len,
899                         &val_name_buf, &val_name_len,
900                         &val_buf, &val_size);
901         } else if (RegOpenKey(reg_key_class, branch_name, &key) == ERROR_SUCCESS) {
902             file = REGPROC_open_export_file(file_name);
903             export_hkey(file, key,
904                         &reg_key_name_buf, &reg_key_name_len,
905                         &val_name_buf, &val_name_len,
906                         &val_buf, &val_size);
907             RegCloseKey(key);
908         } else {
909             fprintf(stderr,"%s: Can't export. Registry key '%s' does not exist!\n",
910                     getAppName(), reg_key_name);
911             REGPROC_print_error();
912         }
913     } else {
914         unsigned int i;
915
916         /* export all registry classes */
917         file = REGPROC_open_export_file(file_name);
918         for (i = 0; i < REG_CLASS_NUMBER; i++) {
919             /* do not export HKEY_CLASSES_ROOT */
920             if (reg_class_keys[i] != HKEY_CLASSES_ROOT &&
921                     reg_class_keys[i] != HKEY_CURRENT_USER &&
922                     reg_class_keys[i] != HKEY_CURRENT_CONFIG &&
923                     reg_class_keys[i] != HKEY_DYN_DATA) {
924                 strcpy(reg_key_name_buf, reg_class_names[i]);
925                 export_hkey(file, reg_class_keys[i],
926                             &reg_key_name_buf, &reg_key_name_len,
927                             &val_name_buf, &val_name_len,
928                             &val_buf, &val_size);
929             }
930         }
931     }
932
933     if (file) {
934         fclose(file);
935     }
936     HeapFree(GetProcessHeap(), 0, reg_key_name);
937     HeapFree(GetProcessHeap(), 0, val_buf);
938     return TRUE;
939 }
940
941 /******************************************************************************
942  * Reads contents of the specified file into the registry.
943  */
944 BOOL import_registry_file(LPTSTR filename)
945 {
946     FILE* reg_file = fopen(filename, "r");
947
948     if (reg_file) {
949         processRegLines(reg_file);
950         return TRUE;
951     }
952     return FALSE;
953 }
954
955 /******************************************************************************
956  * Removes the registry key with all subkeys. Parses full key name.
957  *
958  * Parameters:
959  * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
960  *      empty, points to register key class, does not exist.
961  */
962 void delete_registry_key(CHAR *reg_key_name)
963 {
964     CHAR *key_name;
965     HKEY key_class;
966
967     if (!reg_key_name || !reg_key_name[0])
968         return;
969
970     if (!parseKeyName(reg_key_name, &key_class, &key_name)) {
971         fprintf(stderr,"%s: Incorrect registry class specification in '%s'\n",
972                 getAppName(), reg_key_name);
973         exit(1);
974     }
975     if (!*key_name) {
976         fprintf(stderr,"%s: Can't delete registry class '%s'\n",
977                 getAppName(), reg_key_name);
978         exit(1);
979     }
980
981     RegDeleteTreeA(key_class, key_name);
982 }