reg: Move 'import' syntax checks to reg_import().
[wine.git] / programs / reg / import.c
blob13e54e6a69a5970f888787729dc4bc1270577d79
1 /*
2 * Copyright 2017 Hugh McMaster
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include "reg.h"
23 #include <wine/debug.h>
25 WINE_DEFAULT_DEBUG_CHANNEL(reg);
27 static WCHAR *GetWideString(const char *strA)
29 if (strA)
31 WCHAR *strW;
32 int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0);
34 strW = heap_xalloc(len * sizeof(WCHAR));
35 MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len);
36 return strW;
38 return NULL;
41 static WCHAR *GetWideStringN(const char *strA, int size, DWORD *len)
43 if (strA)
45 WCHAR *strW;
46 *len = MultiByteToWideChar(CP_ACP, 0, strA, size, NULL, 0);
48 strW = heap_xalloc(*len * sizeof(WCHAR));
49 MultiByteToWideChar(CP_ACP, 0, strA, size, strW, *len);
50 return strW;
52 *len = 0;
53 return NULL;
56 static WCHAR *(*get_line)(FILE *);
58 /* parser definitions */
59 enum parser_state
61 HEADER, /* parsing the registry file version header */
62 PARSE_WIN31_LINE, /* parsing a Windows 3.1 registry line */
63 LINE_START, /* at the beginning of a registry line */
64 KEY_NAME, /* parsing a key name */
65 DELETE_KEY, /* deleting a registry key */
66 DEFAULT_VALUE_NAME, /* parsing a default value name */
67 QUOTED_VALUE_NAME, /* parsing a double-quoted value name */
68 DATA_START, /* preparing for data parsing operations */
69 DELETE_VALUE, /* deleting a registry value */
70 DATA_TYPE, /* parsing the registry data type */
71 STRING_DATA, /* parsing REG_SZ data */
72 DWORD_DATA, /* parsing DWORD data */
73 HEX_DATA, /* parsing REG_BINARY, REG_NONE, REG_EXPAND_SZ or REG_MULTI_SZ data */
74 EOL_BACKSLASH, /* preparing to parse multiple lines of hex data */
75 HEX_MULTILINE, /* parsing multiple lines of hex data */
76 UNKNOWN_DATA, /* parsing an unhandled or invalid data type */
77 SET_VALUE, /* adding a value to the registry */
78 NB_PARSER_STATES
81 struct parser
83 FILE *file; /* pointer to a registry file */
84 WCHAR two_wchars[2]; /* first two characters from the encoding check */
85 BOOL is_unicode; /* parsing Unicode or ASCII data */
86 short int reg_version; /* registry file version */
87 HKEY hkey; /* current registry key */
88 WCHAR *key_name; /* current key name */
89 WCHAR *value_name; /* value name */
90 DWORD parse_type; /* generic data type for parsing */
91 DWORD data_type; /* data type */
92 void *data; /* value data */
93 DWORD data_size; /* size of the data (in bytes) */
94 BOOL backslash; /* TRUE if the current line contains a backslash */
95 enum parser_state state; /* current parser state */
98 typedef WCHAR *(*parser_state_func)(struct parser *parser, WCHAR *pos);
100 /* parser state machine functions */
101 static WCHAR *header_state(struct parser *parser, WCHAR *pos);
102 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos);
103 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos);
104 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos);
105 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos);
106 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos);
107 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos);
108 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos);
109 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos);
110 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos);
111 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos);
112 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos);
113 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos);
114 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos);
115 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos);
116 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos);
117 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos);
119 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
121 header_state, /* HEADER */
122 parse_win31_line_state, /* PARSE_WIN31_LINE */
123 line_start_state, /* LINE_START */
124 key_name_state, /* KEY_NAME */
125 delete_key_state, /* DELETE_KEY */
126 default_value_name_state, /* DEFAULT_VALUE_NAME */
127 quoted_value_name_state, /* QUOTED_VALUE_NAME */
128 data_start_state, /* DATA_START */
129 delete_value_state, /* DELETE_VALUE */
130 data_type_state, /* DATA_TYPE */
131 string_data_state, /* STRING_DATA */
132 dword_data_state, /* DWORD_DATA */
133 hex_data_state, /* HEX_DATA */
134 eol_backslash_state, /* EOL_BACKSLASH */
135 hex_multiline_state, /* HEX_MULTILINE */
136 unknown_data_state, /* UNKNOWN_DATA */
137 set_value_state, /* SET_VALUE */
140 /* set the new parser state and return the previous one */
141 static inline enum parser_state set_state(struct parser *parser, enum parser_state state)
143 enum parser_state ret = parser->state;
144 parser->state = state;
145 return ret;
148 /******************************************************************************
149 * Converts a hex representation of a DWORD into a DWORD.
151 static BOOL convert_hex_to_dword(WCHAR *str, DWORD *dw)
153 WCHAR *p, *end;
154 int count = 0;
156 while (*str == ' ' || *str == '\t') str++;
157 if (!*str) goto error;
159 p = str;
160 while (iswxdigit(*p))
162 count++;
163 p++;
165 if (count > 8) goto error;
167 end = p;
168 while (*p == ' ' || *p == '\t') p++;
169 if (*p && *p != ';') goto error;
171 *end = 0;
172 *dw = wcstoul(str, &end, 16);
173 return TRUE;
175 error:
176 return FALSE;
179 /******************************************************************************
180 * Converts comma-separated hex data into a binary string and modifies
181 * the input parameter to skip the concatenating backslash, if found.
183 * Returns TRUE or FALSE to indicate whether parsing was successful.
185 static BOOL convert_hex_csv_to_hex(struct parser *parser, WCHAR **str)
187 size_t size;
188 BYTE *d;
189 WCHAR *s;
191 parser->backslash = FALSE;
193 /* The worst case is 1 digit + 1 comma per byte */
194 size = ((lstrlenW(*str) + 1) / 2) + parser->data_size;
195 parser->data = heap_xrealloc(parser->data, size);
197 s = *str;
198 d = (BYTE *)parser->data + parser->data_size;
200 while (*s)
202 WCHAR *end;
203 unsigned long wc;
205 wc = wcstoul(s, &end, 16);
206 if (wc > 0xff) return FALSE;
208 if (s == end && wc == 0)
210 while (*end == ' ' || *end == '\t') end++;
211 if (*end == '\\')
213 parser->backslash = TRUE;
214 *str = end + 1;
215 return TRUE;
217 else if (*end == ';')
218 return TRUE;
219 return FALSE;
222 *d++ = wc;
223 parser->data_size++;
225 if (*end && *end != ',')
227 while (*end == ' ' || *end == '\t') end++;
228 if (*end && *end != ';') return FALSE;
229 return TRUE;
232 if (*end) end++;
233 s = end;
236 return TRUE;
239 /******************************************************************************
240 * Parses the data type of the registry value being imported and modifies
241 * the input parameter to skip the string representation of the data type.
243 * Returns TRUE or FALSE to indicate whether a data type was found.
245 static BOOL parse_data_type(struct parser *parser, WCHAR **line)
247 struct data_type { const WCHAR *tag; int len; int type; int parse_type; };
249 static const WCHAR quote[] = {'"'};
250 static const WCHAR hex[] = {'h','e','x',':'};
251 static const WCHAR dword[] = {'d','w','o','r','d',':'};
252 static const WCHAR hexp[] = {'h','e','x','('};
254 static const struct data_type data_types[] = {
255 /* tag len type parse type */
256 { quote, 1, REG_SZ, REG_SZ },
257 { hex, 4, REG_BINARY, REG_BINARY },
258 { dword, 6, REG_DWORD, REG_DWORD },
259 { hexp, 4, -1, REG_BINARY }, /* REG_NONE, REG_EXPAND_SZ, REG_MULTI_SZ */
260 { NULL, 0, 0, 0 }
263 const struct data_type *ptr;
265 for (ptr = data_types; ptr->tag; ptr++)
267 if (wcsncmp(ptr->tag, *line, ptr->len))
268 continue;
270 parser->parse_type = ptr->parse_type;
271 parser->data_type = ptr->parse_type;
272 *line += ptr->len;
274 if (ptr->type == -1)
276 WCHAR *end;
277 DWORD val;
279 if (!**line || towlower((*line)[1]) == 'x')
280 return FALSE;
282 /* "hex(xx):" is special */
283 val = wcstoul(*line, &end, 16);
284 if (*end != ')' || *(end + 1) != ':' || (val == ~0u && errno == ERANGE))
285 return FALSE;
287 parser->data_type = val;
288 *line = end + 2;
290 return TRUE;
292 return FALSE;
295 /******************************************************************************
296 * Replaces escape sequences with their character equivalents and
297 * null-terminates the string on the first non-escaped double quote.
299 * Assigns a pointer to the remaining unparsed data in the line.
300 * Returns TRUE or FALSE to indicate whether a closing double quote was found.
302 static BOOL unescape_string(WCHAR *str, WCHAR **unparsed)
304 int str_idx = 0; /* current character under analysis */
305 int val_idx = 0; /* the last character of the unescaped string */
306 int len = lstrlenW(str);
307 BOOL ret;
309 for (str_idx = 0; str_idx < len; str_idx++, val_idx++)
311 if (str[str_idx] == '\\')
313 str_idx++;
314 switch (str[str_idx])
316 case 'n':
317 str[val_idx] = '\n';
318 break;
319 case 'r':
320 str[val_idx] = '\r';
321 break;
322 case '0':
323 return FALSE;
324 case '\\':
325 case '"':
326 str[val_idx] = str[str_idx];
327 break;
328 default:
329 if (!str[str_idx]) return FALSE;
330 output_message(STRING_ESCAPE_SEQUENCE, str[str_idx]);
331 str[val_idx] = str[str_idx];
332 break;
335 else if (str[str_idx] == '"')
336 break;
337 else
338 str[val_idx] = str[str_idx];
341 ret = (str[str_idx] == '"');
342 *unparsed = str + str_idx + 1;
343 str[val_idx] = '\0';
344 return ret;
347 static HKEY parse_key_name(WCHAR *key_name, WCHAR **key_path)
349 if (!key_name) return 0;
351 *key_path = wcschr(key_name, '\\');
352 if (*key_path) (*key_path)++;
354 return path_get_rootkey(key_name);
357 static void close_key(struct parser *parser)
359 if (parser->hkey)
361 heap_free(parser->key_name);
362 parser->key_name = NULL;
364 RegCloseKey(parser->hkey);
365 parser->hkey = NULL;
369 static LONG open_key(struct parser *parser, WCHAR *path)
371 HKEY key_class;
372 WCHAR *key_path;
373 LONG res;
375 close_key(parser);
377 /* Get the registry class */
378 if (!path || !(key_class = parse_key_name(path, &key_path)))
379 return ERROR_INVALID_PARAMETER;
381 res = RegCreateKeyExW(key_class, key_path, 0, NULL, REG_OPTION_NON_VOLATILE,
382 KEY_ALL_ACCESS, NULL, &parser->hkey, NULL);
384 if (res == ERROR_SUCCESS)
386 parser->key_name = heap_xalloc((lstrlenW(path) + 1) * sizeof(WCHAR));
387 lstrcpyW(parser->key_name, path);
389 else
390 parser->hkey = NULL;
392 return res;
395 static void free_parser_data(struct parser *parser)
397 if (parser->parse_type == REG_DWORD || parser->parse_type == REG_BINARY)
398 heap_free(parser->data);
400 parser->data = NULL;
401 parser->data_size = 0;
404 static void prepare_hex_string_data(struct parser *parser)
406 if (parser->data_type == REG_EXPAND_SZ || parser->data_type == REG_MULTI_SZ ||
407 parser->data_type == REG_SZ)
409 if (parser->is_unicode)
411 WCHAR *data = parser->data;
412 DWORD len = parser->data_size / sizeof(WCHAR);
414 if (data[len - 1] != 0)
416 data[len] = 0;
417 parser->data_size += sizeof(WCHAR);
420 else
422 BYTE *data = parser->data;
424 if (data[parser->data_size - 1] != 0)
426 data[parser->data_size] = 0;
427 parser->data_size++;
430 parser->data = GetWideStringN(parser->data, parser->data_size, &parser->data_size);
431 parser->data_size *= sizeof(WCHAR);
432 heap_free(data);
437 enum reg_versions {
438 REG_VERSION_31,
439 REG_VERSION_40,
440 REG_VERSION_50,
441 REG_VERSION_FUZZY,
442 REG_VERSION_INVALID
445 static enum reg_versions parse_file_header(const WCHAR *s)
447 static const WCHAR header_31[] = {'R','E','G','E','D','I','T',0};
448 static const WCHAR header_40[] = {'R','E','G','E','D','I','T','4',0};
449 static const WCHAR header_50[] = {'W','i','n','d','o','w','s',' ',
450 'R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ',
451 'V','e','r','s','i','o','n',' ','5','.','0','0',0};
453 while (*s == ' ' || *s == '\t') s++;
455 if (!lstrcmpW(s, header_31))
456 return REG_VERSION_31;
458 if (!lstrcmpW(s, header_40))
459 return REG_VERSION_40;
461 if (!lstrcmpW(s, header_50))
462 return REG_VERSION_50;
464 /* The Windows version accepts registry file headers beginning with "REGEDIT" and ending
465 * with other characters, as long as "REGEDIT" appears at the start of the line. For example,
466 * "REGEDIT 4", "REGEDIT9" and "REGEDIT4FOO" are all treated as valid file headers.
467 * In all such cases, however, the contents of the registry file are not imported.
469 if (!wcsncmp(s, header_31, 7)) /* "REGEDIT" without NUL */
470 return REG_VERSION_FUZZY;
472 return REG_VERSION_INVALID;
475 /* handler for parser HEADER state */
476 static WCHAR *header_state(struct parser *parser, WCHAR *pos)
478 WCHAR *line, *header;
480 if (!(line = get_line(parser->file)))
481 return NULL;
483 if (!parser->is_unicode)
485 header = heap_xalloc((lstrlenW(line) + 3) * sizeof(WCHAR));
486 header[0] = parser->two_wchars[0];
487 header[1] = parser->two_wchars[1];
488 lstrcpyW(header + 2, line);
489 parser->reg_version = parse_file_header(header);
490 heap_free(header);
492 else parser->reg_version = parse_file_header(line);
494 switch (parser->reg_version)
496 case REG_VERSION_31:
497 set_state(parser, PARSE_WIN31_LINE);
498 break;
499 case REG_VERSION_40:
500 case REG_VERSION_50:
501 set_state(parser, LINE_START);
502 break;
503 default:
504 get_line(NULL); /* Reset static variables */
505 return NULL;
508 return line;
511 /* handler for parser PARSE_WIN31_LINE state */
512 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos)
514 WCHAR *line, *value;
515 static WCHAR hkcr[] = {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T'};
516 unsigned int key_end = 0;
518 if (!(line = get_line(parser->file)))
519 return NULL;
521 if (wcsncmp(line, hkcr, ARRAY_SIZE(hkcr)))
522 return line;
524 /* get key name */
525 while (line[key_end] && !iswspace(line[key_end])) key_end++;
527 value = line + key_end;
528 while (*value == ' ' || *value == '\t') value++;
530 if (*value == '=') value++;
531 if (*value == ' ') value++; /* at most one space is skipped */
533 line[key_end] = 0;
535 if (open_key(parser, line) != ERROR_SUCCESS)
537 output_message(STRING_OPEN_KEY_FAILED, line);
538 return line;
541 parser->value_name = NULL;
542 parser->data_type = REG_SZ;
543 parser->data = value;
544 parser->data_size = (lstrlenW(value) + 1) * sizeof(WCHAR);
546 set_state(parser, SET_VALUE);
547 return value;
550 /* handler for parser LINE_START state */
551 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos)
553 WCHAR *line, *p;
555 if (!(line = get_line(parser->file)))
556 return NULL;
558 for (p = line; *p; p++)
560 switch (*p)
562 case '[':
563 set_state(parser, KEY_NAME);
564 return p + 1;
565 case '@':
566 set_state(parser, DEFAULT_VALUE_NAME);
567 return p;
568 case '"':
569 set_state(parser, QUOTED_VALUE_NAME);
570 return p + 1;
571 case ' ':
572 case '\t':
573 break;
574 default:
575 return p;
579 return p;
582 /* handler for parser KEY_NAME state */
583 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos)
585 WCHAR *p = pos, *key_end;
587 if (*p == ' ' || *p == '\t' || !(key_end = wcsrchr(p, ']')))
588 goto done;
590 *key_end = 0;
592 if (*p == '-')
594 set_state(parser, DELETE_KEY);
595 return p + 1;
597 else if (open_key(parser, p) != ERROR_SUCCESS)
598 output_message(STRING_OPEN_KEY_FAILED, p);
600 done:
601 set_state(parser, LINE_START);
602 return p;
605 /* handler for parser DELETE_KEY state */
606 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos)
608 WCHAR *p = pos;
610 close_key(parser);
612 if (*p == 'H' || *p == 'h')
614 HKEY root;
615 WCHAR *path;
617 root = parse_key_name(p, &path);
619 if (root && path && *path)
620 RegDeleteTreeW(root, path);
623 set_state(parser, LINE_START);
624 return p;
627 /* handler for parser DEFAULT_VALUE_NAME state */
628 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos)
630 heap_free(parser->value_name);
631 parser->value_name = NULL;
633 set_state(parser, DATA_START);
634 return pos + 1;
637 /* handler for parser QUOTED_VALUE_NAME state */
638 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos)
640 WCHAR *val_name = pos, *p;
642 heap_free(parser->value_name);
643 parser->value_name = NULL;
645 if (!unescape_string(val_name, &p))
646 goto invalid;
648 /* copy the value name in case we need to parse multiple lines and the buffer is overwritten */
649 parser->value_name = heap_xalloc((lstrlenW(val_name) + 1) * sizeof(WCHAR));
650 lstrcpyW(parser->value_name, val_name);
652 set_state(parser, DATA_START);
653 return p;
655 invalid:
656 set_state(parser, LINE_START);
657 return val_name;
660 /* handler for parser DATA_START state */
661 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos)
663 WCHAR *p = pos;
664 unsigned int len;
666 while (*p == ' ' || *p == '\t') p++;
667 if (*p != '=') goto invalid;
668 p++;
669 while (*p == ' ' || *p == '\t') p++;
671 /* trim trailing whitespace */
672 len = lstrlenW(p);
673 while (len > 0 && (p[len - 1] == ' ' || p[len - 1] == '\t')) len--;
674 p[len] = 0;
676 if (*p == '-')
677 set_state(parser, DELETE_VALUE);
678 else
679 set_state(parser, DATA_TYPE);
680 return p;
682 invalid:
683 set_state(parser, LINE_START);
684 return p;
687 /* handler for parser DELETE_VALUE state */
688 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos)
690 WCHAR *p = pos + 1;
692 while (*p == ' ' || *p == '\t') p++;
693 if (*p && *p != ';') goto done;
695 RegDeleteValueW(parser->hkey, parser->value_name);
697 done:
698 set_state(parser, LINE_START);
699 return p;
702 /* handler for parser DATA_TYPE state */
703 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos)
705 WCHAR *line = pos;
707 if (!parse_data_type(parser, &line))
709 set_state(parser, LINE_START);
710 return line;
713 switch (parser->parse_type)
715 case REG_SZ:
716 set_state(parser, STRING_DATA);
717 break;
718 case REG_DWORD:
719 set_state(parser, DWORD_DATA);
720 break;
721 case REG_BINARY: /* all hex data types, including undefined */
722 set_state(parser, HEX_DATA);
723 break;
724 default:
725 set_state(parser, UNKNOWN_DATA);
728 return line;
731 /* handler for parser STRING_DATA state */
732 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos)
734 WCHAR *line;
736 parser->data = pos;
738 if (!unescape_string(parser->data, &line))
739 goto invalid;
741 while (*line == ' ' || *line == '\t') line++;
742 if (*line && *line != ';') goto invalid;
744 parser->data_size = (lstrlenW(parser->data) + 1) * sizeof(WCHAR);
746 set_state(parser, SET_VALUE);
747 return line;
749 invalid:
750 free_parser_data(parser);
751 set_state(parser, LINE_START);
752 return line;
755 /* handler for parser DWORD_DATA state */
756 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos)
758 WCHAR *line = pos;
760 parser->data = heap_xalloc(sizeof(DWORD));
762 if (!convert_hex_to_dword(line, parser->data))
763 goto invalid;
765 parser->data_size = sizeof(DWORD);
767 set_state(parser, SET_VALUE);
768 return line;
770 invalid:
771 free_parser_data(parser);
772 set_state(parser, LINE_START);
773 return line;
776 /* handler for parser HEX_DATA state */
777 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos)
779 WCHAR *line = pos;
781 if (!*line)
782 goto set_value;
784 if (!convert_hex_csv_to_hex(parser, &line))
785 goto invalid;
787 if (parser->backslash)
789 set_state(parser, EOL_BACKSLASH);
790 return line;
793 prepare_hex_string_data(parser);
795 set_value:
796 set_state(parser, SET_VALUE);
797 return line;
799 invalid:
800 free_parser_data(parser);
801 set_state(parser, LINE_START);
802 return line;
805 /* handler for parser EOL_BACKSLASH state */
806 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos)
808 WCHAR *p = pos;
810 while (*p == ' ' || *p == '\t') p++;
811 if (*p && *p != ';') goto invalid;
813 set_state(parser, HEX_MULTILINE);
814 return pos;
816 invalid:
817 free_parser_data(parser);
818 set_state(parser, LINE_START);
819 return p;
822 /* handler for parser HEX_MULTILINE state */
823 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos)
825 WCHAR *line;
827 if (!(line = get_line(parser->file)))
829 prepare_hex_string_data(parser);
830 set_state(parser, SET_VALUE);
831 return pos;
834 while (*line == ' ' || *line == '\t') line++;
835 if (!*line || *line == ';') return line;
837 if (!iswxdigit(*line)) goto invalid;
839 set_state(parser, HEX_DATA);
840 return line;
842 invalid:
843 free_parser_data(parser);
844 set_state(parser, LINE_START);
845 return line;
848 /* handler for parser UNKNOWN_DATA state */
849 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos)
851 FIXME("Unknown registry data type [0x%x]\n", parser->data_type);
853 set_state(parser, LINE_START);
854 return pos;
857 /* handler for parser SET_VALUE state */
858 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos)
860 RegSetValueExW(parser->hkey, parser->value_name, 0, parser->data_type,
861 parser->data, parser->data_size);
863 free_parser_data(parser);
865 if (parser->reg_version == REG_VERSION_31)
866 set_state(parser, PARSE_WIN31_LINE);
867 else
868 set_state(parser, LINE_START);
870 return pos;
873 #define REG_VAL_BUF_SIZE 4096
875 static WCHAR *get_lineA(FILE *fp)
877 static WCHAR *lineW;
878 static size_t size;
879 static char *buf, *next;
880 char *line;
882 heap_free(lineW);
884 if (!fp) goto cleanup;
886 if (!size)
888 size = REG_VAL_BUF_SIZE;
889 buf = heap_xalloc(size);
890 *buf = 0;
891 next = buf;
893 line = next;
895 while (next)
897 char *p = strpbrk(line, "\r\n");
898 if (!p)
900 size_t len, count;
901 len = strlen(next);
902 memmove(buf, next, len + 1);
903 if (size - len < 3)
905 size *= 2;
906 buf = heap_xrealloc(buf, size);
908 if (!(count = fread(buf + len, 1, size - len - 1, fp)))
910 next = NULL;
911 lineW = GetWideString(buf);
912 return lineW;
914 buf[len + count] = 0;
915 next = buf;
916 line = buf;
917 continue;
919 next = p + 1;
920 if (*p == '\r' && *(p + 1) == '\n') next++;
921 *p = 0;
922 lineW = GetWideString(line);
923 return lineW;
926 cleanup:
927 lineW = NULL;
928 if (size) heap_free(buf);
929 size = 0;
930 return NULL;
933 static WCHAR *get_lineW(FILE *fp)
935 static size_t size;
936 static WCHAR *buf, *next;
937 WCHAR *line;
939 if (!fp) goto cleanup;
941 if (!size)
943 size = REG_VAL_BUF_SIZE;
944 buf = heap_xalloc(size * sizeof(WCHAR));
945 *buf = 0;
946 next = buf;
948 line = next;
950 while (next)
952 static const WCHAR line_endings[] = {'\r','\n',0};
953 WCHAR *p = wcspbrk(line, line_endings);
954 if (!p)
956 size_t len, count;
957 len = lstrlenW(next);
958 memmove(buf, next, (len + 1) * sizeof(WCHAR));
959 if (size - len < 3)
961 size *= 2;
962 buf = heap_xrealloc(buf, size * sizeof(WCHAR));
964 if (!(count = fread(buf + len, sizeof(WCHAR), size - len - 1, fp)))
966 next = NULL;
967 return buf;
969 buf[len + count] = 0;
970 next = buf;
971 line = buf;
972 continue;
974 next = p + 1;
975 if (*p == '\r' && *(p + 1) == '\n') next++;
976 *p = 0;
977 return line;
980 cleanup:
981 if (size) heap_free(buf);
982 size = 0;
983 return NULL;
986 int reg_import(int argc, WCHAR *argvW[])
988 WCHAR *filename, *pos;
989 FILE *fp;
990 static const WCHAR rb_mode[] = {'r','b',0};
991 BYTE s[2];
992 struct parser parser;
994 if (argc > 3)
996 output_message(STRING_INVALID_SYNTAX);
997 output_message(STRING_FUNC_HELP, wcsupr(argvW[1]));
998 return 1;
1001 filename = argvW[2];
1003 fp = _wfopen(filename, rb_mode);
1004 if (!fp)
1006 output_message(STRING_FILE_NOT_FOUND, filename);
1007 return 1;
1010 if (fread(s, sizeof(WCHAR), 1, fp) != 1)
1011 goto error;
1013 parser.is_unicode = (s[0] == 0xff && s[1] == 0xfe);
1014 get_line = parser.is_unicode ? get_lineW : get_lineA;
1016 parser.file = fp;
1017 parser.two_wchars[0] = s[0];
1018 parser.two_wchars[1] = s[1];
1019 parser.reg_version = -1;
1020 parser.hkey = NULL;
1021 parser.key_name = NULL;
1022 parser.value_name = NULL;
1023 parser.parse_type = 0;
1024 parser.data_type = 0;
1025 parser.data = NULL;
1026 parser.data_size = 0;
1027 parser.backslash = FALSE;
1028 parser.state = HEADER;
1030 pos = parser.two_wchars;
1032 /* parser main loop */
1033 while (pos)
1034 pos = (parser_funcs[parser.state])(&parser, pos);
1036 if (parser.reg_version == REG_VERSION_INVALID)
1037 goto error;
1039 heap_free(parser.value_name);
1040 close_key(&parser);
1042 fclose(fp);
1043 return 0;
1045 error:
1046 fclose(fp);
1047 return 1;