d2d1: Introduce a debug helper for D2D1_POINT_2F.
[wine.git] / programs / regedit / regproc.c
blob4ef99ec3cac2d393203d12ba62a87963322faadc
1 /*
2 * Registry processing routines. Routines, common for registry
3 * processing frontends.
5 * Copyright 1999 Sylvain St-Germain
6 * Copyright 2002 Andriy Palamarchuk
7 * Copyright 2008 Alexander N. Sørnes <alex@thehandofagony.com>
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.
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.
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
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <fcntl.h>
27 #include <io.h>
28 #include <windows.h>
29 #include <commctrl.h>
30 #include <wine/unicode.h>
31 #include <wine/debug.h>
32 #include <wine/heap.h>
33 #include "main.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(regedit);
37 #define REG_VAL_BUF_SIZE 4096
39 static HKEY reg_class_keys[] = {
40 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
41 HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA
44 void *heap_xalloc(size_t size)
46 void *buf = heap_alloc(size);
47 if (!buf)
49 ERR("Out of memory!\n");
50 exit(1);
52 return buf;
55 void *heap_xrealloc(void *buf, size_t size)
57 void *new_buf = heap_realloc(buf, size);
59 if (!new_buf)
61 ERR("Out of memory!\n");
62 exit(1);
65 return new_buf;
68 /******************************************************************************
69 * Allocates memory and converts input from multibyte to wide chars
70 * Returned string must be freed by the caller
72 static WCHAR* GetWideString(const char* strA)
74 if(strA)
76 WCHAR* strW;
77 int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0);
79 strW = heap_xalloc(len * sizeof(WCHAR));
80 MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len);
81 return strW;
83 return NULL;
86 /******************************************************************************
87 * Allocates memory and converts input from multibyte to wide chars
88 * Returned string must be freed by the caller
90 static WCHAR* GetWideStringN(const char* strA, int chars, DWORD *len)
92 if(strA)
94 WCHAR* strW;
95 *len = MultiByteToWideChar(CP_ACP, 0, strA, chars, NULL, 0);
97 strW = heap_xalloc(*len * sizeof(WCHAR));
98 MultiByteToWideChar(CP_ACP, 0, strA, chars, strW, *len);
99 return strW;
101 *len = 0;
102 return NULL;
105 /******************************************************************************
106 * Allocates memory and converts input from wide chars to multibyte
107 * Returned string must be freed by the caller
109 char* GetMultiByteString(const WCHAR* strW)
111 if(strW)
113 char* strA;
114 int len = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL);
116 strA = heap_xalloc(len);
117 WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, len, NULL, NULL);
118 return strA;
120 return NULL;
123 /******************************************************************************
124 * Allocates memory and converts input from wide chars to multibyte
125 * Returned string must be freed by the caller
127 static char* GetMultiByteStringN(const WCHAR* strW, int chars, DWORD* len)
129 if(strW)
131 char* strA;
132 *len = WideCharToMultiByte(CP_ACP, 0, strW, chars, NULL, 0, NULL, NULL);
134 strA = heap_xalloc(*len);
135 WideCharToMultiByte(CP_ACP, 0, strW, chars, strA, *len, NULL, NULL);
136 return strA;
138 *len = 0;
139 return NULL;
142 static WCHAR *(*get_line)(FILE *);
144 /* parser definitions */
145 enum parser_state
147 HEADER, /* parsing the registry file version header */
148 PARSE_WIN31_LINE, /* parsing a Windows 3.1 registry line */
149 LINE_START, /* at the beginning of a registry line */
150 KEY_NAME, /* parsing a key name */
151 DELETE_KEY, /* deleting a registry key */
152 DEFAULT_VALUE_NAME, /* parsing a default value name */
153 QUOTED_VALUE_NAME, /* parsing a double-quoted value name */
154 DATA_START, /* preparing for data parsing operations */
155 DELETE_VALUE, /* deleting a registry value */
156 DATA_TYPE, /* parsing the registry data type */
157 STRING_DATA, /* parsing REG_SZ data */
158 DWORD_DATA, /* parsing DWORD data */
159 HEX_DATA, /* parsing REG_BINARY, REG_NONE, REG_EXPAND_SZ or REG_MULTI_SZ data */
160 EOL_BACKSLASH, /* preparing to parse multiple lines of hex data */
161 HEX_MULTILINE, /* parsing multiple lines of hex data */
162 UNKNOWN_DATA, /* parsing an unhandled or invalid data type */
163 SET_VALUE, /* adding a value to the registry */
164 NB_PARSER_STATES
167 struct parser
169 FILE *file; /* pointer to a registry file */
170 WCHAR two_wchars[2]; /* first two characters from the encoding check */
171 BOOL is_unicode; /* parsing Unicode or ASCII data */
172 short int reg_version; /* registry file version */
173 HKEY hkey; /* current registry key */
174 WCHAR *key_name; /* current key name */
175 WCHAR *value_name; /* value name */
176 DWORD parse_type; /* generic data type for parsing */
177 DWORD data_type; /* data type */
178 void *data; /* value data */
179 DWORD data_size; /* size of the data (in bytes) */
180 BOOL backslash; /* TRUE if the current line contains a backslash */
181 enum parser_state state; /* current parser state */
184 typedef WCHAR *(*parser_state_func)(struct parser *parser, WCHAR *pos);
186 /* parser state machine functions */
187 static WCHAR *header_state(struct parser *parser, WCHAR *pos);
188 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos);
189 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos);
190 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos);
191 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos);
192 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos);
193 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos);
194 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos);
195 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos);
196 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos);
197 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos);
198 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos);
199 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos);
200 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos);
201 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos);
202 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos);
203 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos);
205 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
207 header_state, /* HEADER */
208 parse_win31_line_state, /* PARSE_WIN31_LINE */
209 line_start_state, /* LINE_START */
210 key_name_state, /* KEY_NAME */
211 delete_key_state, /* DELETE_KEY */
212 default_value_name_state, /* DEFAULT_VALUE_NAME */
213 quoted_value_name_state, /* QUOTED_VALUE_NAME */
214 data_start_state, /* DATA_START */
215 delete_value_state, /* DELETE_VALUE */
216 data_type_state, /* DATA_TYPE */
217 string_data_state, /* STRING_DATA */
218 dword_data_state, /* DWORD_DATA */
219 hex_data_state, /* HEX_DATA */
220 eol_backslash_state, /* EOL_BACKSLASH */
221 hex_multiline_state, /* HEX_MULTILINE */
222 unknown_data_state, /* UNKNOWN_DATA */
223 set_value_state, /* SET_VALUE */
226 /* set the new parser state and return the previous one */
227 static inline enum parser_state set_state(struct parser *parser, enum parser_state state)
229 enum parser_state ret = parser->state;
230 parser->state = state;
231 return ret;
234 /******************************************************************************
235 * Converts a hex representation of a DWORD into a DWORD.
237 static BOOL convert_hex_to_dword(WCHAR *str, DWORD *dw)
239 WCHAR *p, *end;
240 int count = 0;
242 while (*str == ' ' || *str == '\t') str++;
243 if (!*str) goto error;
245 p = str;
246 while (isxdigitW(*p))
248 count++;
249 p++;
251 if (count > 8) goto error;
253 end = p;
254 while (*p == ' ' || *p == '\t') p++;
255 if (*p && *p != ';') goto error;
257 *end = 0;
258 *dw = strtoulW(str, &end, 16);
259 return TRUE;
261 error:
262 return FALSE;
265 /******************************************************************************
266 * Converts comma-separated hex data into a binary string and modifies
267 * the input parameter to skip the concatenating backslash, if found.
269 * Returns TRUE or FALSE to indicate whether parsing was successful.
271 static BOOL convert_hex_csv_to_hex(struct parser *parser, WCHAR **str)
273 size_t size;
274 BYTE *d;
275 WCHAR *s;
277 parser->backslash = FALSE;
279 /* The worst case is 1 digit + 1 comma per byte */
280 size = ((lstrlenW(*str) + 1) / 2) + parser->data_size;
281 parser->data = heap_xrealloc(parser->data, size);
283 s = *str;
284 d = (BYTE *)parser->data + parser->data_size;
286 while (*s)
288 WCHAR *end;
289 unsigned long wc;
291 wc = strtoulW(s, &end, 16);
292 if (wc > 0xff) return FALSE;
294 if (s == end && wc == 0)
296 while (*end == ' ' || *end == '\t') end++;
297 if (*end == '\\')
299 parser->backslash = TRUE;
300 *str = end + 1;
301 return TRUE;
303 else if (*end == ';')
304 return TRUE;
305 return FALSE;
308 *d++ = wc;
309 parser->data_size++;
311 if (*end && *end != ',')
313 while (*end == ' ' || *end == '\t') end++;
314 if (*end && *end != ';') return FALSE;
315 return TRUE;
318 if (*end) end++;
319 s = end;
322 return TRUE;
325 /******************************************************************************
326 * Parses the data type of the registry value being imported and modifies
327 * the input parameter to skip the string representation of the data type.
329 * Returns TRUE or FALSE to indicate whether a data type was found.
331 static BOOL parse_data_type(struct parser *parser, WCHAR **line)
333 struct data_type { const WCHAR *tag; int len; int type; int parse_type; };
335 static const WCHAR quote[] = {'"'};
336 static const WCHAR hex[] = {'h','e','x',':'};
337 static const WCHAR dword[] = {'d','w','o','r','d',':'};
338 static const WCHAR hexp[] = {'h','e','x','('};
340 static const struct data_type data_types[] = {
341 /* tag len type parse type */
342 { quote, 1, REG_SZ, REG_SZ },
343 { hex, 4, REG_BINARY, REG_BINARY },
344 { dword, 6, REG_DWORD, REG_DWORD },
345 { hexp, 4, -1, REG_BINARY }, /* REG_NONE, REG_EXPAND_SZ, REG_MULTI_SZ */
346 { NULL, 0, 0, 0 }
349 const struct data_type *ptr;
351 for (ptr = data_types; ptr->tag; ptr++)
353 if (strncmpW(ptr->tag, *line, ptr->len))
354 continue;
356 parser->parse_type = ptr->parse_type;
357 parser->data_type = ptr->parse_type;
358 *line += ptr->len;
360 if (ptr->type == -1)
362 WCHAR *end;
363 DWORD val;
365 if (!**line || tolowerW((*line)[1]) == 'x')
366 return FALSE;
368 /* "hex(xx):" is special */
369 val = wcstoul(*line, &end, 16);
370 if (*end != ')' || *(end + 1) != ':' || (val == ~0u && errno == ERANGE))
371 return FALSE;
373 parser->data_type = val;
374 *line = end + 2;
376 return TRUE;
378 return FALSE;
381 /******************************************************************************
382 * Replaces escape sequences with their character equivalents and
383 * null-terminates the string on the first non-escaped double quote.
385 * Assigns a pointer to the remaining unparsed data in the line.
386 * Returns TRUE or FALSE to indicate whether a closing double quote was found.
388 static BOOL REGPROC_unescape_string(WCHAR *str, WCHAR **unparsed)
390 int str_idx = 0; /* current character under analysis */
391 int val_idx = 0; /* the last character of the unescaped string */
392 int len = lstrlenW(str);
393 BOOL ret;
395 for (str_idx = 0; str_idx < len; str_idx++, val_idx++) {
396 if (str[str_idx] == '\\') {
397 str_idx++;
398 switch (str[str_idx]) {
399 case 'n':
400 str[val_idx] = '\n';
401 break;
402 case 'r':
403 str[val_idx] = '\r';
404 break;
405 case '0':
406 str[val_idx] = '\0';
407 break;
408 case '\\':
409 case '"':
410 str[val_idx] = str[str_idx];
411 break;
412 default:
413 if (!str[str_idx]) return FALSE;
414 output_message(STRING_ESCAPE_SEQUENCE, str[str_idx]);
415 str[val_idx] = str[str_idx];
416 break;
418 } else if (str[str_idx] == '"') {
419 break;
420 } else {
421 str[val_idx] = str[str_idx];
425 ret = (str[str_idx] == '"');
426 *unparsed = str + str_idx + 1;
427 str[val_idx] = '\0';
428 return ret;
431 static HKEY parse_key_name(WCHAR *key_name, WCHAR **key_path)
433 unsigned int i;
435 if (!key_name) return 0;
437 *key_path = strchrW(key_name, '\\');
438 if (*key_path) (*key_path)++;
440 for (i = 0; i < ARRAY_SIZE(reg_class_keys); i++)
442 int len = lstrlenW(reg_class_namesW[i]);
443 if (!strncmpiW(key_name, reg_class_namesW[i], len) &&
444 (key_name[len] == 0 || key_name[len] == '\\'))
446 return reg_class_keys[i];
450 return 0;
453 static void close_key(struct parser *parser)
455 if (parser->hkey)
457 heap_free(parser->key_name);
458 parser->key_name = NULL;
460 RegCloseKey(parser->hkey);
461 parser->hkey = NULL;
465 /******************************************************************************
466 * Opens the registry key given by the input path.
467 * This key must be closed by calling close_key().
469 static LONG open_key(struct parser *parser, WCHAR *path)
471 HKEY key_class;
472 WCHAR *key_path;
473 LONG res;
475 close_key(parser);
477 /* Get the registry class */
478 if (!path || !(key_class = parse_key_name(path, &key_path)))
479 return ERROR_INVALID_PARAMETER;
481 res = RegCreateKeyExW(key_class, key_path, 0, NULL, REG_OPTION_NON_VOLATILE,
482 KEY_ALL_ACCESS, NULL, &parser->hkey, NULL);
484 if (res == ERROR_SUCCESS)
486 parser->key_name = heap_xalloc((lstrlenW(path) + 1) * sizeof(WCHAR));
487 lstrcpyW(parser->key_name, path);
489 else
490 parser->hkey = NULL;
492 return res;
495 static void free_parser_data(struct parser *parser)
497 if (parser->parse_type == REG_DWORD || parser->parse_type == REG_BINARY)
498 heap_free(parser->data);
500 parser->data = NULL;
501 parser->data_size = 0;
504 static void prepare_hex_string_data(struct parser *parser)
506 if (parser->data_type == REG_EXPAND_SZ || parser->data_type == REG_MULTI_SZ ||
507 parser->data_type == REG_SZ)
509 if (parser->is_unicode)
511 WCHAR *data = parser->data;
512 DWORD len = parser->data_size / sizeof(WCHAR);
514 if (data[len - 1] != 0)
516 data[len] = 0;
517 parser->data_size += sizeof(WCHAR);
520 else
522 BYTE *data = parser->data;
524 if (data[parser->data_size - 1] != 0)
526 data[parser->data_size] = 0;
527 parser->data_size++;
530 parser->data = GetWideStringN(parser->data, parser->data_size, &parser->data_size);
531 parser->data_size *= sizeof(WCHAR);
532 heap_free(data);
537 enum reg_versions {
538 REG_VERSION_31,
539 REG_VERSION_40,
540 REG_VERSION_50,
541 REG_VERSION_FUZZY,
542 REG_VERSION_INVALID
545 static enum reg_versions parse_file_header(const WCHAR *s)
547 static const WCHAR header_31[] = {'R','E','G','E','D','I','T',0};
548 static const WCHAR header_40[] = {'R','E','G','E','D','I','T','4',0};
549 static const WCHAR header_50[] = {'W','i','n','d','o','w','s',' ',
550 'R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ',
551 'V','e','r','s','i','o','n',' ','5','.','0','0',0};
553 while (*s == ' ' || *s == '\t') s++;
555 if (!strcmpW(s, header_31))
556 return REG_VERSION_31;
558 if (!strcmpW(s, header_40))
559 return REG_VERSION_40;
561 if (!strcmpW(s, header_50))
562 return REG_VERSION_50;
564 /* The Windows version accepts registry file headers beginning with "REGEDIT" and ending
565 * with other characters, as long as "REGEDIT" appears at the start of the line. For example,
566 * "REGEDIT 4", "REGEDIT9" and "REGEDIT4FOO" are all treated as valid file headers.
567 * In all such cases, however, the contents of the registry file are not imported.
569 if (!strncmpW(s, header_31, 7)) /* "REGEDIT" without NUL */
570 return REG_VERSION_FUZZY;
572 return REG_VERSION_INVALID;
575 /* handler for parser HEADER state */
576 static WCHAR *header_state(struct parser *parser, WCHAR *pos)
578 WCHAR *line, *header;
580 if (!(line = get_line(parser->file)))
581 return NULL;
583 if (!parser->is_unicode)
585 header = heap_xalloc((lstrlenW(line) + 3) * sizeof(WCHAR));
586 header[0] = parser->two_wchars[0];
587 header[1] = parser->two_wchars[1];
588 lstrcpyW(header + 2, line);
589 parser->reg_version = parse_file_header(header);
590 heap_free(header);
592 else parser->reg_version = parse_file_header(line);
594 switch (parser->reg_version)
596 case REG_VERSION_31:
597 set_state(parser, PARSE_WIN31_LINE);
598 break;
599 case REG_VERSION_40:
600 case REG_VERSION_50:
601 set_state(parser, LINE_START);
602 break;
603 default:
604 get_line(NULL); /* Reset static variables */
605 return NULL;
608 return line;
611 /* handler for parser PARSE_WIN31_LINE state */
612 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos)
614 WCHAR *line, *value;
615 static WCHAR hkcr[] = {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T'};
616 unsigned int key_end = 0;
618 if (!(line = get_line(parser->file)))
619 return NULL;
621 if (strncmpW(line, hkcr, ARRAY_SIZE(hkcr)))
622 return line;
624 /* get key name */
625 while (line[key_end] && !isspaceW(line[key_end])) key_end++;
627 value = line + key_end;
628 while (*value == ' ' || *value == '\t') value++;
630 if (*value == '=') value++;
631 if (*value == ' ') value++; /* at most one space is skipped */
633 line[key_end] = 0;
635 if (open_key(parser, line) != ERROR_SUCCESS)
637 output_message(STRING_OPEN_KEY_FAILED, line);
638 return line;
641 parser->value_name = NULL;
642 parser->data_type = REG_SZ;
643 parser->data = value;
644 parser->data_size = (lstrlenW(value) + 1) * sizeof(WCHAR);
646 set_state(parser, SET_VALUE);
647 return value;
650 /* handler for parser LINE_START state */
651 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos)
653 WCHAR *line, *p;
655 if (!(line = get_line(parser->file)))
656 return NULL;
658 for (p = line; *p; p++)
660 switch (*p)
662 case '[':
663 set_state(parser, KEY_NAME);
664 return p + 1;
665 case '@':
666 set_state(parser, DEFAULT_VALUE_NAME);
667 return p;
668 case '"':
669 set_state(parser, QUOTED_VALUE_NAME);
670 return p + 1;
671 case ' ':
672 case '\t':
673 break;
674 default:
675 return p;
679 return p;
682 /* handler for parser KEY_NAME state */
683 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos)
685 WCHAR *p = pos, *key_end;
687 if (*p == ' ' || *p == '\t' || !(key_end = strrchrW(p, ']')))
688 goto done;
690 *key_end = 0;
692 if (*p == '-')
694 set_state(parser, DELETE_KEY);
695 return p + 1;
697 else if (open_key(parser, p) != ERROR_SUCCESS)
698 output_message(STRING_OPEN_KEY_FAILED, p);
700 done:
701 set_state(parser, LINE_START);
702 return p;
705 /* handler for parser DELETE_KEY state */
706 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos)
708 WCHAR *p = pos;
710 close_key(parser);
712 if (*p == 'H' || *p == 'h')
713 delete_registry_key(p);
715 set_state(parser, LINE_START);
716 return p;
719 /* handler for parser DEFAULT_VALUE_NAME state */
720 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos)
722 heap_free(parser->value_name);
723 parser->value_name = NULL;
725 set_state(parser, DATA_START);
726 return pos + 1;
729 /* handler for parser QUOTED_VALUE_NAME state */
730 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos)
732 WCHAR *val_name = pos, *p;
734 if (parser->value_name)
736 heap_free(parser->value_name);
737 parser->value_name = NULL;
740 if (!REGPROC_unescape_string(val_name, &p))
741 goto invalid;
743 /* copy the value name in case we need to parse multiple lines and the buffer is overwritten */
744 parser->value_name = heap_xalloc((lstrlenW(val_name) + 1) * sizeof(WCHAR));
745 lstrcpyW(parser->value_name, val_name);
747 set_state(parser, DATA_START);
748 return p;
750 invalid:
751 set_state(parser, LINE_START);
752 return val_name;
755 /* handler for parser DATA_START state */
756 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos)
758 WCHAR *p = pos;
759 unsigned int len;
761 while (*p == ' ' || *p == '\t') p++;
762 if (*p != '=') goto done;
763 p++;
764 while (*p == ' ' || *p == '\t') p++;
766 /* trim trailing whitespace */
767 len = strlenW(p);
768 while (len > 0 && (p[len - 1] == ' ' || p[len - 1] == '\t')) len--;
769 p[len] = 0;
771 if (*p == '-')
772 set_state(parser, DELETE_VALUE);
773 else
774 set_state(parser, DATA_TYPE);
775 return p;
777 done:
778 set_state(parser, LINE_START);
779 return p;
782 /* handler for parser DELETE_VALUE state */
783 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos)
785 WCHAR *p = pos + 1;
787 while (*p == ' ' || *p == '\t') p++;
788 if (*p && *p != ';') goto done;
790 RegDeleteValueW(parser->hkey, parser->value_name);
792 done:
793 set_state(parser, LINE_START);
794 return p;
797 /* handler for parser DATA_TYPE state */
798 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos)
800 WCHAR *line = pos;
802 if (!parse_data_type(parser, &line))
804 set_state(parser, LINE_START);
805 return line;
808 switch (parser->parse_type)
810 case REG_SZ:
811 set_state(parser, STRING_DATA);
812 break;
813 case REG_DWORD:
814 set_state(parser, DWORD_DATA);
815 break;
816 case REG_BINARY: /* all hex data types, including undefined */
817 set_state(parser, HEX_DATA);
818 break;
819 default:
820 set_state(parser, UNKNOWN_DATA);
823 return line;
826 /* handler for parser STRING_DATA state */
827 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos)
829 WCHAR *line;
831 parser->data = pos;
833 if (!REGPROC_unescape_string(parser->data, &line))
834 goto invalid;
836 while (*line == ' ' || *line == '\t') line++;
837 if (*line && *line != ';') goto invalid;
839 parser->data_size = (lstrlenW(parser->data) + 1) * sizeof(WCHAR);
841 set_state(parser, SET_VALUE);
842 return line;
844 invalid:
845 free_parser_data(parser);
846 set_state(parser, LINE_START);
847 return line;
850 /* handler for parser DWORD_DATA state */
851 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos)
853 WCHAR *line = pos;
855 parser->data = heap_xalloc(sizeof(DWORD));
857 if (!convert_hex_to_dword(line, parser->data))
858 goto invalid;
860 parser->data_size = sizeof(DWORD);
862 set_state(parser, SET_VALUE);
863 return line;
865 invalid:
866 free_parser_data(parser);
867 set_state(parser, LINE_START);
868 return line;
871 /* handler for parser HEX_DATA state */
872 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos)
874 WCHAR *line = pos;
876 if (!*line)
877 goto set_value;
879 if (!convert_hex_csv_to_hex(parser, &line))
880 goto invalid;
882 if (parser->backslash)
884 set_state(parser, EOL_BACKSLASH);
885 return line;
888 prepare_hex_string_data(parser);
890 set_value:
891 set_state(parser, SET_VALUE);
892 return line;
894 invalid:
895 free_parser_data(parser);
896 set_state(parser, LINE_START);
897 return line;
900 /* handler for parser EOL_BACKSLASH state */
901 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos)
903 WCHAR *p = pos;
905 while (*p == ' ' || *p == '\t') p++;
906 if (*p && *p != ';') goto invalid;
908 set_state(parser, HEX_MULTILINE);
909 return pos;
911 invalid:
912 free_parser_data(parser);
913 set_state(parser, LINE_START);
914 return p;
917 /* handler for parser HEX_MULTILINE state */
918 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos)
920 WCHAR *line;
922 if (!(line = get_line(parser->file)))
924 prepare_hex_string_data(parser);
925 set_state(parser, SET_VALUE);
926 return pos;
929 while (*line == ' ' || *line == '\t') line++;
930 if (!*line || *line == ';') return line;
932 if (!isxdigitW(*line)) goto invalid;
934 set_state(parser, HEX_DATA);
935 return line;
937 invalid:
938 free_parser_data(parser);
939 set_state(parser, LINE_START);
940 return line;
943 /* handler for parser UNKNOWN_DATA state */
944 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos)
946 output_message(STRING_UNKNOWN_DATA_FORMAT, parser->data_type);
948 set_state(parser, LINE_START);
949 return pos;
952 /* handler for parser SET_VALUE state */
953 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos)
955 RegSetValueExW(parser->hkey, parser->value_name, 0, parser->data_type,
956 parser->data, parser->data_size);
958 free_parser_data(parser);
960 if (parser->reg_version == REG_VERSION_31)
961 set_state(parser, PARSE_WIN31_LINE);
962 else
963 set_state(parser, LINE_START);
965 return pos;
968 static WCHAR *get_lineA(FILE *fp)
970 static WCHAR *lineW;
971 static size_t size;
972 static char *buf, *next;
973 char *line;
975 heap_free(lineW);
977 if (!fp) goto cleanup;
979 if (!size)
981 size = REG_VAL_BUF_SIZE;
982 buf = heap_xalloc(size);
983 *buf = 0;
984 next = buf;
986 line = next;
988 while (next)
990 char *p = strpbrk(line, "\r\n");
991 if (!p)
993 size_t len, count;
994 len = strlen(next);
995 memmove(buf, next, len + 1);
996 if (size - len < 3)
998 size *= 2;
999 buf = heap_xrealloc(buf, size);
1001 if (!(count = fread(buf + len, 1, size - len - 1, fp)))
1003 next = NULL;
1004 lineW = GetWideString(buf);
1005 return lineW;
1007 buf[len + count] = 0;
1008 next = buf;
1009 line = buf;
1010 continue;
1012 next = p + 1;
1013 if (*p == '\r' && *(p + 1) == '\n') next++;
1014 *p = 0;
1015 lineW = GetWideString(line);
1016 return lineW;
1019 cleanup:
1020 lineW = NULL;
1021 if (size) heap_free(buf);
1022 size = 0;
1023 return NULL;
1026 static WCHAR *get_lineW(FILE *fp)
1028 static size_t size;
1029 static WCHAR *buf, *next;
1030 WCHAR *line;
1032 if (!fp) goto cleanup;
1034 if (!size)
1036 size = REG_VAL_BUF_SIZE;
1037 buf = heap_xalloc(size * sizeof(WCHAR));
1038 *buf = 0;
1039 next = buf;
1041 line = next;
1043 while (next)
1045 static const WCHAR line_endings[] = {'\r','\n',0};
1046 WCHAR *p = strpbrkW(line, line_endings);
1047 if (!p)
1049 size_t len, count;
1050 len = strlenW(next);
1051 memmove(buf, next, (len + 1) * sizeof(WCHAR));
1052 if (size - len < 3)
1054 size *= 2;
1055 buf = heap_xrealloc(buf, size * sizeof(WCHAR));
1057 if (!(count = fread(buf + len, sizeof(WCHAR), size - len - 1, fp)))
1059 next = NULL;
1060 return buf;
1062 buf[len + count] = 0;
1063 next = buf;
1064 line = buf;
1065 continue;
1067 next = p + 1;
1068 if (*p == '\r' && *(p + 1) == '\n') next++;
1069 *p = 0;
1070 return line;
1073 cleanup:
1074 if (size) heap_free(buf);
1075 size = 0;
1076 return NULL;
1079 /******************************************************************************
1080 * Reads contents of the specified file into the registry.
1082 BOOL import_registry_file(FILE *reg_file)
1084 BYTE s[2];
1085 struct parser parser;
1086 WCHAR *pos;
1088 if (!reg_file || (fread(s, 2, 1, reg_file) != 1))
1089 return FALSE;
1091 parser.is_unicode = (s[0] == 0xff && s[1] == 0xfe);
1092 get_line = parser.is_unicode ? get_lineW : get_lineA;
1094 parser.file = reg_file;
1095 parser.two_wchars[0] = s[0];
1096 parser.two_wchars[1] = s[1];
1097 parser.reg_version = -1;
1098 parser.hkey = NULL;
1099 parser.key_name = NULL;
1100 parser.value_name = NULL;
1101 parser.parse_type = 0;
1102 parser.data_type = 0;
1103 parser.data = NULL;
1104 parser.data_size = 0;
1105 parser.backslash = FALSE;
1106 parser.state = HEADER;
1108 pos = parser.two_wchars;
1110 /* parser main loop */
1111 while (pos)
1112 pos = (parser_funcs[parser.state])(&parser, pos);
1114 if (parser.reg_version == REG_VERSION_FUZZY || parser.reg_version == REG_VERSION_INVALID)
1115 return parser.reg_version == REG_VERSION_FUZZY;
1117 heap_free(parser.value_name);
1118 close_key(&parser);
1120 return TRUE;
1123 /******************************************************************************
1124 * Removes the registry key with all subkeys. Parses full key name.
1126 * Parameters:
1127 * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
1128 * empty, points to register key class, does not exist.
1130 void delete_registry_key(WCHAR *reg_key_name)
1132 WCHAR *key_name = NULL;
1133 HKEY key_class;
1135 if (!reg_key_name || !reg_key_name[0])
1136 return;
1138 if (!(key_class = parse_key_name(reg_key_name, &key_name)))
1140 if (key_name) *(key_name - 1) = 0;
1141 error_exit(STRING_INVALID_SYSTEM_KEY, reg_key_name);
1144 if (!key_name || !*key_name)
1145 error_exit(STRING_DELETE_FAILED, reg_key_name);
1147 RegDeleteTreeW(key_class, key_name);
1150 static void REGPROC_write_line(FILE *fp, const WCHAR *str, BOOL unicode)
1152 if (unicode)
1153 fwrite(str, sizeof(WCHAR), lstrlenW(str), fp);
1154 else
1156 char *strA = GetMultiByteString(str);
1157 fputs(strA, fp);
1158 heap_free(strA);
1162 static WCHAR *REGPROC_escape_string(WCHAR *str, size_t str_len, size_t *line_len)
1164 size_t i, escape_count, pos;
1165 WCHAR *buf;
1167 for (i = 0, escape_count = 0; i < str_len; i++)
1169 WCHAR c = str[i];
1171 if (!c) break;
1173 if (c == '\r' || c == '\n' || c == '\\' || c == '"')
1174 escape_count++;
1177 buf = heap_xalloc((str_len + escape_count + 1) * sizeof(WCHAR));
1179 for (i = 0, pos = 0; i < str_len; i++, pos++)
1181 WCHAR c = str[i];
1183 if (!c) break;
1185 switch (c)
1187 case '\r':
1188 buf[pos++] = '\\';
1189 buf[pos] = 'r';
1190 break;
1191 case '\n':
1192 buf[pos++] = '\\';
1193 buf[pos] = 'n';
1194 break;
1195 case '\\':
1196 buf[pos++] = '\\';
1197 buf[pos] = '\\';
1198 break;
1199 case '"':
1200 buf[pos++] = '\\';
1201 buf[pos] = '"';
1202 break;
1203 default:
1204 buf[pos] = c;
1208 buf[pos] = 0;
1209 *line_len = pos;
1210 return buf;
1213 static size_t export_value_name(FILE *fp, WCHAR *name, size_t len, BOOL unicode)
1215 static const WCHAR quoted_fmt[] = {'"','%','s','"','=',0};
1216 static const WCHAR default_name[] = {'@','=',0};
1217 size_t line_len;
1219 if (name && *name)
1221 WCHAR *str = REGPROC_escape_string(name, len, &line_len);
1222 WCHAR *buf = heap_xalloc((line_len + 4) * sizeof(WCHAR));
1223 line_len = sprintfW(buf, quoted_fmt, str);
1224 REGPROC_write_line(fp, buf, unicode);
1225 heap_free(buf);
1226 heap_free(str);
1228 else
1230 line_len = lstrlenW(default_name);
1231 REGPROC_write_line(fp, default_name, unicode);
1234 return line_len;
1237 static void export_string_data(WCHAR **buf, WCHAR *data, size_t size)
1239 size_t len = 0, line_len;
1240 WCHAR *str;
1241 static const WCHAR fmt[] = {'"','%','s','"',0};
1243 if (size)
1244 len = size / sizeof(WCHAR) - 1;
1245 str = REGPROC_escape_string(data, len, &line_len);
1246 *buf = heap_xalloc((line_len + 3) * sizeof(WCHAR));
1247 sprintfW(*buf, fmt, str);
1248 heap_free(str);
1251 static void export_dword_data(WCHAR **buf, DWORD *data)
1253 static const WCHAR fmt[] = {'d','w','o','r','d',':','%','0','8','x',0};
1255 *buf = heap_xalloc(15 * sizeof(WCHAR));
1256 sprintfW(*buf, fmt, *data);
1259 static size_t export_hex_data_type(FILE *fp, DWORD type, BOOL unicode)
1261 static const WCHAR hex[] = {'h','e','x',':',0};
1262 static const WCHAR hexp_fmt[] = {'h','e','x','(','%','x',')',':',0};
1263 size_t line_len;
1265 if (type == REG_BINARY)
1267 line_len = lstrlenW(hex);
1268 REGPROC_write_line(fp, hex, unicode);
1270 else
1272 WCHAR *buf = heap_xalloc(15 * sizeof(WCHAR));
1273 line_len = sprintfW(buf, hexp_fmt, type);
1274 REGPROC_write_line(fp, buf, unicode);
1275 heap_free(buf);
1278 return line_len;
1281 #define MAX_HEX_CHARS 77
1283 static void export_hex_data(FILE *fp, WCHAR **buf, DWORD type, DWORD line_len,
1284 void *data, DWORD size, BOOL unicode)
1286 static const WCHAR fmt[] = {'%','0','2','x',0};
1287 static const WCHAR hex_concat[] = {'\\','\r','\n',' ',' ',0};
1288 size_t num_commas, i, pos;
1290 line_len += export_hex_data_type(fp, type, unicode);
1292 if (!size) return;
1294 if (!unicode && (type == REG_EXPAND_SZ || type == REG_MULTI_SZ))
1295 data = GetMultiByteStringN(data, size / sizeof(WCHAR), &size);
1297 num_commas = size - 1;
1298 *buf = heap_xalloc(size * 3 * sizeof(WCHAR));
1300 for (i = 0, pos = 0; i < size; i++)
1302 pos += sprintfW(*buf + pos, fmt, ((BYTE *)data)[i]);
1303 if (i == num_commas) break;
1304 (*buf)[pos++] = ',';
1305 (*buf)[pos] = 0;
1306 line_len += 3;
1308 if (line_len >= MAX_HEX_CHARS)
1310 REGPROC_write_line(fp, *buf, unicode);
1311 REGPROC_write_line(fp, hex_concat, unicode);
1312 line_len = 2;
1313 pos = 0;
1318 static void export_newline(FILE *fp, BOOL unicode)
1320 static const WCHAR newline[] = {'\r','\n',0};
1322 REGPROC_write_line(fp, newline, unicode);
1325 static void export_data(FILE *fp, WCHAR *value_name, DWORD value_len, DWORD type,
1326 void *data, size_t size, BOOL unicode)
1328 WCHAR *buf = NULL;
1329 size_t line_len = export_value_name(fp, value_name, value_len, unicode);
1331 switch (type)
1333 case REG_SZ:
1334 export_string_data(&buf, data, size);
1335 break;
1336 case REG_DWORD:
1337 if (size)
1339 export_dword_data(&buf, data);
1340 break;
1342 /* fall through */
1343 case REG_NONE:
1344 case REG_EXPAND_SZ:
1345 case REG_BINARY:
1346 case REG_MULTI_SZ:
1347 default:
1348 export_hex_data(fp, &buf, type, line_len, data, size, unicode);
1349 break;
1352 if (size || type == REG_SZ)
1354 REGPROC_write_line(fp, buf, unicode);
1355 heap_free(buf);
1358 export_newline(fp, unicode);
1361 static WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len)
1363 WCHAR *subkey_path;
1364 static const WCHAR fmt[] = {'%','s','\\','%','s',0};
1366 subkey_path = heap_xalloc((path_len + subkey_len + 2) * sizeof(WCHAR));
1367 sprintfW(subkey_path, fmt, path, subkey_name);
1369 return subkey_path;
1372 static void export_key_name(FILE *fp, WCHAR *name, BOOL unicode)
1374 static const WCHAR fmt[] = {'\r','\n','[','%','s',']','\r','\n',0};
1375 WCHAR *buf;
1377 buf = heap_xalloc((lstrlenW(name) + 7) * sizeof(WCHAR));
1378 sprintfW(buf, fmt, name);
1379 REGPROC_write_line(fp, buf, unicode);
1380 heap_free(buf);
1383 #define MAX_SUBKEY_LEN 257
1385 static int export_registry_data(FILE *fp, HKEY key, WCHAR *path, BOOL unicode)
1387 LONG rc;
1388 DWORD max_value_len = 256, value_len;
1389 DWORD max_data_bytes = 2048, data_size;
1390 DWORD subkey_len;
1391 DWORD i, type, path_len;
1392 WCHAR *value_name, *subkey_name, *subkey_path;
1393 BYTE *data;
1394 HKEY subkey;
1396 export_key_name(fp, path, unicode);
1398 value_name = heap_xalloc(max_value_len * sizeof(WCHAR));
1399 data = heap_xalloc(max_data_bytes);
1401 i = 0;
1402 for (;;)
1404 value_len = max_value_len;
1405 data_size = max_data_bytes;
1406 rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size);
1407 if (rc == ERROR_SUCCESS)
1409 export_data(fp, value_name, value_len, type, data, data_size, unicode);
1410 i++;
1412 else if (rc == ERROR_MORE_DATA)
1414 if (data_size > max_data_bytes)
1416 max_data_bytes = data_size;
1417 data = heap_xrealloc(data, max_data_bytes);
1419 else
1421 max_value_len *= 2;
1422 value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR));
1425 else break;
1428 heap_free(data);
1429 heap_free(value_name);
1431 subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
1433 path_len = lstrlenW(path);
1435 i = 0;
1436 for (;;)
1438 subkey_len = MAX_SUBKEY_LEN;
1439 rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
1440 if (rc == ERROR_SUCCESS)
1442 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
1443 if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey))
1445 export_registry_data(fp, subkey, subkey_path, unicode);
1446 RegCloseKey(subkey);
1448 heap_free(subkey_path);
1449 i++;
1451 else break;
1454 heap_free(subkey_name);
1455 return 0;
1458 static FILE *REGPROC_open_export_file(WCHAR *file_name, BOOL unicode)
1460 FILE *file;
1461 static const WCHAR hyphen[] = {'-',0};
1463 if (!strcmpW(file_name, hyphen))
1465 file = stdout;
1466 _setmode(_fileno(file), _O_BINARY);
1468 else
1470 static const WCHAR wb_mode[] = {'w','b',0};
1472 file = _wfopen(file_name, wb_mode);
1473 if (!file)
1475 static const WCHAR regedit[] = {'r','e','g','e','d','i','t',0};
1476 _wperror(regedit);
1477 error_exit(STRING_CANNOT_OPEN_FILE, file_name);
1481 if (unicode)
1483 static const BYTE bom[] = {0xff,0xfe};
1484 static const WCHAR header[] = {'W','i','n','d','o','w','s',' ',
1485 'R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ',
1486 'V','e','r','s','i','o','n',' ','5','.','0','0','\r','\n'};
1488 fwrite(bom, sizeof(BYTE), ARRAY_SIZE(bom), file);
1489 fwrite(header, sizeof(WCHAR), ARRAY_SIZE(header), file);
1491 else
1492 fputs("REGEDIT4\r\n", file);
1494 return file;
1497 static HKEY open_export_key(HKEY key_class, WCHAR *subkey, WCHAR *path)
1499 HKEY key;
1501 if (!RegOpenKeyExW(key_class, subkey, 0, KEY_READ, &key))
1502 return key;
1504 output_message(STRING_OPEN_KEY_FAILED, path);
1505 return NULL;
1508 static BOOL export_key(WCHAR *file_name, WCHAR *path, BOOL unicode)
1510 HKEY key_class, key;
1511 WCHAR *subkey;
1512 FILE *fp;
1513 BOOL ret;
1515 if (!(key_class = parse_key_name(path, &subkey)))
1517 if (subkey) *(subkey - 1) = 0;
1518 output_message(STRING_INVALID_SYSTEM_KEY, path);
1519 return FALSE;
1522 if (!(key = open_export_key(key_class, subkey, path)))
1523 return FALSE;
1525 fp = REGPROC_open_export_file(file_name, unicode);
1526 ret = export_registry_data(fp, key, path, unicode);
1527 export_newline(fp, unicode);
1528 fclose(fp);
1530 RegCloseKey(key);
1531 return ret;
1534 static BOOL export_all(WCHAR *file_name, WCHAR *path, BOOL unicode)
1536 FILE *fp;
1537 int i;
1538 HKEY classes[] = {HKEY_LOCAL_MACHINE, HKEY_USERS}, key;
1539 WCHAR *class_name;
1541 fp = REGPROC_open_export_file(file_name, unicode);
1543 for (i = 0; i < ARRAY_SIZE(classes); i++)
1545 if (!(key = open_export_key(classes[i], NULL, path)))
1547 fclose(fp);
1548 return FALSE;
1551 class_name = heap_xalloc((lstrlenW(reg_class_namesW[i]) + 1) * sizeof(WCHAR));
1552 lstrcpyW(class_name, reg_class_namesW[i]);
1554 export_registry_data(fp, classes[i], class_name, unicode);
1556 heap_free(class_name);
1557 RegCloseKey(key);
1560 export_newline(fp, unicode);
1561 fclose(fp);
1563 return TRUE;
1566 BOOL export_registry_key(WCHAR *file_name, WCHAR *path, DWORD format)
1568 BOOL unicode = (format == REG_FORMAT_5);
1570 if (path && *path)
1571 return export_key(file_name, path, unicode);
1572 else
1573 return export_all(file_name, path, unicode);