include: Use proper dllimports for propsys functions.
[wine.git] / programs / regedit / regproc.c
blob15a64fdf97dac3e4d5dc5e9f584e1f6e97cb3101
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 <fcntl.h>
26 #include <io.h>
27 #include <windows.h>
28 #include <commctrl.h>
30 #include "main.h"
32 #define REG_VAL_BUF_SIZE 4096
34 static HKEY reg_class_keys[] = {
35 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
36 HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA
39 /******************************************************************************
40 * Allocates memory and converts input from multibyte to wide chars
41 * Returned string must be freed by the caller
43 static WCHAR* GetWideString(const char* strA)
45 if(strA)
47 WCHAR* strW;
48 int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0);
50 strW = malloc(len * sizeof(WCHAR));
51 MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len);
52 return strW;
54 return NULL;
57 /******************************************************************************
58 * Allocates memory and converts input from multibyte to wide chars
59 * Returned string must be freed by the caller
61 static WCHAR* GetWideStringN(const char* strA, int chars, DWORD *len)
63 if(strA)
65 WCHAR* strW;
66 *len = MultiByteToWideChar(CP_ACP, 0, strA, chars, NULL, 0);
68 strW = malloc(*len * sizeof(WCHAR));
69 MultiByteToWideChar(CP_ACP, 0, strA, chars, strW, *len);
70 return strW;
72 *len = 0;
73 return NULL;
76 /******************************************************************************
77 * Allocates memory and converts input from wide chars to multibyte
78 * Returned string must be freed by the caller
80 char* GetMultiByteString(const WCHAR* strW)
82 if(strW)
84 char* strA;
85 int len = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL);
87 strA = malloc(len);
88 WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, len, NULL, NULL);
89 return strA;
91 return NULL;
94 /******************************************************************************
95 * Allocates memory and converts input from wide chars to multibyte
96 * Returned string must be freed by the caller
98 static char* GetMultiByteStringN(const WCHAR* strW, int chars, DWORD* len)
100 if(strW)
102 char* strA;
103 *len = WideCharToMultiByte(CP_ACP, 0, strW, chars, NULL, 0, NULL, NULL);
105 strA = malloc(*len);
106 WideCharToMultiByte(CP_ACP, 0, strW, chars, strA, *len, NULL, NULL);
107 return strA;
109 *len = 0;
110 return NULL;
113 static WCHAR *(*get_line)(FILE *);
115 /* parser definitions */
116 enum parser_state
118 HEADER, /* parsing the registry file version header */
119 PARSE_WIN31_LINE, /* parsing a Windows 3.1 registry line */
120 LINE_START, /* at the beginning of a registry line */
121 KEY_NAME, /* parsing a key name */
122 DELETE_KEY, /* deleting a registry key */
123 DEFAULT_VALUE_NAME, /* parsing a default value name */
124 QUOTED_VALUE_NAME, /* parsing a double-quoted value name */
125 DATA_START, /* preparing for data parsing operations */
126 DELETE_VALUE, /* deleting a registry value */
127 DATA_TYPE, /* parsing the registry data type */
128 STRING_DATA, /* parsing REG_SZ data */
129 DWORD_DATA, /* parsing DWORD data */
130 HEX_DATA, /* parsing REG_BINARY, REG_NONE, REG_EXPAND_SZ or REG_MULTI_SZ data */
131 EOL_BACKSLASH, /* preparing to parse multiple lines of hex data */
132 HEX_MULTILINE, /* parsing multiple lines of hex data */
133 UNKNOWN_DATA, /* parsing an unhandled or invalid data type */
134 SET_VALUE, /* adding a value to the registry */
135 NB_PARSER_STATES
138 struct parser
140 FILE *file; /* pointer to a registry file */
141 WCHAR two_wchars[2]; /* first two characters from the encoding check */
142 BOOL is_unicode; /* parsing Unicode or ASCII data */
143 short int reg_version; /* registry file version */
144 HKEY hkey; /* current registry key */
145 WCHAR *key_name; /* current key name */
146 WCHAR *value_name; /* value name */
147 DWORD parse_type; /* generic data type for parsing */
148 DWORD data_type; /* data type */
149 void *data; /* value data */
150 DWORD data_size; /* size of the data (in bytes) */
151 BOOL backslash; /* TRUE if the current line contains a backslash */
152 enum parser_state state; /* current parser state */
155 typedef WCHAR *(*parser_state_func)(struct parser *parser, WCHAR *pos);
157 /* parser state machine functions */
158 static WCHAR *header_state(struct parser *parser, WCHAR *pos);
159 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos);
160 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos);
161 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos);
162 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos);
163 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos);
164 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos);
165 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos);
166 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos);
167 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos);
168 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos);
169 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos);
170 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos);
171 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos);
172 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos);
173 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos);
174 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos);
176 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
178 header_state, /* HEADER */
179 parse_win31_line_state, /* PARSE_WIN31_LINE */
180 line_start_state, /* LINE_START */
181 key_name_state, /* KEY_NAME */
182 delete_key_state, /* DELETE_KEY */
183 default_value_name_state, /* DEFAULT_VALUE_NAME */
184 quoted_value_name_state, /* QUOTED_VALUE_NAME */
185 data_start_state, /* DATA_START */
186 delete_value_state, /* DELETE_VALUE */
187 data_type_state, /* DATA_TYPE */
188 string_data_state, /* STRING_DATA */
189 dword_data_state, /* DWORD_DATA */
190 hex_data_state, /* HEX_DATA */
191 eol_backslash_state, /* EOL_BACKSLASH */
192 hex_multiline_state, /* HEX_MULTILINE */
193 unknown_data_state, /* UNKNOWN_DATA */
194 set_value_state, /* SET_VALUE */
197 /* set the new parser state and return the previous one */
198 static inline enum parser_state set_state(struct parser *parser, enum parser_state state)
200 enum parser_state ret = parser->state;
201 parser->state = state;
202 return ret;
205 /******************************************************************************
206 * Converts a hex representation of a DWORD into a DWORD.
208 static BOOL convert_hex_to_dword(WCHAR *str, DWORD *dw)
210 WCHAR *p, *end;
211 int count = 0;
213 while (*str == ' ' || *str == '\t') str++;
214 if (!*str) goto error;
216 p = str;
217 while (iswxdigit(*p))
219 count++;
220 p++;
222 if (count > 8) goto error;
224 end = p;
225 while (*p == ' ' || *p == '\t') p++;
226 if (*p && *p != ';') goto error;
228 *end = 0;
229 *dw = wcstoul(str, &end, 16);
230 return TRUE;
232 error:
233 return FALSE;
236 /******************************************************************************
237 * Converts comma-separated hex data into a binary string and modifies
238 * the input parameter to skip the concatenating backslash, if found.
240 * Returns TRUE or FALSE to indicate whether parsing was successful.
242 static BOOL convert_hex_csv_to_hex(struct parser *parser, WCHAR **str)
244 size_t size;
245 BYTE *d;
246 WCHAR *s;
248 parser->backslash = FALSE;
250 /* The worst case is 1 digit + 1 comma per byte */
251 size = ((lstrlenW(*str) + 1) / 2) + parser->data_size;
252 parser->data = realloc(parser->data, size);
254 s = *str;
255 d = (BYTE *)parser->data + parser->data_size;
257 while (*s)
259 WCHAR *end;
260 unsigned long wc;
262 wc = wcstoul(s, &end, 16);
263 if (wc > 0xff) return FALSE;
265 if (s == end && wc == 0)
267 while (*end == ' ' || *end == '\t') end++;
268 if (*end == '\\')
270 parser->backslash = TRUE;
271 *str = end + 1;
272 return TRUE;
274 else if (*end == ';')
275 return TRUE;
276 return FALSE;
279 *d++ = wc;
280 parser->data_size++;
282 if (*end && *end != ',')
284 while (*end == ' ' || *end == '\t') end++;
285 if (*end && *end != ';') return FALSE;
286 return TRUE;
289 if (*end) end++;
290 s = end;
293 return TRUE;
296 /******************************************************************************
297 * Parses the data type of the registry value being imported and modifies
298 * the input parameter to skip the string representation of the data type.
300 * Returns TRUE or FALSE to indicate whether a data type was found.
302 static BOOL parse_data_type(struct parser *parser, WCHAR **line)
304 struct data_type { const WCHAR *tag; int len; int type; int parse_type; };
306 static const struct data_type data_types[] = {
307 /* tag len type parse type */
308 { L"\"", 1, REG_SZ, REG_SZ },
309 { L"hex:", 4, REG_BINARY, REG_BINARY },
310 { L"dword:", 6, REG_DWORD, REG_DWORD },
311 { L"hex(", 4, -1, REG_BINARY }, /* REG_NONE, REG_EXPAND_SZ, REG_MULTI_SZ */
312 { NULL, 0, 0, 0 }
315 const struct data_type *ptr;
317 for (ptr = data_types; ptr->tag; ptr++)
319 if (wcsncmp(ptr->tag, *line, ptr->len))
320 continue;
322 parser->parse_type = ptr->parse_type;
323 parser->data_type = ptr->parse_type;
324 *line += ptr->len;
326 if (ptr->type == -1)
328 WCHAR *end;
329 DWORD val;
331 if (!**line || towlower((*line)[1]) == 'x')
332 return FALSE;
334 /* "hex(xx):" is special */
335 val = wcstoul(*line, &end, 16);
336 if (*end != ')' || *(end + 1) != ':' || (val == ~0u && errno == ERANGE))
337 return FALSE;
339 parser->data_type = val;
340 *line = end + 2;
342 return TRUE;
344 return FALSE;
347 /******************************************************************************
348 * Replaces escape sequences with their character equivalents and
349 * null-terminates the string on the first non-escaped double quote.
351 * Assigns a pointer to the remaining unparsed data in the line.
352 * Returns TRUE or FALSE to indicate whether a closing double quote was found.
354 static BOOL REGPROC_unescape_string(WCHAR *str, WCHAR **unparsed)
356 int str_idx = 0; /* current character under analysis */
357 int val_idx = 0; /* the last character of the unescaped string */
358 int len = lstrlenW(str);
359 BOOL ret;
361 for (str_idx = 0; str_idx < len; str_idx++, val_idx++) {
362 if (str[str_idx] == '\\') {
363 str_idx++;
364 switch (str[str_idx]) {
365 case 'n':
366 str[val_idx] = '\n';
367 break;
368 case 'r':
369 str[val_idx] = '\r';
370 break;
371 case '0':
372 return FALSE;
373 case '\\':
374 case '"':
375 str[val_idx] = str[str_idx];
376 break;
377 default:
378 if (!str[str_idx]) return FALSE;
379 output_message(STRING_ESCAPE_SEQUENCE, str[str_idx]);
380 str[val_idx] = str[str_idx];
381 break;
383 } else if (str[str_idx] == '"') {
384 break;
385 } else {
386 str[val_idx] = str[str_idx];
390 ret = (str[str_idx] == '"');
391 *unparsed = str + str_idx + 1;
392 str[val_idx] = '\0';
393 return ret;
396 static HKEY parse_key_name(WCHAR *key_name, WCHAR **key_path)
398 unsigned int i;
400 if (!key_name) return 0;
402 *key_path = wcschr(key_name, '\\');
403 if (*key_path) (*key_path)++;
405 for (i = 0; i < ARRAY_SIZE(reg_class_keys); i++)
407 int len = lstrlenW(reg_class_namesW[i]);
408 if (!wcsnicmp(key_name, reg_class_namesW[i], len) &&
409 (key_name[len] == 0 || key_name[len] == '\\'))
411 return reg_class_keys[i];
415 return 0;
418 static void close_key(struct parser *parser)
420 if (parser->hkey)
422 free(parser->key_name);
423 parser->key_name = NULL;
425 RegCloseKey(parser->hkey);
426 parser->hkey = NULL;
430 /******************************************************************************
431 * Opens the registry key given by the input path.
432 * This key must be closed by calling close_key().
434 static LONG open_key(struct parser *parser, WCHAR *path)
436 HKEY key_class;
437 WCHAR *key_path;
438 LONG res;
440 close_key(parser);
442 /* Get the registry class */
443 if (!path || !(key_class = parse_key_name(path, &key_path)))
444 return ERROR_INVALID_PARAMETER;
446 res = RegCreateKeyExW(key_class, key_path, 0, NULL, REG_OPTION_NON_VOLATILE,
447 KEY_ALL_ACCESS, NULL, &parser->hkey, NULL);
449 if (res == ERROR_SUCCESS)
450 parser->key_name = wcsdup(path);
451 else
452 parser->hkey = NULL;
454 return res;
457 static void free_parser_data(struct parser *parser)
459 if (parser->parse_type == REG_DWORD || parser->parse_type == REG_BINARY)
460 free(parser->data);
462 parser->data = NULL;
463 parser->data_size = 0;
466 static void prepare_hex_string_data(struct parser *parser)
468 if (parser->data_type == REG_EXPAND_SZ || parser->data_type == REG_MULTI_SZ ||
469 parser->data_type == REG_SZ)
471 if (parser->is_unicode)
473 WCHAR *data = parser->data;
474 DWORD len = parser->data_size / sizeof(WCHAR);
476 if (data[len - 1] != 0)
478 data[len] = 0;
479 parser->data_size += sizeof(WCHAR);
482 else
484 BYTE *data = parser->data;
486 if (data[parser->data_size - 1] != 0)
488 data[parser->data_size] = 0;
489 parser->data_size++;
492 parser->data = GetWideStringN(parser->data, parser->data_size, &parser->data_size);
493 parser->data_size *= sizeof(WCHAR);
494 free(data);
499 enum reg_versions {
500 REG_VERSION_31,
501 REG_VERSION_40,
502 REG_VERSION_50,
503 REG_VERSION_FUZZY,
504 REG_VERSION_INVALID
507 static enum reg_versions parse_file_header(const WCHAR *s)
509 static const WCHAR header_31[] = L"REGEDIT";
511 while (*s == ' ' || *s == '\t') s++;
513 if (!lstrcmpW(s, header_31))
514 return REG_VERSION_31;
516 if (!lstrcmpW(s, L"REGEDIT4"))
517 return REG_VERSION_40;
519 if (!lstrcmpW(s, L"Windows Registry Editor Version 5.00"))
520 return REG_VERSION_50;
522 /* The Windows version accepts registry file headers beginning with "REGEDIT" and ending
523 * with other characters, as long as "REGEDIT" appears at the start of the line. For example,
524 * "REGEDIT 4", "REGEDIT9" and "REGEDIT4FOO" are all treated as valid file headers.
525 * In all such cases, however, the contents of the registry file are not imported.
527 if (!wcsncmp(s, header_31, 7)) /* "REGEDIT" without NUL */
528 return REG_VERSION_FUZZY;
530 return REG_VERSION_INVALID;
533 /* handler for parser HEADER state */
534 static WCHAR *header_state(struct parser *parser, WCHAR *pos)
536 WCHAR *line, *header;
538 if (!(line = get_line(parser->file)))
539 return NULL;
541 if (!parser->is_unicode)
543 header = malloc((lstrlenW(line) + 3) * sizeof(WCHAR));
544 header[0] = parser->two_wchars[0];
545 header[1] = parser->two_wchars[1];
546 lstrcpyW(header + 2, line);
547 parser->reg_version = parse_file_header(header);
548 free(header);
550 else parser->reg_version = parse_file_header(line);
552 switch (parser->reg_version)
554 case REG_VERSION_31:
555 set_state(parser, PARSE_WIN31_LINE);
556 break;
557 case REG_VERSION_40:
558 case REG_VERSION_50:
559 set_state(parser, LINE_START);
560 break;
561 default:
562 get_line(NULL); /* Reset static variables */
563 return NULL;
566 return line;
569 /* handler for parser PARSE_WIN31_LINE state */
570 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos)
572 WCHAR *line, *value;
573 static WCHAR hkcr[] = L"HKEY_CLASSES_ROOT";
574 unsigned int key_end = 0;
576 if (!(line = get_line(parser->file)))
577 return NULL;
579 if (wcsncmp(line, hkcr, lstrlenW(hkcr)))
580 return line;
582 /* get key name */
583 while (line[key_end] && !iswspace(line[key_end])) key_end++;
585 value = line + key_end;
586 while (*value == ' ' || *value == '\t') value++;
588 if (*value == '=') value++;
589 if (*value == ' ') value++; /* at most one space is skipped */
591 line[key_end] = 0;
593 if (open_key(parser, line) != ERROR_SUCCESS)
595 output_message(STRING_OPEN_KEY_FAILED, line);
596 return line;
599 parser->value_name = NULL;
600 parser->data_type = REG_SZ;
601 parser->data = value;
602 parser->data_size = (lstrlenW(value) + 1) * sizeof(WCHAR);
604 set_state(parser, SET_VALUE);
605 return value;
608 /* handler for parser LINE_START state */
609 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos)
611 WCHAR *line, *p;
613 if (!(line = get_line(parser->file)))
614 return NULL;
616 for (p = line; *p; p++)
618 switch (*p)
620 case '[':
621 set_state(parser, KEY_NAME);
622 return p + 1;
623 case '@':
624 set_state(parser, DEFAULT_VALUE_NAME);
625 return p;
626 case '"':
627 set_state(parser, QUOTED_VALUE_NAME);
628 return p + 1;
629 case ' ':
630 case '\t':
631 break;
632 default:
633 return p;
637 return p;
640 /* handler for parser KEY_NAME state */
641 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos)
643 WCHAR *p = pos, *key_end;
645 if (*p == ' ' || *p == '\t' || !(key_end = wcsrchr(p, ']')))
646 goto done;
648 *key_end = 0;
650 if (*p == '-')
652 set_state(parser, DELETE_KEY);
653 return p + 1;
655 else if (open_key(parser, p) != ERROR_SUCCESS)
656 output_message(STRING_OPEN_KEY_FAILED, p);
658 done:
659 set_state(parser, LINE_START);
660 return p;
663 /* handler for parser DELETE_KEY state */
664 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos)
666 WCHAR *p = pos;
668 close_key(parser);
670 if (*p == 'H' || *p == 'h')
671 delete_registry_key(p);
673 set_state(parser, LINE_START);
674 return p;
677 /* handler for parser DEFAULT_VALUE_NAME state */
678 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos)
680 free(parser->value_name);
681 parser->value_name = NULL;
683 set_state(parser, DATA_START);
684 return pos + 1;
687 /* handler for parser QUOTED_VALUE_NAME state */
688 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos)
690 WCHAR *val_name = pos, *p;
692 free(parser->value_name);
693 parser->value_name = NULL;
695 if (!REGPROC_unescape_string(val_name, &p))
696 goto invalid;
698 /* copy the value name in case we need to parse multiple lines and the buffer is overwritten */
699 parser->value_name = wcsdup(val_name);
701 set_state(parser, DATA_START);
702 return p;
704 invalid:
705 set_state(parser, LINE_START);
706 return val_name;
709 /* handler for parser DATA_START state */
710 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos)
712 WCHAR *p = pos;
713 unsigned int len;
715 while (*p == ' ' || *p == '\t') p++;
716 if (*p != '=') goto done;
717 p++;
718 while (*p == ' ' || *p == '\t') p++;
720 /* trim trailing whitespace */
721 len = lstrlenW(p);
722 while (len > 0 && (p[len - 1] == ' ' || p[len - 1] == '\t')) len--;
723 p[len] = 0;
725 if (*p == '-')
726 set_state(parser, DELETE_VALUE);
727 else
728 set_state(parser, DATA_TYPE);
729 return p;
731 done:
732 set_state(parser, LINE_START);
733 return p;
736 /* handler for parser DELETE_VALUE state */
737 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos)
739 WCHAR *p = pos + 1;
741 while (*p == ' ' || *p == '\t') p++;
742 if (*p && *p != ';') goto done;
744 RegDeleteValueW(parser->hkey, parser->value_name);
746 done:
747 set_state(parser, LINE_START);
748 return p;
751 /* handler for parser DATA_TYPE state */
752 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos)
754 WCHAR *line = pos;
756 if (!parse_data_type(parser, &line))
758 set_state(parser, LINE_START);
759 return line;
762 switch (parser->parse_type)
764 case REG_SZ:
765 set_state(parser, STRING_DATA);
766 break;
767 case REG_DWORD:
768 set_state(parser, DWORD_DATA);
769 break;
770 case REG_BINARY: /* all hex data types, including undefined */
771 set_state(parser, HEX_DATA);
772 break;
773 default:
774 set_state(parser, UNKNOWN_DATA);
777 return line;
780 /* handler for parser STRING_DATA state */
781 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos)
783 WCHAR *line;
785 parser->data = pos;
787 if (!REGPROC_unescape_string(parser->data, &line))
788 goto invalid;
790 while (*line == ' ' || *line == '\t') line++;
791 if (*line && *line != ';') goto invalid;
793 parser->data_size = (lstrlenW(parser->data) + 1) * sizeof(WCHAR);
795 set_state(parser, SET_VALUE);
796 return line;
798 invalid:
799 free_parser_data(parser);
800 set_state(parser, LINE_START);
801 return line;
804 /* handler for parser DWORD_DATA state */
805 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos)
807 WCHAR *line = pos;
809 parser->data = malloc(sizeof(DWORD));
811 if (!convert_hex_to_dword(line, parser->data))
812 goto invalid;
814 parser->data_size = sizeof(DWORD);
816 set_state(parser, SET_VALUE);
817 return line;
819 invalid:
820 free_parser_data(parser);
821 set_state(parser, LINE_START);
822 return line;
825 /* handler for parser HEX_DATA state */
826 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos)
828 WCHAR *line = pos;
830 if (!*line)
831 goto set_value;
833 if (!convert_hex_csv_to_hex(parser, &line))
834 goto invalid;
836 if (parser->backslash)
838 set_state(parser, EOL_BACKSLASH);
839 return line;
842 prepare_hex_string_data(parser);
844 set_value:
845 set_state(parser, SET_VALUE);
846 return line;
848 invalid:
849 free_parser_data(parser);
850 set_state(parser, LINE_START);
851 return line;
854 /* handler for parser EOL_BACKSLASH state */
855 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos)
857 WCHAR *p = pos;
859 while (*p == ' ' || *p == '\t') p++;
860 if (*p && *p != ';') goto invalid;
862 set_state(parser, HEX_MULTILINE);
863 return pos;
865 invalid:
866 free_parser_data(parser);
867 set_state(parser, LINE_START);
868 return p;
871 /* handler for parser HEX_MULTILINE state */
872 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos)
874 WCHAR *line;
876 if (!(line = get_line(parser->file)))
878 prepare_hex_string_data(parser);
879 set_state(parser, SET_VALUE);
880 return pos;
883 while (*line == ' ' || *line == '\t') line++;
884 if (!*line || *line == ';') return line;
886 if (!iswxdigit(*line)) goto invalid;
888 set_state(parser, HEX_DATA);
889 return line;
891 invalid:
892 free_parser_data(parser);
893 set_state(parser, LINE_START);
894 return line;
897 /* handler for parser UNKNOWN_DATA state */
898 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos)
900 output_message(STRING_UNKNOWN_DATA_FORMAT, parser->data_type);
902 set_state(parser, LINE_START);
903 return pos;
906 /* handler for parser SET_VALUE state */
907 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos)
909 RegSetValueExW(parser->hkey, parser->value_name, 0, parser->data_type,
910 parser->data, parser->data_size);
912 free_parser_data(parser);
914 if (parser->reg_version == REG_VERSION_31)
915 set_state(parser, PARSE_WIN31_LINE);
916 else
917 set_state(parser, LINE_START);
919 return pos;
922 static WCHAR *get_lineA(FILE *fp)
924 static WCHAR *lineW;
925 static size_t size;
926 static char *buf, *next;
927 char *line;
929 free(lineW);
931 if (!fp) goto cleanup;
933 if (!size)
935 size = REG_VAL_BUF_SIZE;
936 buf = malloc(size);
937 *buf = 0;
938 next = buf;
940 line = next;
942 while (next)
944 char *p = strpbrk(line, "\r\n");
945 if (!p)
947 size_t len, count;
948 len = strlen(next);
949 memmove(buf, next, len + 1);
950 if (size - len < 3)
952 size *= 2;
953 buf = realloc(buf, size);
955 if (!(count = fread(buf + len, 1, size - len - 1, fp)))
957 next = NULL;
958 lineW = GetWideString(buf);
959 return lineW;
961 buf[len + count] = 0;
962 next = buf;
963 line = buf;
964 continue;
966 next = p + 1;
967 if (*p == '\r' && *(p + 1) == '\n') next++;
968 *p = 0;
969 lineW = GetWideString(line);
970 return lineW;
973 cleanup:
974 lineW = NULL;
975 if (size) free(buf);
976 size = 0;
977 return NULL;
980 static WCHAR *get_lineW(FILE *fp)
982 static size_t size;
983 static WCHAR *buf, *next;
984 WCHAR *line;
986 if (!fp) goto cleanup;
988 if (!size)
990 size = REG_VAL_BUF_SIZE;
991 buf = malloc(size * sizeof(WCHAR));
992 *buf = 0;
993 next = buf;
995 line = next;
997 while (next)
999 WCHAR *p = wcspbrk(line, L"\r\n");
1000 if (!p)
1002 size_t len, count;
1003 len = lstrlenW(next);
1004 memmove(buf, next, (len + 1) * sizeof(WCHAR));
1005 if (size - len < 3)
1007 size *= 2;
1008 buf = realloc(buf, size * sizeof(WCHAR));
1010 if (!(count = fread(buf + len, sizeof(WCHAR), size - len - 1, fp)))
1012 next = NULL;
1013 return buf;
1015 buf[len + count] = 0;
1016 next = buf;
1017 line = buf;
1018 continue;
1020 next = p + 1;
1021 if (*p == '\r' && *(p + 1) == '\n') next++;
1022 *p = 0;
1023 return line;
1026 cleanup:
1027 if (size) free(buf);
1028 size = 0;
1029 return NULL;
1032 /******************************************************************************
1033 * Reads contents of the specified file into the registry.
1035 BOOL import_registry_file(FILE *reg_file)
1037 BYTE s[2];
1038 struct parser parser;
1039 WCHAR *pos;
1041 if (!reg_file || (fread(s, 2, 1, reg_file) != 1))
1042 return FALSE;
1044 parser.is_unicode = (s[0] == 0xff && s[1] == 0xfe);
1045 get_line = parser.is_unicode ? get_lineW : get_lineA;
1047 parser.file = reg_file;
1048 parser.two_wchars[0] = s[0];
1049 parser.two_wchars[1] = s[1];
1050 parser.reg_version = -1;
1051 parser.hkey = NULL;
1052 parser.key_name = NULL;
1053 parser.value_name = NULL;
1054 parser.parse_type = 0;
1055 parser.data_type = 0;
1056 parser.data = NULL;
1057 parser.data_size = 0;
1058 parser.backslash = FALSE;
1059 parser.state = HEADER;
1061 pos = parser.two_wchars;
1063 /* parser main loop */
1064 while (pos)
1065 pos = (parser_funcs[parser.state])(&parser, pos);
1067 if (parser.reg_version == REG_VERSION_FUZZY || parser.reg_version == REG_VERSION_INVALID)
1068 return parser.reg_version == REG_VERSION_FUZZY;
1070 free(parser.value_name);
1071 close_key(&parser);
1073 return TRUE;
1076 /******************************************************************************
1077 * Removes the registry key with all subkeys. Parses full key name.
1079 * Parameters:
1080 * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
1081 * empty, points to register key class, does not exist.
1083 void delete_registry_key(WCHAR *reg_key_name)
1085 WCHAR *key_name = NULL;
1086 HKEY key_class;
1088 if (!reg_key_name || !reg_key_name[0])
1089 return;
1091 if (!(key_class = parse_key_name(reg_key_name, &key_name)))
1093 if (key_name) *(key_name - 1) = 0;
1094 error_exit(STRING_INVALID_SYSTEM_KEY, reg_key_name);
1097 if (!key_name || !*key_name)
1098 error_exit(STRING_DELETE_FAILED, reg_key_name);
1100 RegDeleteTreeW(key_class, key_name);
1103 static void REGPROC_write_line(FILE *fp, const WCHAR *str, BOOL unicode)
1105 if (unicode)
1106 fwrite(str, sizeof(WCHAR), lstrlenW(str), fp);
1107 else
1109 char *strA = GetMultiByteString(str);
1110 fputs(strA, fp);
1111 free(strA);
1115 static WCHAR *REGPROC_escape_string(WCHAR *str, size_t str_len, size_t *line_len)
1117 size_t i, escape_count, pos;
1118 WCHAR *buf;
1120 for (i = 0, escape_count = 0; i < str_len; i++)
1122 WCHAR c = str[i];
1124 if (!c) break;
1126 if (c == '\r' || c == '\n' || c == '\\' || c == '"')
1127 escape_count++;
1130 buf = malloc((str_len + escape_count + 1) * sizeof(WCHAR));
1132 for (i = 0, pos = 0; i < str_len; i++, pos++)
1134 WCHAR c = str[i];
1136 if (!c) break;
1138 switch (c)
1140 case '\r':
1141 buf[pos++] = '\\';
1142 buf[pos] = 'r';
1143 break;
1144 case '\n':
1145 buf[pos++] = '\\';
1146 buf[pos] = 'n';
1147 break;
1148 case '\\':
1149 buf[pos++] = '\\';
1150 buf[pos] = '\\';
1151 break;
1152 case '"':
1153 buf[pos++] = '\\';
1154 buf[pos] = '"';
1155 break;
1156 default:
1157 buf[pos] = c;
1161 buf[pos] = 0;
1162 *line_len = pos;
1163 return buf;
1166 static size_t export_value_name(FILE *fp, WCHAR *name, size_t len, BOOL unicode)
1168 static const WCHAR default_name[] = L"@=";
1169 size_t line_len;
1171 if (name && *name)
1173 WCHAR *str = REGPROC_escape_string(name, len, &line_len);
1174 WCHAR *buf = malloc((line_len + 4) * sizeof(WCHAR));
1175 line_len = swprintf(buf, line_len + 4, L"\"%s\"=", str);
1176 REGPROC_write_line(fp, buf, unicode);
1177 free(buf);
1178 free(str);
1180 else
1182 line_len = lstrlenW(default_name);
1183 REGPROC_write_line(fp, default_name, unicode);
1186 return line_len;
1189 static void export_string_data(WCHAR **buf, WCHAR *data, size_t size)
1191 size_t len = 0, line_len;
1192 WCHAR *str;
1194 if (size)
1195 len = size / sizeof(WCHAR) - 1;
1196 str = REGPROC_escape_string(data, len, &line_len);
1197 *buf = malloc((line_len + 3) * sizeof(WCHAR));
1198 swprintf(*buf, line_len + 3, L"\"%s\"", str);
1199 free(str);
1202 static void export_dword_data(WCHAR **buf, DWORD *data)
1204 *buf = malloc(15 * sizeof(WCHAR));
1205 swprintf(*buf, 15, L"dword:%08x", *data);
1208 static size_t export_hex_data_type(FILE *fp, DWORD type, BOOL unicode)
1210 static const WCHAR hex[] = L"hex:";
1211 size_t line_len;
1213 if (type == REG_BINARY)
1215 line_len = lstrlenW(hex);
1216 REGPROC_write_line(fp, hex, unicode);
1218 else
1220 WCHAR *buf = malloc(15 * sizeof(WCHAR));
1221 line_len = swprintf(buf, 15, L"hex(%x):", type);
1222 REGPROC_write_line(fp, buf, unicode);
1223 free(buf);
1226 return line_len;
1229 #define MAX_HEX_CHARS 77
1231 static void export_hex_data(FILE *fp, WCHAR **buf, DWORD type, DWORD line_len,
1232 void *data, DWORD size, BOOL unicode)
1234 size_t num_commas, i, pos;
1236 line_len += export_hex_data_type(fp, type, unicode);
1238 if (!size) return;
1240 if (!unicode && (type == REG_EXPAND_SZ || type == REG_MULTI_SZ))
1241 data = GetMultiByteStringN(data, size / sizeof(WCHAR), &size);
1243 num_commas = size - 1;
1244 *buf = malloc(size * 3 * sizeof(WCHAR));
1246 for (i = 0, pos = 0; i < size; i++)
1248 pos += swprintf(*buf + pos, 3, L"%02x", ((BYTE *)data)[i]);
1249 if (i == num_commas) break;
1250 (*buf)[pos++] = ',';
1251 (*buf)[pos] = 0;
1252 line_len += 3;
1254 if (line_len >= MAX_HEX_CHARS)
1256 REGPROC_write_line(fp, *buf, unicode);
1257 REGPROC_write_line(fp, L"\\\r\n ", unicode);
1258 line_len = 2;
1259 pos = 0;
1264 static void export_newline(FILE *fp, BOOL unicode)
1266 REGPROC_write_line(fp, L"\r\n", unicode);
1269 static void export_data(FILE *fp, WCHAR *value_name, DWORD value_len, DWORD type,
1270 void *data, size_t size, BOOL unicode)
1272 WCHAR *buf = NULL;
1273 size_t line_len = export_value_name(fp, value_name, value_len, unicode);
1275 switch (type)
1277 case REG_SZ:
1278 export_string_data(&buf, data, size);
1279 break;
1280 case REG_DWORD:
1281 if (size == sizeof(DWORD))
1283 export_dword_data(&buf, data);
1284 break;
1286 /* fall through */
1287 case REG_NONE:
1288 case REG_EXPAND_SZ:
1289 case REG_BINARY:
1290 case REG_MULTI_SZ:
1291 default:
1292 export_hex_data(fp, &buf, type, line_len, data, size, unicode);
1293 break;
1296 if (size || type == REG_SZ)
1298 REGPROC_write_line(fp, buf, unicode);
1299 free(buf);
1302 export_newline(fp, unicode);
1305 static WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len)
1307 WCHAR *subkey_path;
1309 subkey_path = malloc((path_len + subkey_len + 2) * sizeof(WCHAR));
1310 swprintf(subkey_path, path_len + subkey_len + 2, L"%s\\%s", path, subkey_name);
1312 return subkey_path;
1315 static void export_key_name(FILE *fp, WCHAR *name, BOOL unicode)
1317 WCHAR *buf;
1319 buf = malloc((lstrlenW(name) + 7) * sizeof(WCHAR));
1320 swprintf(buf, lstrlenW(name) + 7, L"\r\n[%s]\r\n", name);
1321 REGPROC_write_line(fp, buf, unicode);
1322 free(buf);
1325 #define MAX_SUBKEY_LEN 257
1327 static void export_registry_data(FILE *fp, HKEY key, WCHAR *path, BOOL unicode)
1329 LONG rc;
1330 DWORD max_value_len = 256, value_len;
1331 DWORD max_data_bytes = 2048, data_size;
1332 DWORD subkey_len;
1333 DWORD i, type, path_len;
1334 WCHAR *value_name, *subkey_name, *subkey_path;
1335 BYTE *data;
1336 HKEY subkey;
1338 export_key_name(fp, path, unicode);
1340 value_name = malloc(max_value_len * sizeof(WCHAR));
1341 data = malloc(max_data_bytes);
1343 i = 0;
1344 for (;;)
1346 value_len = max_value_len;
1347 data_size = max_data_bytes;
1348 rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size);
1349 if (rc == ERROR_SUCCESS)
1351 export_data(fp, value_name, value_len, type, data, data_size, unicode);
1352 i++;
1354 else if (rc == ERROR_MORE_DATA)
1356 if (data_size > max_data_bytes)
1358 max_data_bytes = data_size;
1359 data = realloc(data, max_data_bytes);
1361 else
1363 max_value_len *= 2;
1364 value_name = realloc(value_name, max_value_len * sizeof(WCHAR));
1367 else break;
1370 free(data);
1371 free(value_name);
1373 subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
1375 path_len = lstrlenW(path);
1377 i = 0;
1378 for (;;)
1380 subkey_len = MAX_SUBKEY_LEN;
1381 rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
1382 if (rc == ERROR_SUCCESS)
1384 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
1385 if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey))
1387 export_registry_data(fp, subkey, subkey_path, unicode);
1388 RegCloseKey(subkey);
1390 free(subkey_path);
1391 i++;
1393 else break;
1396 free(subkey_name);
1399 static FILE *REGPROC_open_export_file(WCHAR *file_name, BOOL unicode)
1401 FILE *file;
1403 if (!lstrcmpW(file_name, L"-"))
1405 file = stdout;
1406 _setmode(_fileno(file), _O_BINARY);
1408 else
1410 file = _wfopen(file_name, L"wb");
1411 if (!file)
1413 _wperror(L"regedit");
1414 error_exit(STRING_CANNOT_OPEN_FILE, file_name);
1418 if (unicode)
1420 static const BYTE bom[] = {0xff,0xfe};
1421 static const WCHAR header[] = L"Windows Registry Editor Version 5.00\r\n";
1423 fwrite(bom, sizeof(BYTE), ARRAY_SIZE(bom), file);
1424 fwrite(header, sizeof(WCHAR), lstrlenW(header), file);
1426 else
1427 fputs("REGEDIT4\r\n", file);
1429 return file;
1432 static HKEY open_export_key(HKEY key_class, WCHAR *subkey, WCHAR *path)
1434 HKEY key;
1436 if (!RegOpenKeyExW(key_class, subkey, 0, KEY_READ, &key))
1437 return key;
1439 output_message(STRING_OPEN_KEY_FAILED, path);
1440 return NULL;
1443 static BOOL export_key(WCHAR *file_name, WCHAR *path, BOOL unicode)
1445 HKEY key_class, key;
1446 WCHAR *subkey;
1447 FILE *fp;
1449 if (!(key_class = parse_key_name(path, &subkey)))
1451 if (subkey) *(subkey - 1) = 0;
1452 output_message(STRING_INVALID_SYSTEM_KEY, path);
1453 return FALSE;
1456 if (!(key = open_export_key(key_class, subkey, path)))
1457 return FALSE;
1459 fp = REGPROC_open_export_file(file_name, unicode);
1460 export_registry_data(fp, key, path, unicode);
1461 export_newline(fp, unicode);
1462 fclose(fp);
1464 RegCloseKey(key);
1465 return TRUE;
1468 static BOOL export_all(WCHAR *file_name, WCHAR *path, BOOL unicode)
1470 FILE *fp;
1471 int i;
1472 HKEY classes[] = {HKEY_LOCAL_MACHINE, HKEY_USERS}, key;
1473 WCHAR *class_name;
1475 fp = REGPROC_open_export_file(file_name, unicode);
1477 for (i = 0; i < ARRAY_SIZE(classes); i++)
1479 if (!(key = open_export_key(classes[i], NULL, path)))
1481 fclose(fp);
1482 return FALSE;
1485 class_name = wcsdup(reg_class_namesW[i]);
1487 export_registry_data(fp, classes[i], class_name, unicode);
1489 free(class_name);
1490 RegCloseKey(key);
1493 export_newline(fp, unicode);
1494 fclose(fp);
1496 return TRUE;
1499 BOOL export_registry_key(WCHAR *file_name, WCHAR *path, DWORD format)
1501 BOOL unicode = (format == REG_FORMAT_5);
1503 if (path && *path)
1504 return export_key(file_name, path, unicode);
1505 else
1506 return export_all(file_name, path, unicode);