xref: /reactos/base/applications/regedit/regproc.c (revision b3194e32)
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  * Copyright 2008 Alexander N. Sørnes <alex@thehandofagony.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 #ifdef __REACTOS__
25 #include <fcntl.h>
26 #include <io.h>
27 #include "regedit.h"
28 #else
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <io.h>
32 #include <windows.h>
33 #include <commctrl.h>
34 
35 #include "main.h"
36 #endif
37 
38 #define REG_VAL_BUF_SIZE        4096
39 
40 static HKEY reg_class_keys[] = {
41             HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
42             HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA
43         };
44 
45 /******************************************************************************
46  * Allocates memory and converts input from multibyte to wide chars
47  * Returned string must be freed by the caller
48  */
49 static WCHAR* GetWideString(const char* strA)
50 {
51     if(strA)
52     {
53         WCHAR* strW;
54         int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0);
55 
56         strW = malloc(len * sizeof(WCHAR));
57         MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len);
58         return strW;
59     }
60     return NULL;
61 }
62 
63 /******************************************************************************
64  * Allocates memory and converts input from multibyte to wide chars
65  * Returned string must be freed by the caller
66  */
67 static WCHAR* GetWideStringN(const char* strA, int chars, DWORD *len)
68 {
69     if(strA)
70     {
71         WCHAR* strW;
72         *len = MultiByteToWideChar(CP_ACP, 0, strA, chars, NULL, 0);
73 
74         strW = malloc(*len * sizeof(WCHAR));
75         MultiByteToWideChar(CP_ACP, 0, strA, chars, strW, *len);
76         return strW;
77     }
78     *len = 0;
79     return NULL;
80 }
81 
82 /******************************************************************************
83  * Allocates memory and converts input from wide chars to multibyte
84  * Returned string must be freed by the caller
85  */
86 char* GetMultiByteString(const WCHAR* strW)
87 {
88     if(strW)
89     {
90         char* strA;
91         int len = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL);
92 
93         strA = malloc(len);
94         WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, len, NULL, NULL);
95         return strA;
96     }
97     return NULL;
98 }
99 
100 /******************************************************************************
101  * Allocates memory and converts input from wide chars to multibyte
102  * Returned string must be freed by the caller
103  */
104 static char* GetMultiByteStringN(const WCHAR* strW, int chars, DWORD* len)
105 {
106     if(strW)
107     {
108         char* strA;
109         *len = WideCharToMultiByte(CP_ACP, 0, strW, chars, NULL, 0, NULL, NULL);
110 
111         strA = malloc(*len);
112         WideCharToMultiByte(CP_ACP, 0, strW, chars, strA, *len, NULL, NULL);
113         return strA;
114     }
115     *len = 0;
116     return NULL;
117 }
118 
119 static WCHAR *(*get_line)(FILE *);
120 
121 /* parser definitions */
122 enum parser_state
123 {
124     HEADER,              /* parsing the registry file version header */
125     PARSE_WIN31_LINE,    /* parsing a Windows 3.1 registry line */
126     LINE_START,          /* at the beginning of a registry line */
127     KEY_NAME,            /* parsing a key name */
128     DELETE_KEY,          /* deleting a registry key */
129     DEFAULT_VALUE_NAME,  /* parsing a default value name */
130     QUOTED_VALUE_NAME,   /* parsing a double-quoted value name */
131     DATA_START,          /* preparing for data parsing operations */
132     DELETE_VALUE,        /* deleting a registry value */
133     DATA_TYPE,           /* parsing the registry data type */
134     STRING_DATA,         /* parsing REG_SZ data */
135     DWORD_DATA,          /* parsing DWORD data */
136     HEX_DATA,            /* parsing REG_BINARY, REG_NONE, REG_EXPAND_SZ or REG_MULTI_SZ data */
137     EOL_BACKSLASH,       /* preparing to parse multiple lines of hex data */
138     HEX_MULTILINE,       /* parsing multiple lines of hex data */
139     UNKNOWN_DATA,        /* parsing an unhandled or invalid data type */
140     SET_VALUE,           /* adding a value to the registry */
141     NB_PARSER_STATES
142 };
143 
144 struct parser
145 {
146     FILE              *file;           /* pointer to a registry file */
147     WCHAR              two_wchars[2];  /* first two characters from the encoding check */
148     BOOL               is_unicode;     /* parsing Unicode or ASCII data */
149     short int          reg_version;    /* registry file version */
150     HKEY               hkey;           /* current registry key */
151     WCHAR             *key_name;       /* current key name */
152     WCHAR             *value_name;     /* value name */
153     DWORD              parse_type;     /* generic data type for parsing */
154     DWORD              data_type;      /* data type */
155     void              *data;           /* value data */
156     DWORD              data_size;      /* size of the data (in bytes) */
157     BOOL               backslash;      /* TRUE if the current line contains a backslash */
158     enum parser_state  state;          /* current parser state */
159 };
160 
161 typedef WCHAR *(*parser_state_func)(struct parser *parser, WCHAR *pos);
162 
163 /* parser state machine functions */
164 static WCHAR *header_state(struct parser *parser, WCHAR *pos);
165 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos);
166 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos);
167 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos);
168 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos);
169 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos);
170 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos);
171 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos);
172 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos);
173 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos);
174 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos);
175 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos);
176 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos);
177 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos);
178 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos);
179 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos);
180 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos);
181 
182 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
183 {
184     header_state,              /* HEADER */
185     parse_win31_line_state,    /* PARSE_WIN31_LINE */
186     line_start_state,          /* LINE_START */
187     key_name_state,            /* KEY_NAME */
188     delete_key_state,          /* DELETE_KEY */
189     default_value_name_state,  /* DEFAULT_VALUE_NAME */
190     quoted_value_name_state,   /* QUOTED_VALUE_NAME */
191     data_start_state,          /* DATA_START */
192     delete_value_state,        /* DELETE_VALUE */
193     data_type_state,           /* DATA_TYPE */
194     string_data_state,         /* STRING_DATA */
195     dword_data_state,          /* DWORD_DATA */
196     hex_data_state,            /* HEX_DATA */
197     eol_backslash_state,       /* EOL_BACKSLASH */
198     hex_multiline_state,       /* HEX_MULTILINE */
199     unknown_data_state,        /* UNKNOWN_DATA */
200     set_value_state,           /* SET_VALUE */
201 };
202 
203 /* set the new parser state and return the previous one */
204 static inline enum parser_state set_state(struct parser *parser, enum parser_state state)
205 {
206     enum parser_state ret = parser->state;
207     parser->state = state;
208     return ret;
209 }
210 
211 /******************************************************************************
212  * Converts a hex representation of a DWORD into a DWORD.
213  */
214 static BOOL convert_hex_to_dword(WCHAR *str, DWORD *dw)
215 {
216     WCHAR *p, *end;
217     int count = 0;
218 
219     while (*str == ' ' || *str == '\t') str++;
220     if (!*str) goto error;
221 
222     p = str;
223     while (iswxdigit(*p))
224     {
225         count++;
226         p++;
227     }
228     if (count > 8) goto error;
229 
230     end = p;
231     while (*p == ' ' || *p == '\t') p++;
232     if (*p && *p != ';') goto error;
233 
234     *end = 0;
235     *dw = wcstoul(str, &end, 16);
236     return TRUE;
237 
238 error:
239     return FALSE;
240 }
241 
242 /******************************************************************************
243  * Converts comma-separated hex data into a binary string and modifies
244  * the input parameter to skip the concatenating backslash, if found.
245  *
246  * Returns TRUE or FALSE to indicate whether parsing was successful.
247  */
248 static BOOL convert_hex_csv_to_hex(struct parser *parser, WCHAR **str)
249 {
250     size_t size;
251     BYTE *d;
252     WCHAR *s;
253 
254     parser->backslash = FALSE;
255 
256     /* The worst case is 1 digit + 1 comma per byte */
257     size = ((lstrlenW(*str) + 1) / 2) + parser->data_size;
258     parser->data = realloc(parser->data, size);
259 
260     s = *str;
261     d = (BYTE *)parser->data + parser->data_size;
262 
263     while (*s)
264     {
265         WCHAR *end;
266         unsigned long wc;
267 
268         wc = wcstoul(s, &end, 16);
269         if (wc > 0xff) return FALSE;
270 
271         if (s == end && wc == 0)
272         {
273             while (*end == ' ' || *end == '\t') end++;
274             if (*end == '\\')
275             {
276                 parser->backslash = TRUE;
277                 *str = end + 1;
278                 return TRUE;
279             }
280             else if (*end == ';')
281                 return TRUE;
282             return FALSE;
283         }
284 
285         *d++ = wc;
286         parser->data_size++;
287 
288         if (*end && *end != ',')
289         {
290             while (*end == ' ' || *end == '\t') end++;
291             if (*end && *end != ';') return FALSE;
292             return TRUE;
293         }
294 
295         if (*end) end++;
296         s = end;
297     }
298 
299     return TRUE;
300 }
301 
302 /******************************************************************************
303  * Parses the data type of the registry value being imported and modifies
304  * the input parameter to skip the string representation of the data type.
305  *
306  * Returns TRUE or FALSE to indicate whether a data type was found.
307  */
308 static BOOL parse_data_type(struct parser *parser, WCHAR **line)
309 {
310     struct data_type { const WCHAR *tag; int len; int type; int parse_type; };
311 
312     static const struct data_type data_types[] = {
313     /*    tag       len  type         parse type    */
314         { L"\"",     1,  REG_SZ,      REG_SZ },
315         { L"hex:",   4,  REG_BINARY,  REG_BINARY },
316         { L"dword:", 6,  REG_DWORD,   REG_DWORD },
317         { L"hex(",   4,  -1,          REG_BINARY }, /* REG_NONE, REG_EXPAND_SZ, REG_MULTI_SZ */
318         { NULL,      0,  0,           0 }
319     };
320 
321     const struct data_type *ptr;
322 
323     for (ptr = data_types; ptr->tag; ptr++)
324     {
325         if (wcsncmp(ptr->tag, *line, ptr->len))
326             continue;
327 
328         parser->parse_type = ptr->parse_type;
329         parser->data_type = ptr->parse_type;
330         *line += ptr->len;
331 
332         if (ptr->type == -1)
333         {
334             WCHAR *end;
335             DWORD val;
336 
337             if (!**line || towlower((*line)[1]) == 'x')
338                 return FALSE;
339 
340             /* "hex(xx):" is special */
341             val = wcstoul(*line, &end, 16);
342             if (*end != ')' || *(end + 1) != ':' || (val == ~0u && errno == ERANGE))
343                 return FALSE;
344 
345             parser->data_type = val;
346             *line = end + 2;
347         }
348         return TRUE;
349     }
350     return FALSE;
351 }
352 
353 /******************************************************************************
354  * Replaces escape sequences with their character equivalents and
355  * null-terminates the string on the first non-escaped double quote.
356  *
357  * Assigns a pointer to the remaining unparsed data in the line.
358  * Returns TRUE or FALSE to indicate whether a closing double quote was found.
359  */
360 static BOOL REGPROC_unescape_string(WCHAR *str, WCHAR **unparsed)
361 {
362     int str_idx = 0;            /* current character under analysis */
363     int val_idx = 0;            /* the last character of the unescaped string */
364     int len = lstrlenW(str);
365     BOOL ret;
366 
367     for (str_idx = 0; str_idx < len; str_idx++, val_idx++) {
368         if (str[str_idx] == '\\') {
369             str_idx++;
370             switch (str[str_idx]) {
371             case 'n':
372                 str[val_idx] = '\n';
373                 break;
374             case 'r':
375                 str[val_idx] = '\r';
376                 break;
377             case '0':
378                 return FALSE;
379             case '\\':
380             case '"':
381                 str[val_idx] = str[str_idx];
382                 break;
383             default:
384                 if (!str[str_idx]) return FALSE;
385                 output_message(STRING_ESCAPE_SEQUENCE, str[str_idx]);
386                 str[val_idx] = str[str_idx];
387                 break;
388             }
389         } else if (str[str_idx] == '"') {
390             break;
391         } else {
392             str[val_idx] = str[str_idx];
393         }
394     }
395 
396     ret = (str[str_idx] == '"');
397     *unparsed = str + str_idx + 1;
398     str[val_idx] = '\0';
399     return ret;
400 }
401 
402 static HKEY parse_key_name(WCHAR *key_name, WCHAR **key_path)
403 {
404     unsigned int i;
405 
406     if (!key_name) return 0;
407 
408     *key_path = wcschr(key_name, '\\');
409     if (*key_path) (*key_path)++;
410 
411     for (i = 0; i < ARRAY_SIZE(reg_class_keys); i++)
412     {
413         int len = lstrlenW(reg_class_namesW[i]);
414 #ifdef __REACTOS__
415         if (!_wcsnicmp(key_name, reg_class_namesW[i], len) &&
416 #else
417         if (!wcsnicmp(key_name, reg_class_namesW[i], len) &&
418 #endif
419            (key_name[len] == 0 || key_name[len] == '\\'))
420         {
421             return reg_class_keys[i];
422         }
423     }
424 
425     return 0;
426 }
427 
428 static void close_key(struct parser *parser)
429 {
430     if (parser->hkey)
431     {
432         free(parser->key_name);
433         parser->key_name = NULL;
434 
435         RegCloseKey(parser->hkey);
436         parser->hkey = NULL;
437     }
438 }
439 
440 /******************************************************************************
441  * Opens the registry key given by the input path.
442  * This key must be closed by calling close_key().
443  */
444 static LONG open_key(struct parser *parser, WCHAR *path)
445 {
446     HKEY key_class;
447     WCHAR *key_path;
448     LONG res;
449 
450     close_key(parser);
451 
452     /* Get the registry class */
453     if (!path || !(key_class = parse_key_name(path, &key_path)))
454         return ERROR_INVALID_PARAMETER;
455 
456     res = RegCreateKeyExW(key_class, key_path, 0, NULL, REG_OPTION_NON_VOLATILE,
457                           KEY_ALL_ACCESS, NULL, &parser->hkey, NULL);
458 
459     if (res == ERROR_SUCCESS)
460     {
461         parser->key_name = malloc((lstrlenW(path) + 1) * sizeof(WCHAR));
462         lstrcpyW(parser->key_name, path);
463     }
464     else
465         parser->hkey = NULL;
466 
467     return res;
468 }
469 
470 static void free_parser_data(struct parser *parser)
471 {
472     if (parser->parse_type == REG_DWORD || parser->parse_type == REG_BINARY)
473         free(parser->data);
474 
475     parser->data = NULL;
476     parser->data_size = 0;
477 }
478 
479 static void prepare_hex_string_data(struct parser *parser)
480 {
481     if (parser->data_type == REG_EXPAND_SZ || parser->data_type == REG_MULTI_SZ ||
482         parser->data_type == REG_SZ)
483     {
484         if (parser->is_unicode)
485         {
486             WCHAR *data = parser->data;
487             DWORD len = parser->data_size / sizeof(WCHAR);
488 
489             if (data[len - 1] != 0)
490             {
491                 data[len] = 0;
492                 parser->data_size += sizeof(WCHAR);
493             }
494         }
495         else
496         {
497             BYTE *data = parser->data;
498 
499             if (data[parser->data_size - 1] != 0)
500             {
501                 data[parser->data_size] = 0;
502                 parser->data_size++;
503             }
504 
505             parser->data = GetWideStringN(parser->data, parser->data_size, &parser->data_size);
506             parser->data_size *= sizeof(WCHAR);
507             free(data);
508         }
509     }
510 }
511 
512 enum reg_versions {
513     REG_VERSION_31,
514     REG_VERSION_40,
515     REG_VERSION_50,
516     REG_VERSION_FUZZY,
517     REG_VERSION_INVALID
518 };
519 
520 static enum reg_versions parse_file_header(const WCHAR *s)
521 {
522     static const WCHAR header_31[] = L"REGEDIT";
523 
524     while (*s == ' ' || *s == '\t') s++;
525 
526     if (!lstrcmpW(s, header_31))
527         return REG_VERSION_31;
528 
529     if (!lstrcmpW(s, L"REGEDIT4"))
530         return REG_VERSION_40;
531 
532     if (!lstrcmpW(s, L"Windows Registry Editor Version 5.00"))
533         return REG_VERSION_50;
534 
535     /* The Windows version accepts registry file headers beginning with "REGEDIT" and ending
536      * with other characters, as long as "REGEDIT" appears at the start of the line. For example,
537      * "REGEDIT 4", "REGEDIT9" and "REGEDIT4FOO" are all treated as valid file headers.
538      * In all such cases, however, the contents of the registry file are not imported.
539      */
540     if (!wcsncmp(s, header_31, 7)) /* "REGEDIT" without NUL */
541         return REG_VERSION_FUZZY;
542 
543     return REG_VERSION_INVALID;
544 }
545 
546 /* handler for parser HEADER state */
547 static WCHAR *header_state(struct parser *parser, WCHAR *pos)
548 {
549     WCHAR *line, *header;
550 
551     if (!(line = get_line(parser->file)))
552         return NULL;
553 
554     if (!parser->is_unicode)
555     {
556         header = malloc((lstrlenW(line) + 3) * sizeof(WCHAR));
557         header[0] = parser->two_wchars[0];
558         header[1] = parser->two_wchars[1];
559         lstrcpyW(header + 2, line);
560         parser->reg_version = parse_file_header(header);
561         free(header);
562     }
563     else parser->reg_version = parse_file_header(line);
564 
565     switch (parser->reg_version)
566     {
567     case REG_VERSION_31:
568         set_state(parser, PARSE_WIN31_LINE);
569         break;
570     case REG_VERSION_40:
571     case REG_VERSION_50:
572         set_state(parser, LINE_START);
573         break;
574     default:
575         get_line(NULL); /* Reset static variables */
576         return NULL;
577     }
578 
579     return line;
580 }
581 
582 /* handler for parser PARSE_WIN31_LINE state */
583 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos)
584 {
585     WCHAR *line, *value;
586     static WCHAR hkcr[] = L"HKEY_CLASSES_ROOT";
587     unsigned int key_end = 0;
588 
589     if (!(line = get_line(parser->file)))
590         return NULL;
591 
592     if (wcsncmp(line, hkcr, lstrlenW(hkcr)))
593         return line;
594 
595     /* get key name */
596     while (line[key_end] && !iswspace(line[key_end])) key_end++;
597 
598     value = line + key_end;
599     while (*value == ' ' || *value == '\t') value++;
600 
601     if (*value == '=') value++;
602     if (*value == ' ') value++; /* at most one space is skipped */
603 
604     line[key_end] = 0;
605 
606     if (open_key(parser, line) != ERROR_SUCCESS)
607     {
608         output_message(STRING_OPEN_KEY_FAILED, line);
609         return line;
610     }
611 
612     parser->value_name = NULL;
613     parser->data_type = REG_SZ;
614     parser->data = value;
615     parser->data_size = (lstrlenW(value) + 1) * sizeof(WCHAR);
616 
617     set_state(parser, SET_VALUE);
618     return value;
619 }
620 
621 /* handler for parser LINE_START state */
622 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos)
623 {
624     WCHAR *line, *p;
625 
626     if (!(line = get_line(parser->file)))
627         return NULL;
628 
629     for (p = line; *p; p++)
630     {
631         switch (*p)
632         {
633         case '[':
634             set_state(parser, KEY_NAME);
635             return p + 1;
636         case '@':
637             set_state(parser, DEFAULT_VALUE_NAME);
638             return p;
639         case '"':
640             set_state(parser, QUOTED_VALUE_NAME);
641             return p + 1;
642         case ' ':
643         case '\t':
644             break;
645         default:
646             return p;
647         }
648     }
649 
650     return p;
651 }
652 
653 /* handler for parser KEY_NAME state */
654 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos)
655 {
656     WCHAR *p = pos, *key_end;
657 
658     if (*p == ' ' || *p == '\t' || !(key_end = wcsrchr(p, ']')))
659         goto done;
660 
661     *key_end = 0;
662 
663     if (*p == '-')
664     {
665         set_state(parser, DELETE_KEY);
666         return p + 1;
667     }
668     else if (open_key(parser, p) != ERROR_SUCCESS)
669         output_message(STRING_OPEN_KEY_FAILED, p);
670 
671 done:
672     set_state(parser, LINE_START);
673     return p;
674 }
675 
676 /* handler for parser DELETE_KEY state */
677 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos)
678 {
679     WCHAR *p = pos;
680 
681     close_key(parser);
682 
683     if (*p == 'H' || *p == 'h')
684         delete_registry_key(p);
685 
686     set_state(parser, LINE_START);
687     return p;
688 }
689 
690 /* handler for parser DEFAULT_VALUE_NAME state */
691 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos)
692 {
693     free(parser->value_name);
694     parser->value_name = NULL;
695 
696     set_state(parser, DATA_START);
697     return pos + 1;
698 }
699 
700 /* handler for parser QUOTED_VALUE_NAME state */
701 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos)
702 {
703     WCHAR *val_name = pos, *p;
704 
705     free(parser->value_name);
706     parser->value_name = NULL;
707 
708     if (!REGPROC_unescape_string(val_name, &p))
709         goto invalid;
710 
711     /* copy the value name in case we need to parse multiple lines and the buffer is overwritten */
712     parser->value_name = malloc((lstrlenW(val_name) + 1) * sizeof(WCHAR));
713     lstrcpyW(parser->value_name, val_name);
714 
715     set_state(parser, DATA_START);
716     return p;
717 
718 invalid:
719     set_state(parser, LINE_START);
720     return val_name;
721 }
722 
723 /* handler for parser DATA_START state */
724 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos)
725 {
726     WCHAR *p = pos;
727     unsigned int len;
728 
729     while (*p == ' ' || *p == '\t') p++;
730     if (*p != '=') goto done;
731     p++;
732     while (*p == ' ' || *p == '\t') p++;
733 
734     /* trim trailing whitespace */
735     len = lstrlenW(p);
736     while (len > 0 && (p[len - 1] == ' ' || p[len - 1] == '\t')) len--;
737     p[len] = 0;
738 
739     if (*p == '-')
740         set_state(parser, DELETE_VALUE);
741     else
742         set_state(parser, DATA_TYPE);
743     return p;
744 
745 done:
746     set_state(parser, LINE_START);
747     return p;
748 }
749 
750 /* handler for parser DELETE_VALUE state */
751 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos)
752 {
753     WCHAR *p = pos + 1;
754 
755     while (*p == ' ' || *p == '\t') p++;
756     if (*p && *p != ';') goto done;
757 
758     RegDeleteValueW(parser->hkey, parser->value_name);
759 
760 done:
761     set_state(parser, LINE_START);
762     return p;
763 }
764 
765 /* handler for parser DATA_TYPE state */
766 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos)
767 {
768     WCHAR *line = pos;
769 
770     if (!parse_data_type(parser, &line))
771     {
772         set_state(parser, LINE_START);
773         return line;
774     }
775 
776     switch (parser->parse_type)
777     {
778     case REG_SZ:
779         set_state(parser, STRING_DATA);
780         break;
781     case REG_DWORD:
782         set_state(parser, DWORD_DATA);
783         break;
784     case REG_BINARY: /* all hex data types, including undefined */
785         set_state(parser, HEX_DATA);
786         break;
787     default:
788         set_state(parser, UNKNOWN_DATA);
789     }
790 
791     return line;
792 }
793 
794 /* handler for parser STRING_DATA state */
795 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos)
796 {
797     WCHAR *line;
798 
799     parser->data = pos;
800 
801     if (!REGPROC_unescape_string(parser->data, &line))
802         goto invalid;
803 
804     while (*line == ' ' || *line == '\t') line++;
805     if (*line && *line != ';') goto invalid;
806 
807     parser->data_size = (lstrlenW(parser->data) + 1) * sizeof(WCHAR);
808 
809     set_state(parser, SET_VALUE);
810     return line;
811 
812 invalid:
813     free_parser_data(parser);
814     set_state(parser, LINE_START);
815     return line;
816 }
817 
818 /* handler for parser DWORD_DATA state */
819 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos)
820 {
821     WCHAR *line = pos;
822 
823     parser->data = malloc(sizeof(DWORD));
824 
825     if (!convert_hex_to_dword(line, parser->data))
826         goto invalid;
827 
828     parser->data_size = sizeof(DWORD);
829 
830     set_state(parser, SET_VALUE);
831     return line;
832 
833 invalid:
834     free_parser_data(parser);
835     set_state(parser, LINE_START);
836     return line;
837 }
838 
839 /* handler for parser HEX_DATA state */
840 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos)
841 {
842     WCHAR *line = pos;
843 
844     if (!*line)
845         goto set_value;
846 
847     if (!convert_hex_csv_to_hex(parser, &line))
848         goto invalid;
849 
850     if (parser->backslash)
851     {
852         set_state(parser, EOL_BACKSLASH);
853         return line;
854     }
855 
856     prepare_hex_string_data(parser);
857 
858 set_value:
859     set_state(parser, SET_VALUE);
860     return line;
861 
862 invalid:
863     free_parser_data(parser);
864     set_state(parser, LINE_START);
865     return line;
866 }
867 
868 /* handler for parser EOL_BACKSLASH state */
869 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos)
870 {
871     WCHAR *p = pos;
872 
873     while (*p == ' ' || *p == '\t') p++;
874     if (*p && *p != ';') goto invalid;
875 
876     set_state(parser, HEX_MULTILINE);
877     return pos;
878 
879 invalid:
880     free_parser_data(parser);
881     set_state(parser, LINE_START);
882     return p;
883 }
884 
885 /* handler for parser HEX_MULTILINE state */
886 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos)
887 {
888     WCHAR *line;
889 
890     if (!(line = get_line(parser->file)))
891     {
892         prepare_hex_string_data(parser);
893         set_state(parser, SET_VALUE);
894         return pos;
895     }
896 
897     while (*line == ' ' || *line == '\t') line++;
898     if (!*line || *line == ';') return line;
899 
900     if (!iswxdigit(*line)) goto invalid;
901 
902     set_state(parser, HEX_DATA);
903     return line;
904 
905 invalid:
906     free_parser_data(parser);
907     set_state(parser, LINE_START);
908     return line;
909 }
910 
911 /* handler for parser UNKNOWN_DATA state */
912 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos)
913 {
914     output_message(STRING_UNKNOWN_DATA_FORMAT, parser->data_type);
915 
916     set_state(parser, LINE_START);
917     return pos;
918 }
919 
920 /* handler for parser SET_VALUE state */
921 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos)
922 {
923     RegSetValueExW(parser->hkey, parser->value_name, 0, parser->data_type,
924                    parser->data, parser->data_size);
925 
926     free_parser_data(parser);
927 
928     if (parser->reg_version == REG_VERSION_31)
929         set_state(parser, PARSE_WIN31_LINE);
930     else
931         set_state(parser, LINE_START);
932 
933     return pos;
934 }
935 
936 static WCHAR *get_lineA(FILE *fp)
937 {
938     static WCHAR *lineW;
939     static size_t size;
940     static char *buf, *next;
941     char *line;
942 
943     free(lineW);
944 
945     if (!fp) goto cleanup;
946 
947     if (!size)
948     {
949         size = REG_VAL_BUF_SIZE;
950         buf = malloc(size);
951         *buf = 0;
952         next = buf;
953     }
954     line = next;
955 
956     while (next)
957     {
958         char *p = strpbrk(line, "\r\n");
959         if (!p)
960         {
961             size_t len, count;
962             len = strlen(next);
963             memmove(buf, next, len + 1);
964             if (size - len < 3)
965             {
966                 size *= 2;
967                 buf = realloc(buf, size);
968             }
969             if (!(count = fread(buf + len, 1, size - len - 1, fp)))
970             {
971                 next = NULL;
972                 lineW = GetWideString(buf);
973                 return lineW;
974             }
975             buf[len + count] = 0;
976             next = buf;
977             line = buf;
978             continue;
979         }
980         next = p + 1;
981         if (*p == '\r' && *(p + 1) == '\n') next++;
982         *p = 0;
983         lineW = GetWideString(line);
984         return lineW;
985     }
986 
987 cleanup:
988     lineW = NULL;
989     if (size) free(buf);
990     size = 0;
991     return NULL;
992 }
993 
994 static WCHAR *get_lineW(FILE *fp)
995 {
996     static size_t size;
997     static WCHAR *buf, *next;
998     WCHAR *line;
999 
1000     if (!fp) goto cleanup;
1001 
1002     if (!size)
1003     {
1004         size = REG_VAL_BUF_SIZE;
1005         buf = malloc(size * sizeof(WCHAR));
1006         *buf = 0;
1007         next = buf;
1008     }
1009     line = next;
1010 
1011     while (next)
1012     {
1013         WCHAR *p = wcspbrk(line, L"\r\n");
1014         if (!p)
1015         {
1016             size_t len, count;
1017             len = lstrlenW(next);
1018             memmove(buf, next, (len + 1) * sizeof(WCHAR));
1019             if (size - len < 3)
1020             {
1021                 size *= 2;
1022                 buf = realloc(buf, size * sizeof(WCHAR));
1023             }
1024             if (!(count = fread(buf + len, sizeof(WCHAR), size - len - 1, fp)))
1025             {
1026                 next = NULL;
1027                 return buf;
1028             }
1029             buf[len + count] = 0;
1030             next = buf;
1031             line = buf;
1032             continue;
1033         }
1034         next = p + 1;
1035         if (*p == '\r' && *(p + 1) == '\n') next++;
1036         *p = 0;
1037         return line;
1038     }
1039 
1040 cleanup:
1041     if (size) free(buf);
1042     size = 0;
1043     return NULL;
1044 }
1045 
1046 /******************************************************************************
1047  * Reads contents of the specified file into the registry.
1048  */
1049 BOOL import_registry_file(FILE *reg_file)
1050 {
1051     BYTE s[2];
1052     struct parser parser;
1053     WCHAR *pos;
1054 
1055     if (!reg_file || (fread(s, 2, 1, reg_file) != 1))
1056         return FALSE;
1057 
1058     parser.is_unicode = (s[0] == 0xff && s[1] == 0xfe);
1059     get_line = parser.is_unicode ? get_lineW : get_lineA;
1060 
1061     parser.file          = reg_file;
1062     parser.two_wchars[0] = s[0];
1063     parser.two_wchars[1] = s[1];
1064     parser.reg_version   = -1;
1065     parser.hkey          = NULL;
1066     parser.key_name      = NULL;
1067     parser.value_name    = NULL;
1068     parser.parse_type    = 0;
1069     parser.data_type     = 0;
1070     parser.data          = NULL;
1071     parser.data_size     = 0;
1072     parser.backslash     = FALSE;
1073     parser.state         = HEADER;
1074 
1075     pos = parser.two_wchars;
1076 
1077     /* parser main loop */
1078     while (pos)
1079         pos = (parser_funcs[parser.state])(&parser, pos);
1080 
1081     if (parser.reg_version == REG_VERSION_FUZZY || parser.reg_version == REG_VERSION_INVALID)
1082         return parser.reg_version == REG_VERSION_FUZZY;
1083 
1084     free(parser.value_name);
1085     close_key(&parser);
1086 
1087     return TRUE;
1088 }
1089 
1090 /******************************************************************************
1091  * Removes the registry key with all subkeys. Parses full key name.
1092  *
1093  * Parameters:
1094  * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
1095  *      empty, points to register key class, does not exist.
1096  */
1097 void delete_registry_key(WCHAR *reg_key_name)
1098 {
1099     WCHAR *key_name = NULL;
1100     HKEY key_class;
1101 
1102     if (!reg_key_name || !reg_key_name[0])
1103         return;
1104 
1105     if (!(key_class = parse_key_name(reg_key_name, &key_name)))
1106     {
1107         if (key_name) *(key_name - 1) = 0;
1108 #ifdef __REACTOS__
1109         output_message(STRING_INVALID_SYSTEM_KEY, reg_key_name);
1110         return;
1111 #else
1112         error_exit(STRING_INVALID_SYSTEM_KEY, reg_key_name);
1113 #endif
1114     }
1115 
1116     if (!key_name || !*key_name)
1117 #ifdef __REACTOS__
1118     {
1119         output_message(STRING_DELETE_FAILED, reg_key_name);
1120         return;
1121     }
1122 #else
1123         error_exit(STRING_DELETE_FAILED, reg_key_name);
1124 #endif
1125 
1126 #ifdef __REACTOS__
1127     SHDeleteKey(key_class, key_name);
1128 #else
1129     RegDeleteTreeW(key_class, key_name);
1130 #endif
1131 }
1132 
1133 static void REGPROC_write_line(FILE *fp, const WCHAR *str, BOOL unicode)
1134 {
1135     if (unicode)
1136         fwrite(str, sizeof(WCHAR), lstrlenW(str), fp);
1137     else
1138     {
1139         char *strA = GetMultiByteString(str);
1140         fputs(strA, fp);
1141         free(strA);
1142     }
1143 }
1144 
1145 static WCHAR *REGPROC_escape_string(WCHAR *str, size_t str_len, size_t *line_len)
1146 {
1147     size_t i, escape_count, pos;
1148     WCHAR *buf;
1149 
1150     for (i = 0, escape_count = 0; i < str_len; i++)
1151     {
1152         WCHAR c = str[i];
1153 
1154         if (!c) break;
1155 
1156         if (c == '\r' || c == '\n' || c == '\\' || c == '"')
1157             escape_count++;
1158     }
1159 
1160     buf = malloc((str_len + escape_count + 1) * sizeof(WCHAR));
1161 
1162     for (i = 0, pos = 0; i < str_len; i++, pos++)
1163     {
1164         WCHAR c = str[i];
1165 
1166         if (!c) break;
1167 
1168         switch (c)
1169         {
1170         case '\r':
1171             buf[pos++] = '\\';
1172             buf[pos] = 'r';
1173             break;
1174         case '\n':
1175             buf[pos++] = '\\';
1176             buf[pos] = 'n';
1177             break;
1178         case '\\':
1179             buf[pos++] = '\\';
1180             buf[pos] = '\\';
1181             break;
1182         case '"':
1183             buf[pos++] = '\\';
1184             buf[pos] = '"';
1185             break;
1186         default:
1187             buf[pos] = c;
1188         }
1189     }
1190 
1191     buf[pos] = 0;
1192     *line_len = pos;
1193     return buf;
1194 }
1195 
1196 static size_t export_value_name(FILE *fp, WCHAR *name, size_t len, BOOL unicode)
1197 {
1198     static const WCHAR default_name[] = L"@=";
1199     size_t line_len;
1200 
1201     if (name && *name)
1202     {
1203         WCHAR *str = REGPROC_escape_string(name, len, &line_len);
1204         WCHAR *buf = malloc((line_len + 4) * sizeof(WCHAR));
1205 #ifdef __REACTOS__
1206         StringCchPrintfW(buf, line_len + 4, L"\"%s\"=", str);
1207         line_len = wcslen(buf);
1208 #else
1209         line_len = swprintf(buf, line_len + 4, L"\"%s\"=", str);
1210 #endif
1211         REGPROC_write_line(fp, buf, unicode);
1212         free(buf);
1213         free(str);
1214     }
1215     else
1216     {
1217         line_len = lstrlenW(default_name);
1218         REGPROC_write_line(fp, default_name, unicode);
1219     }
1220 
1221     return line_len;
1222 }
1223 
1224 static void export_string_data(WCHAR **buf, WCHAR *data, size_t size)
1225 {
1226     size_t len = 0, line_len;
1227     WCHAR *str;
1228 
1229     if (size)
1230         len = size / sizeof(WCHAR) - 1;
1231     str = REGPROC_escape_string(data, len, &line_len);
1232     *buf = malloc((line_len + 3) * sizeof(WCHAR));
1233 #ifdef __REACTOS__
1234     StringCchPrintfW(*buf, line_len + 3, L"\"%s\"", str);
1235 #else
1236     swprintf(*buf, line_len + 3, L"\"%s\"", str);
1237 #endif
1238     free(str);
1239 }
1240 
1241 static void export_dword_data(WCHAR **buf, DWORD *data)
1242 {
1243     *buf = malloc(15 * sizeof(WCHAR));
1244 #ifdef __REACTOS__
1245     StringCchPrintfW(*buf, 15, L"dword:%08x", *data);
1246 #else
1247     swprintf(*buf, 15, L"dword:%08x", *data);
1248 #endif
1249 }
1250 
1251 static size_t export_hex_data_type(FILE *fp, DWORD type, BOOL unicode)
1252 {
1253     static const WCHAR hex[] = L"hex:";
1254     size_t line_len;
1255 
1256     if (type == REG_BINARY)
1257     {
1258         line_len = lstrlenW(hex);
1259         REGPROC_write_line(fp, hex, unicode);
1260     }
1261     else
1262     {
1263         WCHAR *buf = malloc(15 * sizeof(WCHAR));
1264 #ifdef __REACTOS__
1265         StringCchPrintfW(buf, 15, L"hex(%x):", type);
1266         line_len = wcslen(buf);
1267 #else
1268         line_len = swprintf(buf, 15, L"hex(%x):", type);
1269 #endif
1270         REGPROC_write_line(fp, buf, unicode);
1271         free(buf);
1272     }
1273 
1274     return line_len;
1275 }
1276 
1277 #define MAX_HEX_CHARS 77
1278 
1279 static void export_hex_data(FILE *fp, WCHAR **buf, DWORD type, DWORD line_len,
1280                             void *data, DWORD size, BOOL unicode)
1281 {
1282     size_t num_commas, i, pos;
1283 
1284     line_len += export_hex_data_type(fp, type, unicode);
1285 
1286     if (!size) return;
1287 
1288     if (!unicode && (type == REG_EXPAND_SZ || type == REG_MULTI_SZ))
1289         data = GetMultiByteStringN(data, size / sizeof(WCHAR), &size);
1290 
1291     num_commas = size - 1;
1292     *buf = malloc(size * 3 * sizeof(WCHAR));
1293 
1294     for (i = 0, pos = 0; i < size; i++)
1295     {
1296 #ifdef __REACTOS__
1297         StringCchPrintfW(*buf + pos, 3, L"%02x", ((BYTE *)data)[i]);
1298         pos += wcslen(*buf + pos);
1299 #else
1300         pos += swprintf(*buf + pos, 3, L"%02x", ((BYTE *)data)[i]);
1301 #endif
1302         if (i == num_commas) break;
1303         (*buf)[pos++] = ',';
1304         (*buf)[pos] = 0;
1305         line_len += 3;
1306 
1307         if (line_len >= MAX_HEX_CHARS)
1308         {
1309             REGPROC_write_line(fp, *buf, unicode);
1310             REGPROC_write_line(fp, L"\\\r\n  ", unicode);
1311             line_len = 2;
1312             pos = 0;
1313         }
1314     }
1315 }
1316 
1317 static void export_newline(FILE *fp, BOOL unicode)
1318 {
1319     REGPROC_write_line(fp, L"\r\n", unicode);
1320 }
1321 
1322 static void export_data(FILE *fp, WCHAR *value_name, DWORD value_len, DWORD type,
1323                         void *data, size_t size, BOOL unicode)
1324 {
1325     WCHAR *buf = NULL;
1326     size_t line_len = export_value_name(fp, value_name, value_len, unicode);
1327 
1328     switch (type)
1329     {
1330     case REG_SZ:
1331         export_string_data(&buf, data, size);
1332         break;
1333     case REG_DWORD:
1334         if (size)
1335         {
1336             export_dword_data(&buf, data);
1337             break;
1338         }
1339         /* fall through */
1340     case REG_NONE:
1341     case REG_EXPAND_SZ:
1342     case REG_BINARY:
1343     case REG_MULTI_SZ:
1344     default:
1345         export_hex_data(fp, &buf, type, line_len, data, size, unicode);
1346         break;
1347     }
1348 
1349     if (size || type == REG_SZ)
1350     {
1351         REGPROC_write_line(fp, buf, unicode);
1352         free(buf);
1353     }
1354 
1355     export_newline(fp, unicode);
1356 }
1357 
1358 static WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len)
1359 {
1360     WCHAR *subkey_path;
1361 
1362     subkey_path = malloc((path_len + subkey_len + 2) * sizeof(WCHAR));
1363 #ifdef __REACTOS__
1364     StringCchPrintfW(subkey_path, path_len + subkey_len + 2, L"%s\\%s", path, subkey_name);
1365 #else
1366     swprintf(subkey_path, path_len + subkey_len + 2, L"%s\\%s", path, subkey_name);
1367 #endif
1368 
1369     return subkey_path;
1370 }
1371 
1372 static void export_key_name(FILE *fp, WCHAR *name, BOOL unicode)
1373 {
1374     WCHAR *buf;
1375 
1376     buf = malloc((lstrlenW(name) + 7) * sizeof(WCHAR));
1377 #ifdef __REACTOS__
1378     StringCchPrintfW(buf, lstrlenW(name) + 7, L"\r\n[%s]\r\n", name);
1379 #else
1380     swprintf(buf, lstrlenW(name) + 7, L"\r\n[%s]\r\n", name);
1381 #endif
1382     REGPROC_write_line(fp, buf, unicode);
1383     free(buf);
1384 }
1385 
1386 #define MAX_SUBKEY_LEN   257
1387 
1388 static void export_registry_data(FILE *fp, HKEY key, WCHAR *path, BOOL unicode)
1389 {
1390     LONG rc;
1391     DWORD max_value_len = 256, value_len;
1392     DWORD max_data_bytes = 2048, data_size;
1393     DWORD subkey_len;
1394     DWORD i, type, path_len;
1395     WCHAR *value_name, *subkey_name, *subkey_path;
1396     BYTE *data;
1397     HKEY subkey;
1398 
1399     export_key_name(fp, path, unicode);
1400 
1401     value_name = malloc(max_value_len * sizeof(WCHAR));
1402     data = malloc(max_data_bytes);
1403 
1404     i = 0;
1405     for (;;)
1406     {
1407         value_len = max_value_len;
1408         data_size = max_data_bytes;
1409         rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size);
1410         if (rc == ERROR_SUCCESS)
1411         {
1412             export_data(fp, value_name, value_len, type, data, data_size, unicode);
1413             i++;
1414         }
1415         else if (rc == ERROR_MORE_DATA)
1416         {
1417             if (data_size > max_data_bytes)
1418             {
1419                 max_data_bytes = data_size;
1420                 data = realloc(data, max_data_bytes);
1421             }
1422             else
1423             {
1424                 max_value_len *= 2;
1425                 value_name = realloc(value_name, max_value_len * sizeof(WCHAR));
1426             }
1427         }
1428         else break;
1429     }
1430 
1431     free(data);
1432     free(value_name);
1433 
1434     subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
1435 
1436     path_len = lstrlenW(path);
1437 
1438     i = 0;
1439     for (;;)
1440     {
1441         subkey_len = MAX_SUBKEY_LEN;
1442         rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
1443         if (rc == ERROR_SUCCESS)
1444         {
1445             subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
1446             if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey))
1447             {
1448                 export_registry_data(fp, subkey, subkey_path, unicode);
1449                 RegCloseKey(subkey);
1450             }
1451             free(subkey_path);
1452             i++;
1453         }
1454         else break;
1455     }
1456 
1457     free(subkey_name);
1458 }
1459 
1460 static FILE *REGPROC_open_export_file(WCHAR *file_name, BOOL unicode)
1461 {
1462     FILE *file;
1463 
1464     if (!lstrcmpW(file_name, L"-"))
1465     {
1466         file = stdout;
1467         _setmode(_fileno(file), _O_BINARY);
1468     }
1469     else
1470     {
1471         file = _wfopen(file_name, L"wb");
1472         if (!file)
1473         {
1474             _wperror(L"regedit");
1475 #ifdef __REACTOS__
1476             output_message(STRING_CANNOT_OPEN_FILE, file_name);
1477             return NULL;
1478 #else
1479             error_exit(STRING_CANNOT_OPEN_FILE, file_name);
1480 #endif
1481         }
1482     }
1483 
1484     if (unicode)
1485     {
1486         static const BYTE bom[] = {0xff,0xfe};
1487         static const WCHAR header[] = L"Windows Registry Editor Version 5.00\r\n";
1488 
1489         fwrite(bom, sizeof(BYTE), ARRAY_SIZE(bom), file);
1490         fwrite(header, sizeof(WCHAR), lstrlenW(header), file);
1491     }
1492     else
1493         fputs("REGEDIT4\r\n", file);
1494 
1495     return file;
1496 }
1497 
1498 static HKEY open_export_key(HKEY key_class, WCHAR *subkey, WCHAR *path)
1499 {
1500     HKEY key;
1501 
1502     if (!RegOpenKeyExW(key_class, subkey, 0, KEY_READ, &key))
1503         return key;
1504 
1505     output_message(STRING_OPEN_KEY_FAILED, path);
1506     return NULL;
1507 }
1508 
1509 static BOOL export_key(WCHAR *file_name, WCHAR *path, BOOL unicode)
1510 {
1511     HKEY key_class, key;
1512     WCHAR *subkey;
1513     FILE *fp;
1514 
1515     if (!(key_class = parse_key_name(path, &subkey)))
1516     {
1517         if (subkey) *(subkey - 1) = 0;
1518         output_message(STRING_INVALID_SYSTEM_KEY, path);
1519         return FALSE;
1520     }
1521 
1522     if (!(key = open_export_key(key_class, subkey, path)))
1523         return FALSE;
1524 
1525     fp = REGPROC_open_export_file(file_name, unicode);
1526 #ifdef __REACTOS__
1527     if (!fp)
1528         return TRUE; /* Error message is already displayed */
1529 #endif
1530     export_registry_data(fp, key, path, unicode);
1531     export_newline(fp, unicode);
1532     fclose(fp);
1533 
1534     RegCloseKey(key);
1535     return TRUE;
1536 }
1537 
1538 static BOOL export_all(WCHAR *file_name, WCHAR *path, BOOL unicode)
1539 {
1540     FILE *fp;
1541     int i;
1542     HKEY classes[] = {HKEY_LOCAL_MACHINE, HKEY_USERS}, key;
1543     WCHAR *class_name;
1544 
1545     fp = REGPROC_open_export_file(file_name, unicode);
1546 #ifdef __REACTOS__
1547     if (!fp)
1548         return TRUE; /* Error message is already displayed */
1549 #endif
1550 
1551     for (i = 0; i < ARRAY_SIZE(classes); i++)
1552     {
1553         if (!(key = open_export_key(classes[i], NULL, path)))
1554         {
1555             fclose(fp);
1556             return FALSE;
1557         }
1558 
1559         class_name = malloc((lstrlenW(reg_class_namesW[i]) + 1) * sizeof(WCHAR));
1560         lstrcpyW(class_name, reg_class_namesW[i]);
1561 
1562         export_registry_data(fp, classes[i], class_name, unicode);
1563 
1564         free(class_name);
1565         RegCloseKey(key);
1566     }
1567 
1568     export_newline(fp, unicode);
1569     fclose(fp);
1570 
1571     return TRUE;
1572 }
1573 
1574 BOOL export_registry_key(WCHAR *file_name, WCHAR *path, DWORD format)
1575 {
1576     BOOL unicode = (format == REG_FORMAT_5);
1577 
1578     if (path && *path)
1579         return export_key(file_name, path, unicode);
1580     else
1581         return export_all(file_name, path, unicode);
1582 }
1583