regedit: Perform key operations in the state machine.
[wine.git] / programs / regedit / regproc.c
blobe1352a72093f725ccffc9876331022ac0ae13f59
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 <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <fcntl.h>
28 #include <io.h>
29 #include <windows.h>
30 #include <winnt.h>
31 #include <winreg.h>
32 #include <assert.h>
33 #include <wine/unicode.h>
34 #include <wine/debug.h>
35 #include "regproc.h"
37 #define REG_VAL_BUF_SIZE 4096
39 /* maximal number of characters in hexadecimal data line,
40 * including the indentation, but not including the '\' character
42 #define REG_FILE_HEX_LINE_LEN (2 + 25 * 3)
44 extern const WCHAR* reg_class_namesW[];
46 static HKEY reg_class_keys[] = {
47 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
48 HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA
51 #define ARRAY_SIZE(A) (sizeof(A)/sizeof(*A))
53 /******************************************************************************
54 * Allocates memory and converts input from multibyte to wide chars
55 * Returned string must be freed by the caller
57 static WCHAR* GetWideString(const char* strA)
59 if(strA)
61 WCHAR* strW;
62 int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0);
64 strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
65 CHECK_ENOUGH_MEMORY(strW);
66 MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len);
67 return strW;
69 return NULL;
72 /******************************************************************************
73 * Allocates memory and converts input from multibyte to wide chars
74 * Returned string must be freed by the caller
76 static WCHAR* GetWideStringN(const char* strA, int chars, DWORD *len)
78 if(strA)
80 WCHAR* strW;
81 *len = MultiByteToWideChar(CP_ACP, 0, strA, chars, NULL, 0);
83 strW = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(WCHAR));
84 CHECK_ENOUGH_MEMORY(strW);
85 MultiByteToWideChar(CP_ACP, 0, strA, chars, strW, *len);
86 return strW;
88 *len = 0;
89 return NULL;
92 /******************************************************************************
93 * Allocates memory and converts input from wide chars to multibyte
94 * Returned string must be freed by the caller
96 char* GetMultiByteString(const WCHAR* strW)
98 if(strW)
100 char* strA;
101 int len = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL);
103 strA = HeapAlloc(GetProcessHeap(), 0, len);
104 CHECK_ENOUGH_MEMORY(strA);
105 WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, len, NULL, NULL);
106 return strA;
108 return NULL;
111 /******************************************************************************
112 * Allocates memory and converts input from wide chars to multibyte
113 * Returned string must be freed by the caller
115 static char* GetMultiByteStringN(const WCHAR* strW, int chars, DWORD* len)
117 if(strW)
119 char* strA;
120 *len = WideCharToMultiByte(CP_ACP, 0, strW, chars, NULL, 0, NULL, NULL);
122 strA = HeapAlloc(GetProcessHeap(), 0, *len);
123 CHECK_ENOUGH_MEMORY(strA);
124 WideCharToMultiByte(CP_ACP, 0, strW, chars, strA, *len, NULL, NULL);
125 return strA;
127 *len = 0;
128 return NULL;
131 static WCHAR *(*get_line)(FILE *);
133 /* parser definitions */
134 enum parser_state
136 HEADER, /* parsing the registry file version header */
137 PARSE_WIN31_LINE, /* parsing a Windows 3.1 registry line */
138 LINE_START, /* at the beginning of a registry line */
139 KEY_NAME, /* parsing a key name */
140 DELETE_KEY, /* deleting a registry key */
141 SET_VALUE, /* adding a value to the registry */
142 NB_PARSER_STATES
145 struct parser
147 FILE *file; /* pointer to a registry file */
148 WCHAR two_wchars[2]; /* first two characters from the encoding check */
149 BOOL is_unicode; /* parsing Unicode or ASCII data */
150 short int reg_version; /* registry file version */
151 WCHAR *value_name; /* value name */
152 DWORD data_type; /* data type */
153 void *data; /* value data */
154 DWORD data_size; /* size of the data (in bytes) */
155 enum parser_state state; /* current parser state */
158 typedef WCHAR *(*parser_state_func)(struct parser *parser, WCHAR *pos);
160 /* parser state machine functions */
161 static WCHAR *header_state(struct parser *parser, WCHAR *pos);
162 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos);
163 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos);
164 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos);
165 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos);
166 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos);
168 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
170 header_state, /* HEADER */
171 parse_win31_line_state, /* PARSE_WIN31_LINE */
172 line_start_state, /* LINE_START */
173 key_name_state, /* KEY_NAME */
174 delete_key_state, /* DELETE_KEY */
175 set_value_state, /* SET_VALUE */
178 /* set the new parser state and return the previous one */
179 static inline enum parser_state set_state(struct parser *parser, enum parser_state state)
181 enum parser_state ret = parser->state;
182 parser->state = state;
183 return ret;
186 /******************************************************************************
187 * Converts a hex representation of a DWORD into a DWORD.
189 static BOOL convertHexToDWord(WCHAR* str, DWORD *dw)
191 WCHAR *p, *end;
192 int count = 0;
194 while (*str == ' ' || *str == '\t') str++;
195 if (!*str) goto error;
197 p = str;
198 while (isxdigitW(*p))
200 count++;
201 p++;
203 if (count > 8) goto error;
205 end = p;
206 while (*p == ' ' || *p == '\t') p++;
207 if (*p && *p != ';') goto error;
209 *end = 0;
210 *dw = strtoulW(str, &end, 16);
211 return TRUE;
213 error:
214 output_message(STRING_INVALID_HEX);
215 return FALSE;
218 /******************************************************************************
219 * Converts a hex comma separated values list into a binary string.
221 static BYTE* convertHexCSVToHex(WCHAR *str, DWORD *size)
223 WCHAR *s;
224 BYTE *d, *data;
226 /* The worst case is 1 digit + 1 comma per byte */
227 *size=(lstrlenW(str)+1)/2;
228 data=HeapAlloc(GetProcessHeap(), 0, *size);
229 CHECK_ENOUGH_MEMORY(data);
231 s = str;
232 d = data;
233 *size=0;
234 while (*s != '\0') {
235 UINT wc;
236 WCHAR *end;
238 wc = strtoulW(s,&end,16);
239 if (end == s || wc > 0xff || (*end && *end != ',')) {
240 output_message(STRING_CSV_HEX_ERROR, s);
241 HeapFree(GetProcessHeap(), 0, data);
242 return NULL;
244 *d++ =(BYTE)wc;
245 (*size)++;
246 if (*end) end++;
247 s = end;
250 return data;
253 #define REG_UNKNOWN_TYPE 99
255 /******************************************************************************
256 * This function returns the HKEY associated with the data type encoded in the
257 * value. It modifies the input parameter (key value) in order to skip this
258 * "now useless" data type information.
260 * Note: Updated based on the algorithm used in 'server/registry.c'
262 static DWORD getDataType(LPWSTR *lpValue, DWORD* parse_type)
264 struct data_type { const WCHAR *tag; int len; int type; int parse_type; };
266 static const WCHAR quote[] = {'"'};
267 static const WCHAR hex[] = {'h','e','x',':'};
268 static const WCHAR dword[] = {'d','w','o','r','d',':'};
269 static const WCHAR hexp[] = {'h','e','x','('};
271 static const struct data_type data_types[] = {
272 /* tag len type parse type */
273 { quote, 1, REG_SZ, REG_SZ },
274 { hex, 4, REG_BINARY, REG_BINARY },
275 { dword, 6, REG_DWORD, REG_DWORD },
276 { hexp, 4, -1, REG_BINARY }, /* REG_NONE, REG_EXPAND_SZ, REG_MULTI_SZ */
277 { NULL, 0, 0, 0 }
280 const struct data_type *ptr;
281 int type;
283 for (ptr = data_types; ptr->tag; ptr++) {
284 if (strncmpW( ptr->tag, *lpValue, ptr->len ))
285 continue;
287 /* Found! */
288 *parse_type = ptr->parse_type;
289 type=ptr->type;
290 *lpValue+=ptr->len;
291 if (type == -1) {
292 WCHAR* end;
294 /* "hex(xx):" is special */
295 type = (int)strtoulW( *lpValue , &end, 16 );
296 if (**lpValue=='\0' || *end!=')' || *(end+1)!=':') {
297 type = REG_UNKNOWN_TYPE;
298 } else {
299 *lpValue = end + 2;
302 return type;
304 *parse_type = REG_UNKNOWN_TYPE;
305 return REG_UNKNOWN_TYPE;
308 /******************************************************************************
309 * Replaces escape sequences with their character equivalents and
310 * null-terminates the string on the first non-escaped double quote.
312 * Assigns a pointer to the remaining unparsed data in the line.
313 * Returns TRUE or FALSE to indicate whether a closing double quote was found.
315 static BOOL REGPROC_unescape_string(WCHAR *str, WCHAR **unparsed)
317 int str_idx = 0; /* current character under analysis */
318 int val_idx = 0; /* the last character of the unescaped string */
319 int len = lstrlenW(str);
320 BOOL ret;
322 for (str_idx = 0; str_idx < len; str_idx++, val_idx++) {
323 if (str[str_idx] == '\\') {
324 str_idx++;
325 switch (str[str_idx]) {
326 case 'n':
327 str[val_idx] = '\n';
328 break;
329 case 'r':
330 str[val_idx] = '\r';
331 break;
332 case '0':
333 str[val_idx] = '\0';
334 break;
335 case '\\':
336 case '"':
337 str[val_idx] = str[str_idx];
338 break;
339 default:
340 output_message(STRING_ESCAPE_SEQUENCE, str[str_idx]);
341 str[val_idx] = str[str_idx];
342 break;
344 } else if (str[str_idx] == '"') {
345 break;
346 } else {
347 str[val_idx] = str[str_idx];
351 ret = (str[str_idx] == '"');
352 *unparsed = str + str_idx + 1;
353 str[val_idx] = '\0';
354 return ret;
357 static HKEY parse_key_name(WCHAR *key_name, WCHAR **key_path)
359 unsigned int i;
361 if (!key_name) return 0;
363 *key_path = strchrW(key_name, '\\');
364 if (*key_path) (*key_path)++;
366 for (i = 0; i < ARRAY_SIZE(reg_class_keys); i++)
368 int len = lstrlenW(reg_class_namesW[i]);
369 if (!strncmpW(key_name, reg_class_namesW[i], len) &&
370 (key_name[len] == 0 || key_name[len] == '\\'))
372 return reg_class_keys[i];
376 return 0;
379 /* Globals used by the setValue() & co */
380 static WCHAR *currentKeyName;
381 static HKEY currentKeyHandle = NULL;
383 /* Registry data types */
384 static const WCHAR type_none[] = {'R','E','G','_','N','O','N','E',0};
385 static const WCHAR type_sz[] = {'R','E','G','_','S','Z',0};
386 static const WCHAR type_expand_sz[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0};
387 static const WCHAR type_binary[] = {'R','E','G','_','B','I','N','A','R','Y',0};
388 static const WCHAR type_dword[] = {'R','E','G','_','D','W','O','R','D',0};
389 static const WCHAR type_dword_le[] = {'R','E','G','_','D','W','O','R','D','_','L','I','T','T','L','E','_','E','N','D','I','A','N',0};
390 static const WCHAR type_dword_be[] = {'R','E','G','_','D','W','O','R','D','_','B','I','G','_','E','N','D','I','A','N',0};
391 static const WCHAR type_multi_sz[] = {'R','E','G','_','M','U','L','T','I','_','S','Z',0};
393 static const struct
395 DWORD type;
396 const WCHAR *name;
398 type_rels[] =
400 {REG_NONE, type_none},
401 {REG_SZ, type_sz},
402 {REG_EXPAND_SZ, type_expand_sz},
403 {REG_BINARY, type_binary},
404 {REG_DWORD, type_dword},
405 {REG_DWORD_LITTLE_ENDIAN, type_dword_le},
406 {REG_DWORD_BIG_ENDIAN, type_dword_be},
407 {REG_MULTI_SZ, type_multi_sz},
410 static const WCHAR *reg_type_to_wchar(DWORD type)
412 int i, array_size = ARRAY_SIZE(type_rels);
414 for (i = 0; i < array_size; i++)
416 if (type == type_rels[i].type)
417 return type_rels[i].name;
419 return NULL;
422 /******************************************************************************
423 * Sets the value with name val_name to the data in val_data for the currently
424 * opened key.
426 * Parameters:
427 * val_name - name of the registry value
428 * val_data - registry value data
430 static LONG setValue(WCHAR* val_name, WCHAR* val_data, BOOL is_unicode)
432 LONG res;
433 DWORD dwDataType, dwParseType;
434 LPBYTE lpbData;
435 DWORD dwData, dwLen;
436 WCHAR del[] = {'-',0};
438 if ( (val_name == NULL) || (val_data == NULL) )
439 return ERROR_INVALID_PARAMETER;
441 if (lstrcmpW(val_data, del) == 0)
443 res=RegDeleteValueW(currentKeyHandle,val_name);
444 return (res == ERROR_FILE_NOT_FOUND ? ERROR_SUCCESS : res);
447 /* Get the data type stored into the value field */
448 dwDataType = getDataType(&val_data, &dwParseType);
450 if (dwParseType == REG_SZ) /* no conversion for string */
452 WCHAR *line;
453 if (!REGPROC_unescape_string(val_data, &line))
454 return ERROR_INVALID_DATA;
455 while (*line == ' ' || *line == '\t') line++;
456 if (*line && *line != ';')
457 return ERROR_INVALID_DATA;
458 lpbData = (BYTE*) val_data;
459 dwLen = (lstrlenW(val_data) + 1) * sizeof(WCHAR); /* size is in bytes */
461 else if (dwParseType == REG_DWORD) /* Convert the dword types */
463 if (!convertHexToDWord(val_data, &dwData))
464 return ERROR_INVALID_DATA;
465 lpbData = (BYTE*)&dwData;
466 dwLen = sizeof(dwData);
468 else if (dwParseType == REG_BINARY) /* Convert the binary data */
470 lpbData = convertHexCSVToHex(val_data, &dwLen);
471 if (!lpbData)
472 return ERROR_INVALID_DATA;
474 if((dwDataType == REG_MULTI_SZ || dwDataType == REG_EXPAND_SZ) && !is_unicode)
476 LPBYTE tmp = lpbData;
477 lpbData = (LPBYTE)GetWideStringN((char*)lpbData, dwLen, &dwLen);
478 dwLen *= sizeof(WCHAR);
479 HeapFree(GetProcessHeap(), 0, tmp);
482 else /* unknown format */
484 if (dwDataType == REG_UNKNOWN_TYPE)
486 WCHAR buf[32];
487 LoadStringW(GetModuleHandleW(NULL), STRING_UNKNOWN_TYPE, buf, ARRAY_SIZE(buf));
488 output_message(STRING_UNKNOWN_DATA_FORMAT, buf);
490 else
491 output_message(STRING_UNKNOWN_DATA_FORMAT, reg_type_to_wchar(dwDataType));
493 return ERROR_INVALID_DATA;
496 res = RegSetValueExW(
497 currentKeyHandle,
498 val_name,
499 0, /* Reserved */
500 dwDataType,
501 lpbData,
502 dwLen);
503 if (dwParseType == REG_BINARY)
504 HeapFree(GetProcessHeap(), 0, lpbData);
505 return res;
508 static void closeKey(void)
510 if (currentKeyHandle)
512 HeapFree(GetProcessHeap(), 0, currentKeyName);
513 currentKeyName = NULL;
515 RegCloseKey(currentKeyHandle);
516 currentKeyHandle = NULL;
520 /******************************************************************************
521 * Opens the registry key given by the input path.
522 * This key must be closed by calling close_key().
524 static LONG openKeyW(WCHAR* stdInput)
526 HKEY key_class;
527 WCHAR *key_path;
528 LONG res;
530 closeKey();
532 /* Get the registry class */
533 if (!stdInput || !(key_class = parse_key_name(stdInput, &key_path)))
534 return ERROR_INVALID_PARAMETER;
536 res = RegCreateKeyExW(key_class, key_path, 0, NULL, REG_OPTION_NON_VOLATILE,
537 KEY_ALL_ACCESS, NULL, &currentKeyHandle, NULL);
539 if (res == ERROR_SUCCESS)
541 currentKeyName = HeapAlloc(GetProcessHeap(), 0, (strlenW(stdInput) + 1) * sizeof(WCHAR));
542 CHECK_ENOUGH_MEMORY(currentKeyName);
543 strcpyW(currentKeyName, stdInput);
545 else
546 currentKeyHandle = NULL;
548 return res;
552 /******************************************************************************
553 * This function is a wrapper for the setValue function. It prepares the
554 * land and cleans the area once completed.
555 * Note: this function modifies the line parameter.
557 * line - registry file unwrapped line. Should have the registry value name and
558 * complete registry value data.
560 static void processSetValue(WCHAR* line, BOOL is_unicode)
562 WCHAR *val_name;
563 int len = 0;
564 LONG res;
566 /* get value name */
567 val_name = line;
569 if (*line == '@')
570 *line++ = 0;
571 else if (!REGPROC_unescape_string(++val_name, &line))
572 goto error;
574 while (*line == ' ' || *line == '\t') line++;
575 if (*line != '=')
576 goto error;
577 line++;
578 while (*line == ' ' || *line == '\t') line++;
580 /* trim trailing blanks */
581 len = strlenW(line);
582 while (len > 0 && (line[len - 1] == ' ' || line[len - 1] == '\t')) len--;
583 line[len] = 0;
585 res = setValue(val_name, line, is_unicode);
586 if ( res != ERROR_SUCCESS )
587 output_message(STRING_SETVALUE_FAILED, val_name, currentKeyName);
588 return;
590 error:
591 output_message(STRING_SETVALUE_FAILED, val_name, currentKeyName);
592 output_message(STRING_INVALID_LINE_SYNTAX);
595 enum reg_versions {
596 REG_VERSION_31,
597 REG_VERSION_40,
598 REG_VERSION_50,
599 REG_VERSION_FUZZY,
600 REG_VERSION_INVALID
603 static enum reg_versions parse_file_header(const WCHAR *s)
605 static const WCHAR header_31[] = {'R','E','G','E','D','I','T',0};
606 static const WCHAR header_40[] = {'R','E','G','E','D','I','T','4',0};
607 static const WCHAR header_50[] = {'W','i','n','d','o','w','s',' ',
608 'R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ',
609 'V','e','r','s','i','o','n',' ','5','.','0','0',0};
611 while (*s && (*s == ' ' || *s == '\t')) s++;
613 if (!strcmpW(s, header_31))
614 return REG_VERSION_31;
616 if (!strcmpW(s, header_40))
617 return REG_VERSION_40;
619 if (!strcmpW(s, header_50))
620 return REG_VERSION_50;
622 /* The Windows version accepts registry file headers beginning with "REGEDIT" and ending
623 * with other characters, as long as "REGEDIT" appears at the start of the line. For example,
624 * "REGEDIT 4", "REGEDIT9" and "REGEDIT4FOO" are all treated as valid file headers.
625 * In all such cases, however, the contents of the registry file are not imported.
627 if (!strncmpW(s, header_31, 7)) /* "REGEDIT" without NUL */
628 return REG_VERSION_FUZZY;
630 return REG_VERSION_INVALID;
633 /* handler for parser HEADER state */
634 static WCHAR *header_state(struct parser *parser, WCHAR *pos)
636 WCHAR *line, *header;
638 if (!(line = get_line(parser->file)))
639 return NULL;
641 if (!parser->is_unicode)
643 header = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(line) + 3) * sizeof(WCHAR));
644 CHECK_ENOUGH_MEMORY(header);
645 header[0] = parser->two_wchars[0];
646 header[1] = parser->two_wchars[1];
647 lstrcpyW(header + 2, line);
648 parser->reg_version = parse_file_header(header);
649 HeapFree(GetProcessHeap(), 0, header);
651 else parser->reg_version = parse_file_header(line);
653 switch (parser->reg_version)
655 case REG_VERSION_31:
656 set_state(parser, PARSE_WIN31_LINE);
657 break;
658 case REG_VERSION_40:
659 case REG_VERSION_50:
660 set_state(parser, LINE_START);
661 break;
662 default:
663 get_line(NULL); /* Reset static variables */
664 return NULL;
667 return line;
670 /* handler for parser PARSE_WIN31_LINE state */
671 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos)
673 WCHAR *line, *value;
674 static WCHAR hkcr[] = {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T'};
675 unsigned int key_end = 0;
677 if (!(line = get_line(parser->file)))
678 return NULL;
680 if (strncmpW(line, hkcr, ARRAY_SIZE(hkcr)))
681 goto invalid;
683 /* get key name */
684 while (line[key_end] && !isspaceW(line[key_end])) key_end++;
686 value = line + key_end;
687 while (*value == ' ' || *value == '\t') value++;
689 if (*value == '=') value++;
690 if (*value == ' ') value++; /* at most one space is skipped */
692 line[key_end] = 0;
694 closeKey();
696 if (openKeyW(line) != ERROR_SUCCESS)
698 output_message(STRING_OPEN_KEY_FAILED, line);
699 goto invalid;
702 parser->value_name = NULL;
703 parser->data_type = REG_SZ;
704 parser->data = value;
705 parser->data_size = (lstrlenW(value) + 1) * sizeof(WCHAR);
707 set_state(parser, SET_VALUE);
708 return value;
710 invalid:
711 set_state(parser, PARSE_WIN31_LINE);
712 return line;
715 /* handler for parser LINE_START state */
716 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos)
718 WCHAR *line, *p;
720 if (!(line = get_line(parser->file)))
721 return NULL;
723 for (p = line; *p; p++)
725 switch (*p)
727 case '[':
728 set_state(parser, KEY_NAME);
729 return p + 1;
730 case '@':
731 case '"':
732 processSetValue(p, parser->is_unicode);
733 return p;
734 case ' ':
735 case '\t':
736 break;
737 default:
738 set_state(parser, LINE_START);
739 return p;
743 return p;
746 /* handler for parser KEY_NAME state */
747 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos)
749 WCHAR *p = pos, *key_end;
751 if (*p == ' ' || *p == '\t' || !(key_end = strrchrW(p, ']')))
752 goto done;
754 *key_end = 0;
756 if (*p == '-')
758 set_state(parser, DELETE_KEY);
759 return p + 1;
761 else if (openKeyW(p) != ERROR_SUCCESS)
762 output_message(STRING_OPEN_KEY_FAILED, p);
764 done:
765 set_state(parser, LINE_START);
766 return p;
769 /* handler for parser DELETE_KEY state */
770 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos)
772 WCHAR *p = pos;
774 if (*p == 'H')
775 delete_registry_key(p);
777 set_state(parser, LINE_START);
778 return p;
781 /* handler for parser SET_VALUE state */
782 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos)
784 RegSetValueExW(currentKeyHandle, parser->value_name, 0, parser->data_type,
785 parser->data, parser->data_size);
787 set_state(parser, PARSE_WIN31_LINE);
789 return pos;
792 static WCHAR *get_lineA(FILE *fp)
794 static WCHAR *lineW;
795 static size_t size;
796 static char *buf, *next;
797 char *line;
799 HeapFree(GetProcessHeap(), 0, lineW);
801 if (!fp) goto cleanup;
803 if (!size)
805 size = REG_VAL_BUF_SIZE;
806 buf = HeapAlloc(GetProcessHeap(), 0, size);
807 CHECK_ENOUGH_MEMORY(buf);
808 *buf = 0;
809 next = buf;
811 line = next;
813 while (next)
815 char *p = strpbrk(line, "\r\n");
816 if (!p)
818 size_t len, count;
819 len = strlen(next);
820 memmove(buf, next, len + 1);
821 if (size - len < 3)
823 char *new_buf = HeapReAlloc(GetProcessHeap(), 0, buf, size * 2);
824 CHECK_ENOUGH_MEMORY(new_buf);
825 buf = new_buf;
826 size *= 2;
828 if (!(count = fread(buf + len, 1, size - len - 1, fp)))
830 next = NULL;
831 lineW = GetWideString(buf);
832 return lineW;
834 buf[len + count] = 0;
835 next = buf;
836 line = buf;
837 continue;
839 next = p + 1;
840 if (*p == '\r' && *(p + 1) == '\n') next++;
841 *p = 0;
842 if (p > buf && *(p - 1) == '\\')
844 while (*next == ' ' || *next == '\t') next++;
845 memmove(p - 1, next, strlen(next) + 1);
846 next = line;
847 continue;
849 if (*line == ';' || *line == '#')
851 line = next;
852 continue;
854 lineW = GetWideString(line);
855 return lineW;
858 cleanup:
859 lineW = NULL;
860 if (size) HeapFree(GetProcessHeap(), 0, buf);
861 size = 0;
862 return NULL;
865 static WCHAR *get_lineW(FILE *fp)
867 static size_t size;
868 static WCHAR *buf, *next;
869 WCHAR *line;
871 if (!fp) goto cleanup;
873 if (!size)
875 size = REG_VAL_BUF_SIZE;
876 buf = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
877 CHECK_ENOUGH_MEMORY(buf);
878 *buf = 0;
879 next = buf;
881 line = next;
883 while (next)
885 static const WCHAR line_endings[] = {'\r','\n',0};
886 WCHAR *p = strpbrkW(line, line_endings);
887 if (!p)
889 size_t len, count;
890 len = strlenW(next);
891 memmove(buf, next, (len + 1) * sizeof(WCHAR));
892 if (size - len < 3)
894 WCHAR *new_buf = HeapReAlloc(GetProcessHeap(), 0, buf, (size * 2) * sizeof(WCHAR));
895 CHECK_ENOUGH_MEMORY(new_buf);
896 buf = new_buf;
897 size *= 2;
899 if (!(count = fread(buf + len, sizeof(WCHAR), size - len - 1, fp)))
901 next = NULL;
902 return buf;
904 buf[len + count] = 0;
905 next = buf;
906 line = buf;
907 continue;
909 next = p + 1;
910 if (*p == '\r' && *(p + 1) == '\n') next++;
911 *p = 0;
912 if (p > buf && *(p - 1) == '\\')
914 while (*next == ' ' || *next == '\t') next++;
915 memmove(p - 1, next, (strlenW(next) + 1) * sizeof(WCHAR));
916 next = line;
917 continue;
919 if (*line == ';' || *line == '#')
921 line = next;
922 continue;
924 return line;
927 cleanup:
928 if (size) HeapFree(GetProcessHeap(), 0, buf);
929 size = 0;
930 return NULL;
933 /******************************************************************************
934 * Checks whether the buffer has enough room for the string or required size.
935 * Resizes the buffer if necessary.
937 * Parameters:
938 * buffer - pointer to a buffer for string
939 * len - current length of the buffer in characters.
940 * required_len - length of the string to place to the buffer in characters.
941 * The length does not include the terminating null character.
943 static void REGPROC_resize_char_buffer(WCHAR **buffer, DWORD *len, DWORD required_len)
945 required_len++;
946 if (required_len > *len) {
947 *len = required_len;
948 if (!*buffer)
949 *buffer = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(**buffer));
950 else
951 *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *len * sizeof(**buffer));
952 CHECK_ENOUGH_MEMORY(*buffer);
956 /******************************************************************************
957 * Same as REGPROC_resize_char_buffer() but on a regular buffer.
959 * Parameters:
960 * buffer - pointer to a buffer
961 * len - current size of the buffer in bytes
962 * required_size - size of the data to place in the buffer in bytes
964 static void REGPROC_resize_binary_buffer(BYTE **buffer, DWORD *size, DWORD required_size)
966 if (required_size > *size) {
967 *size = required_size;
968 if (!*buffer)
969 *buffer = HeapAlloc(GetProcessHeap(), 0, *size);
970 else
971 *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *size);
972 CHECK_ENOUGH_MEMORY(*buffer);
976 /******************************************************************************
977 * Prints string str to file
979 static void REGPROC_export_string(WCHAR **line_buf, DWORD *line_buf_size, DWORD *line_len, WCHAR *str, DWORD str_len)
981 DWORD i, pos;
982 DWORD extra = 0;
984 REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + 10);
986 /* escaping characters */
987 pos = *line_len;
988 for (i = 0; i < str_len; i++) {
989 WCHAR c = str[i];
990 switch (c) {
991 case '\n':
992 extra++;
993 REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + extra);
994 (*line_buf)[pos++] = '\\';
995 (*line_buf)[pos++] = 'n';
996 break;
998 case '\r':
999 extra++;
1000 REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + extra);
1001 (*line_buf)[pos++] = '\\';
1002 (*line_buf)[pos++] = 'r';
1003 break;
1005 case '\\':
1006 case '"':
1007 extra++;
1008 REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + extra);
1009 (*line_buf)[pos++] = '\\';
1010 /* Fall through */
1012 default:
1013 (*line_buf)[pos++] = c;
1014 break;
1017 (*line_buf)[pos] = '\0';
1018 *line_len = pos;
1021 static void REGPROC_export_binary(WCHAR **line_buf, DWORD *line_buf_size, DWORD *line_len, DWORD type, BYTE *value, DWORD value_size, BOOL unicode)
1023 DWORD hex_pos, data_pos;
1024 const WCHAR *hex_prefix;
1025 const WCHAR hex[] = {'h','e','x',':',0};
1026 WCHAR hex_buf[17];
1027 const WCHAR concat[] = {'\\','\r','\n',' ',' ',0};
1028 DWORD concat_prefix, concat_len;
1029 const WCHAR newline[] = {'\r','\n',0};
1030 CHAR* value_multibyte = NULL;
1032 if (type == REG_BINARY) {
1033 hex_prefix = hex;
1034 } else {
1035 const WCHAR hex_format[] = {'h','e','x','(','%','x',')',':',0};
1036 hex_prefix = hex_buf;
1037 sprintfW(hex_buf, hex_format, type);
1038 if ((type == REG_SZ || type == REG_EXPAND_SZ || type == REG_MULTI_SZ) && !unicode)
1040 value_multibyte = GetMultiByteStringN((WCHAR*)value, value_size / sizeof(WCHAR), &value_size);
1041 value = (BYTE*)value_multibyte;
1045 concat_len = lstrlenW(concat);
1046 concat_prefix = 2;
1048 hex_pos = *line_len;
1049 *line_len += lstrlenW(hex_prefix);
1050 data_pos = *line_len;
1051 *line_len += value_size * 3;
1052 /* - The 2 spaces that concat places at the start of the
1053 * line effectively reduce the space available for data.
1054 * - If the value name and hex prefix are very long
1055 * ( > REG_FILE_HEX_LINE_LEN) or *line_len divides
1056 * without a remainder then we may overestimate
1057 * the needed number of lines by one. But that's ok.
1058 * - The trailing '\r' takes the place of a comma so
1059 * we only need to add 1 for the trailing '\n'
1061 *line_len += *line_len / (REG_FILE_HEX_LINE_LEN - concat_prefix) * concat_len + 1;
1062 REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len);
1063 lstrcpyW(*line_buf + hex_pos, hex_prefix);
1064 if (value_size)
1066 const WCHAR format[] = {'%','0','2','x',0};
1067 DWORD i, column;
1069 column = data_pos; /* no line wrap yet */
1070 i = 0;
1071 while (1)
1073 sprintfW(*line_buf + data_pos, format, (unsigned int)value[i]);
1074 data_pos += 2;
1075 if (++i == value_size)
1076 break;
1078 (*line_buf)[data_pos++] = ',';
1079 column += 3;
1081 /* wrap the line */
1082 if (column >= REG_FILE_HEX_LINE_LEN) {
1083 lstrcpyW(*line_buf + data_pos, concat);
1084 data_pos += concat_len;
1085 column = concat_prefix;
1089 lstrcpyW(*line_buf + data_pos, newline);
1090 HeapFree(GetProcessHeap(), 0, value_multibyte);
1093 /******************************************************************************
1094 * Writes the given line to a file, in multi-byte or wide characters
1096 static void REGPROC_write_line(FILE *file, const WCHAR* str, BOOL unicode)
1098 if(unicode)
1100 fwrite(str, sizeof(WCHAR), lstrlenW(str), file);
1101 } else
1103 char* strA = GetMultiByteString(str);
1104 fputs(strA, file);
1105 HeapFree(GetProcessHeap(), 0, strA);
1109 /******************************************************************************
1110 * Writes contents of the registry key to the specified file stream.
1112 * Parameters:
1113 * file - writable file stream to export registry branch to.
1114 * key - registry branch to export.
1115 * reg_key_name_buf - name of the key with registry class.
1116 * Is resized if necessary.
1117 * reg_key_name_size - length of the buffer for the registry class in characters.
1118 * val_name_buf - buffer for storing value name.
1119 * Is resized if necessary.
1120 * val_name_size - length of the buffer for storing value names in characters.
1121 * val_buf - buffer for storing values while extracting.
1122 * Is resized if necessary.
1123 * val_size - size of the buffer for storing values in bytes.
1125 static void export_hkey(FILE *file, HKEY key,
1126 WCHAR **reg_key_name_buf, DWORD *reg_key_name_size,
1127 WCHAR **val_name_buf, DWORD *val_name_size,
1128 BYTE **val_buf, DWORD *val_size,
1129 WCHAR **line_buf, DWORD *line_buf_size,
1130 BOOL unicode)
1132 DWORD max_sub_key_len;
1133 DWORD max_val_name_len;
1134 DWORD max_val_size;
1135 DWORD curr_len;
1136 DWORD i;
1137 LONG ret;
1138 WCHAR key_format[] = {'\r','\n','[','%','s',']','\r','\n',0};
1140 /* get size information and resize the buffers if necessary */
1141 if (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL,
1142 &max_sub_key_len, NULL,
1143 NULL, &max_val_name_len, &max_val_size, NULL, NULL
1144 ) != ERROR_SUCCESS)
1145 return;
1146 curr_len = strlenW(*reg_key_name_buf);
1147 REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_size,
1148 max_sub_key_len + curr_len + 1);
1149 REGPROC_resize_char_buffer(val_name_buf, val_name_size,
1150 max_val_name_len);
1151 REGPROC_resize_binary_buffer(val_buf, val_size, max_val_size);
1152 REGPROC_resize_char_buffer(line_buf, line_buf_size, lstrlenW(*reg_key_name_buf) + 4);
1153 /* output data for the current key */
1154 sprintfW(*line_buf, key_format, *reg_key_name_buf);
1155 REGPROC_write_line(file, *line_buf, unicode);
1157 /* print all the values */
1158 i = 0;
1159 for (;;) {
1160 DWORD value_type;
1161 DWORD val_name_size1 = *val_name_size;
1162 DWORD val_size1 = *val_size;
1163 ret = RegEnumValueW(key, i, *val_name_buf, &val_name_size1, NULL,
1164 &value_type, *val_buf, &val_size1);
1165 if (ret == ERROR_MORE_DATA) {
1166 /* Increase the size of the buffers and retry */
1167 REGPROC_resize_char_buffer(val_name_buf, val_name_size, val_name_size1);
1168 REGPROC_resize_binary_buffer(val_buf, val_size, val_size1);
1169 } else if (ret == ERROR_SUCCESS) {
1170 DWORD line_len;
1171 i++;
1173 if ((*val_name_buf)[0]) {
1174 const WCHAR val_start[] = {'"','%','s','"','=',0};
1176 line_len = 0;
1177 REGPROC_export_string(line_buf, line_buf_size, &line_len, *val_name_buf, lstrlenW(*val_name_buf));
1178 REGPROC_resize_char_buffer(val_name_buf, val_name_size, lstrlenW(*line_buf) + 1);
1179 lstrcpyW(*val_name_buf, *line_buf);
1181 line_len = 3 + lstrlenW(*val_name_buf);
1182 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len);
1183 sprintfW(*line_buf, val_start, *val_name_buf);
1184 } else {
1185 const WCHAR std_val[] = {'@','=',0};
1186 line_len = 2;
1187 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len);
1188 lstrcpyW(*line_buf, std_val);
1191 switch (value_type) {
1192 case REG_SZ:
1194 WCHAR* wstr = (WCHAR*)*val_buf;
1196 if (val_size1 < sizeof(WCHAR) || val_size1 % sizeof(WCHAR) ||
1197 wstr[val_size1 / sizeof(WCHAR) - 1]) {
1198 REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode);
1199 } else {
1200 const WCHAR start[] = {'"',0};
1201 const WCHAR end[] = {'"','\r','\n',0};
1202 DWORD len;
1204 len = lstrlenW(start);
1205 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + len);
1206 lstrcpyW(*line_buf + line_len, start);
1207 line_len += len;
1209 REGPROC_export_string(line_buf, line_buf_size, &line_len, wstr, lstrlenW(wstr));
1211 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + lstrlenW(end));
1212 lstrcpyW(*line_buf + line_len, end);
1214 break;
1217 case REG_DWORD:
1219 WCHAR format[] = {'d','w','o','r','d',':','%','0','8','x','\r','\n',0};
1221 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + 15);
1222 sprintfW(*line_buf + line_len, format, *((DWORD *)*val_buf));
1223 break;
1226 default:
1228 output_message(STRING_UNSUPPORTED_TYPE, reg_type_to_wchar(value_type), *reg_key_name_buf);
1229 output_message(STRING_EXPORT_AS_BINARY, *val_name_buf);
1231 /* falls through */
1232 case REG_EXPAND_SZ:
1233 case REG_MULTI_SZ:
1234 /* falls through */
1235 case REG_BINARY:
1236 REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode);
1238 REGPROC_write_line(file, *line_buf, unicode);
1240 else break;
1243 i = 0;
1244 (*reg_key_name_buf)[curr_len] = '\\';
1245 for (;;) {
1246 DWORD buf_size = *reg_key_name_size - curr_len - 1;
1248 ret = RegEnumKeyExW(key, i, *reg_key_name_buf + curr_len + 1, &buf_size,
1249 NULL, NULL, NULL, NULL);
1250 if (ret == ERROR_MORE_DATA) {
1251 /* Increase the size of the buffer and retry */
1252 REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_size, curr_len + 1 + buf_size);
1253 } else if (ret == ERROR_SUCCESS) {
1254 HKEY subkey;
1256 i++;
1257 if (RegOpenKeyW(key, *reg_key_name_buf + curr_len + 1,
1258 &subkey) == ERROR_SUCCESS) {
1259 export_hkey(file, subkey, reg_key_name_buf, reg_key_name_size,
1260 val_name_buf, val_name_size, val_buf, val_size,
1261 line_buf, line_buf_size, unicode);
1262 RegCloseKey(subkey);
1264 else break;
1266 else break;
1268 (*reg_key_name_buf)[curr_len] = '\0';
1271 /******************************************************************************
1272 * Open file in binary mode for export.
1274 static FILE *REGPROC_open_export_file(WCHAR *file_name, BOOL unicode)
1276 FILE *file;
1277 WCHAR dash = '-';
1279 if (strncmpW(file_name,&dash,1)==0) {
1280 file=stdout;
1281 _setmode(_fileno(file), _O_BINARY);
1282 } else
1284 WCHAR wb_mode[] = {'w','b',0};
1285 WCHAR regedit[] = {'r','e','g','e','d','i','t',0};
1287 file = _wfopen(file_name, wb_mode);
1288 if (!file) {
1289 _wperror(regedit);
1290 output_message(STRING_CANNOT_OPEN_FILE, file_name);
1291 exit(1);
1294 if(unicode)
1296 const BYTE unicode_seq[] = {0xff,0xfe};
1297 const WCHAR header[] = {'W','i','n','d','o','w','s',' ','R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ','V','e','r','s','i','o','n',' ','5','.','0','0','\r','\n'};
1298 fwrite(unicode_seq, sizeof(BYTE), sizeof(unicode_seq)/sizeof(unicode_seq[0]), file);
1299 fwrite(header, sizeof(WCHAR), sizeof(header)/sizeof(header[0]), file);
1300 } else
1302 fputs("REGEDIT4\r\n", file);
1305 return file;
1308 /******************************************************************************
1309 * Writes contents of the registry key to the specified file stream.
1311 * Parameters:
1312 * file_name - name of a file to export registry branch to.
1313 * reg_key_name - registry branch to export. The whole registry is exported if
1314 * reg_key_name is NULL or contains an empty string.
1316 BOOL export_registry_key(WCHAR *file_name, WCHAR *reg_key_name, DWORD format)
1318 WCHAR *reg_key_name_buf;
1319 WCHAR *val_name_buf;
1320 BYTE *val_buf;
1321 WCHAR *line_buf;
1322 DWORD reg_key_name_size = KEY_MAX_LEN;
1323 DWORD val_name_size = KEY_MAX_LEN;
1324 DWORD val_size = REG_VAL_BUF_SIZE;
1325 DWORD line_buf_size = KEY_MAX_LEN + REG_VAL_BUF_SIZE;
1326 FILE *file = NULL;
1327 BOOL unicode = (format == REG_FORMAT_5);
1329 reg_key_name_buf = HeapAlloc(GetProcessHeap(), 0,
1330 reg_key_name_size * sizeof(*reg_key_name_buf));
1331 val_name_buf = HeapAlloc(GetProcessHeap(), 0,
1332 val_name_size * sizeof(*val_name_buf));
1333 val_buf = HeapAlloc(GetProcessHeap(), 0, val_size);
1334 line_buf = HeapAlloc(GetProcessHeap(), 0, line_buf_size * sizeof(*line_buf));
1335 CHECK_ENOUGH_MEMORY(reg_key_name_buf && val_name_buf && val_buf && line_buf);
1337 if (reg_key_name && reg_key_name[0]) {
1338 HKEY reg_key_class;
1339 WCHAR *branch_name = NULL;
1340 HKEY key;
1342 REGPROC_resize_char_buffer(&reg_key_name_buf, &reg_key_name_size,
1343 lstrlenW(reg_key_name));
1344 lstrcpyW(reg_key_name_buf, reg_key_name);
1346 /* open the specified key */
1347 if (!(reg_key_class = parse_key_name(reg_key_name, &branch_name))) {
1348 output_message(STRING_INCORRECT_REG_CLASS, reg_key_name);
1349 exit(1);
1351 if (!branch_name || !*branch_name) {
1352 /* no branch - registry class is specified */
1353 file = REGPROC_open_export_file(file_name, unicode);
1354 export_hkey(file, reg_key_class,
1355 &reg_key_name_buf, &reg_key_name_size,
1356 &val_name_buf, &val_name_size,
1357 &val_buf, &val_size, &line_buf,
1358 &line_buf_size, unicode);
1359 } else if (RegOpenKeyW(reg_key_class, branch_name, &key) == ERROR_SUCCESS) {
1360 file = REGPROC_open_export_file(file_name, unicode);
1361 export_hkey(file, key,
1362 &reg_key_name_buf, &reg_key_name_size,
1363 &val_name_buf, &val_name_size,
1364 &val_buf, &val_size, &line_buf,
1365 &line_buf_size, unicode);
1366 RegCloseKey(key);
1367 } else {
1368 output_message(STRING_REG_KEY_NOT_FOUND, reg_key_name);
1370 } else {
1371 unsigned int i;
1373 /* export all registry classes */
1374 file = REGPROC_open_export_file(file_name, unicode);
1375 for (i = 0; i < ARRAY_SIZE(reg_class_keys); i++) {
1376 /* do not export HKEY_CLASSES_ROOT */
1377 if (reg_class_keys[i] != HKEY_CLASSES_ROOT &&
1378 reg_class_keys[i] != HKEY_CURRENT_USER &&
1379 reg_class_keys[i] != HKEY_CURRENT_CONFIG &&
1380 reg_class_keys[i] != HKEY_DYN_DATA) {
1381 lstrcpyW(reg_key_name_buf, reg_class_namesW[i]);
1382 export_hkey(file, reg_class_keys[i],
1383 &reg_key_name_buf, &reg_key_name_size,
1384 &val_name_buf, &val_name_size,
1385 &val_buf, &val_size, &line_buf,
1386 &line_buf_size, unicode);
1391 if (file) {
1392 fclose(file);
1394 HeapFree(GetProcessHeap(), 0, reg_key_name);
1395 HeapFree(GetProcessHeap(), 0, val_name_buf);
1396 HeapFree(GetProcessHeap(), 0, val_buf);
1397 HeapFree(GetProcessHeap(), 0, line_buf);
1398 return TRUE;
1401 /******************************************************************************
1402 * Reads contents of the specified file into the registry.
1404 BOOL import_registry_file(FILE *reg_file)
1406 BYTE s[2];
1407 struct parser parser;
1408 WCHAR *pos;
1410 if (!reg_file || (fread(s, 2, 1, reg_file) != 1))
1411 return FALSE;
1413 parser.is_unicode = (s[0] == 0xff && s[1] == 0xfe);
1414 get_line = parser.is_unicode ? get_lineW : get_lineA;
1416 parser.file = reg_file;
1417 parser.two_wchars[0] = s[0];
1418 parser.two_wchars[1] = s[1];
1419 parser.reg_version = -1;
1420 parser.value_name = NULL;
1421 parser.data_type = 0;
1422 parser.data = NULL;
1423 parser.data_size = 0;
1424 parser.state = HEADER;
1426 pos = parser.two_wchars;
1428 /* parser main loop */
1429 while (pos)
1430 pos = (parser_funcs[parser.state])(&parser, pos);
1432 if (parser.reg_version == REG_VERSION_FUZZY || parser.reg_version == REG_VERSION_INVALID)
1433 return parser.reg_version == REG_VERSION_FUZZY;
1435 closeKey();
1436 return TRUE;
1439 /******************************************************************************
1440 * Removes the registry key with all subkeys. Parses full key name.
1442 * Parameters:
1443 * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
1444 * empty, points to register key class, does not exist.
1446 void delete_registry_key(WCHAR *reg_key_name)
1448 WCHAR *key_name = NULL;
1449 HKEY key_class;
1451 if (!reg_key_name || !reg_key_name[0])
1452 return;
1454 if (!(key_class = parse_key_name(reg_key_name, &key_name))) {
1455 output_message(STRING_INCORRECT_REG_CLASS, reg_key_name);
1456 exit(1);
1458 if (!*key_name) {
1459 output_message(STRING_DELETE_REG_CLASS_FAILED, reg_key_name);
1460 exit(1);
1463 RegDeleteTreeW(key_class, key_name);