regedit: Replace call to delete_branch with RegDeleteTreeA.
[wine.git] / programs / regedit / regproc.c
blobe17a973d799823a345e05158976744f38906fa46
1 /*
2 * Registry processing routines. Routines, common for registry
3 * processing frontends.
5 * Copyright 1999 Sylvain St-Germain
6 * Copyright 2002 Andriy Palamarchuk
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <limits.h>
24 #include <stdio.h>
25 #include <windows.h>
26 #include <winnt.h>
27 #include <winreg.h>
28 #include <assert.h>
29 #include "regproc.h"
31 #define REG_VAL_BUF_SIZE 4096
33 /* maximal number of characters in hexadecimal data line,
34 not including '\' character */
35 #define REG_FILE_HEX_LINE_LEN 76
37 static const CHAR *reg_class_names[] = {
38 "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CLASSES_ROOT",
39 "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA"
42 #define REG_CLASS_NUMBER (sizeof(reg_class_names) / sizeof(reg_class_names[0]))
44 static HKEY reg_class_keys[REG_CLASS_NUMBER] = {
45 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
46 HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA
49 /* return values */
50 #define NOT_ENOUGH_MEMORY 1
51 #define IO_ERROR 2
53 /* processing macros */
55 /* common check of memory allocation results */
56 #define CHECK_ENOUGH_MEMORY(p) \
57 if (!(p)) \
58 { \
59 fprintf(stderr,"%s: file %s, line %d: Not enough memory\n", \
60 getAppName(), __FILE__, __LINE__); \
61 exit(NOT_ENOUGH_MEMORY); \
64 /******************************************************************************
65 * Converts a hex representation of a DWORD into a DWORD.
67 static BOOL convertHexToDWord(char* str, DWORD *dw)
69 char dummy;
70 if (strlen(str) > 8 || sscanf(str, "%x%c", dw, &dummy) != 1) {
71 fprintf(stderr,"%s: ERROR, invalid hex value\n", getAppName());
72 return FALSE;
74 return TRUE;
77 /******************************************************************************
78 * Converts a hex comma separated values list into a binary string.
80 static BYTE* convertHexCSVToHex(char *str, DWORD *size)
82 char *s;
83 BYTE *d, *data;
85 /* The worst case is 1 digit + 1 comma per byte */
86 *size=(strlen(str)+1)/2;
87 data=HeapAlloc(GetProcessHeap(), 0, *size);
88 CHECK_ENOUGH_MEMORY(data);
90 s = str;
91 d = data;
92 *size=0;
93 while (*s != '\0') {
94 UINT wc;
95 char dummy;
97 if (s[1] != ',' && s[1] != '\0' && s[2] != ',' && s[2] != '\0') {
98 fprintf(stderr,"%s: ERROR converting CSV hex stream. Invalid sequence at '%s'\n",
99 getAppName(), s);
100 HeapFree(GetProcessHeap(), 0, data);
101 return NULL;
103 if (sscanf(s, "%x%c", &wc, &dummy) < 1 || dummy != ',') {
104 fprintf(stderr,"%s: ERROR converting CSV hex stream. Invalid value at '%s'\n",
105 getAppName(), s);
106 HeapFree(GetProcessHeap(), 0, data);
107 return NULL;
109 *d++ =(BYTE)wc;
110 (*size)++;
112 /* Skip one or two digits and any comma */
113 while (*s && *s!=',') s++;
114 if (*s) s++;
117 return data;
120 /******************************************************************************
121 * This function returns the HKEY associated with the data type encoded in the
122 * value. It modifies the input parameter (key value) in order to skip this
123 * "now useless" data type information.
125 * Note: Updated based on the algorithm used in 'server/registry.c'
127 static DWORD getDataType(LPSTR *lpValue, DWORD* parse_type)
129 struct data_type { const char *tag; int len; int type; int parse_type; };
131 static const struct data_type data_types[] = { /* actual type */ /* type to assume for parsing */
132 { "\"", 1, REG_SZ, REG_SZ },
133 { "str:\"", 5, REG_SZ, REG_SZ },
134 { "str(2):\"", 8, REG_EXPAND_SZ, REG_SZ },
135 { "hex:", 4, REG_BINARY, REG_BINARY },
136 { "dword:", 6, REG_DWORD, REG_DWORD },
137 { "hex(", 4, -1, REG_BINARY },
138 { NULL, 0, 0, 0 }
141 const struct data_type *ptr;
142 int type;
144 for (ptr = data_types; ptr->tag; ptr++) {
145 if (memcmp( ptr->tag, *lpValue, ptr->len ))
146 continue;
148 /* Found! */
149 *parse_type = ptr->parse_type;
150 type=ptr->type;
151 *lpValue+=ptr->len;
152 if (type == -1) {
153 char* end;
154 /* "hex(xx):" is special */
155 type = (int)strtoul( *lpValue , &end, 16 );
156 if (**lpValue=='\0' || *end!=')' || *(end+1)!=':') {
157 type=REG_NONE;
158 } else {
159 *lpValue=end+2;
162 return type;
164 *parse_type=REG_NONE;
165 return REG_NONE;
168 /******************************************************************************
169 * Replaces escape sequences with the characters.
171 static void REGPROC_unescape_string(LPSTR str)
173 int str_idx = 0; /* current character under analysis */
174 int val_idx = 0; /* the last character of the unescaped string */
175 int len = strlen(str);
176 for (str_idx = 0; str_idx < len; str_idx++, val_idx++) {
177 if (str[str_idx] == '\\') {
178 str_idx++;
179 switch (str[str_idx]) {
180 case 'n':
181 str[val_idx] = '\n';
182 break;
183 case '\\':
184 case '"':
185 str[val_idx] = str[str_idx];
186 break;
187 default:
188 fprintf(stderr,"Warning! Unrecognized escape sequence: \\%c'\n",
189 str[str_idx]);
190 str[val_idx] = str[str_idx];
191 break;
193 } else {
194 str[val_idx] = str[str_idx];
197 str[val_idx] = '\0';
200 /******************************************************************************
201 * Parses HKEY_SOME_ROOT\some\key\path to get the root key handle and
202 * extract the key path (what comes after the first '\').
204 static BOOL parseKeyName(LPSTR lpKeyName, HKEY *hKey, LPSTR *lpKeyPath)
206 LPSTR lpSlash;
207 unsigned int i, len;
209 if (lpKeyName == NULL)
210 return FALSE;
212 lpSlash = strchr(lpKeyName, '\\');
213 if (lpSlash)
215 len = lpSlash-lpKeyName;
217 else
219 len = strlen(lpKeyName);
220 lpSlash = lpKeyName+len;
222 *hKey = NULL;
223 for (i = 0; i < REG_CLASS_NUMBER; i++) {
224 if (strncmp(lpKeyName, reg_class_names[i], len) == 0 &&
225 len == strlen(reg_class_names[i])) {
226 *hKey = reg_class_keys[i];
227 break;
230 if (*hKey == NULL)
231 return FALSE;
233 if (*lpSlash != '\0')
234 lpSlash++;
235 *lpKeyPath = lpSlash;
236 return TRUE;
239 /* Globals used by the setValue() & co */
240 static LPSTR currentKeyName;
241 static HKEY currentKeyHandle = NULL;
243 /******************************************************************************
244 * Sets the value with name val_name to the data in val_data for the currently
245 * opened key.
247 * Parameters:
248 * val_name - name of the registry value
249 * val_data - registry value data
251 static LONG setValue(LPSTR val_name, LPSTR val_data)
253 LONG res;
254 DWORD dwDataType, dwParseType;
255 LPBYTE lpbData;
256 DWORD dwData, dwLen;
258 if ( (val_name == NULL) || (val_data == NULL) )
259 return ERROR_INVALID_PARAMETER;
261 if (strcmp(val_data, "-") == 0)
263 res=RegDeleteValue(currentKeyHandle,val_name);
264 return (res == ERROR_FILE_NOT_FOUND ? ERROR_SUCCESS : res);
267 /* Get the data type stored into the value field */
268 dwDataType = getDataType(&val_data, &dwParseType);
270 if (dwParseType == REG_SZ) /* no conversion for string */
272 REGPROC_unescape_string(val_data);
273 /* Compute dwLen after REGPROC_unescape_string because it may
274 * have changed the string length and we don't want to store
275 * the extra garbage in the registry.
277 dwLen = strlen(val_data);
278 if (dwLen>0 && val_data[dwLen-1]=='"')
280 dwLen--;
281 val_data[dwLen]='\0';
283 lpbData = (BYTE*) val_data;
285 else if (dwParseType == REG_DWORD) /* Convert the dword types */
287 if (!convertHexToDWord(val_data, &dwData))
288 return ERROR_INVALID_DATA;
289 lpbData = (BYTE*)&dwData;
290 dwLen = sizeof(dwData);
292 else if (dwParseType == REG_BINARY) /* Convert the binary data */
294 lpbData = convertHexCSVToHex(val_data, &dwLen);
295 if (!lpbData)
296 return ERROR_INVALID_DATA;
298 else /* unknown format */
300 fprintf(stderr,"%s: ERROR, unknown data format\n", getAppName());
301 return ERROR_INVALID_DATA;
304 res = RegSetValueEx(
305 currentKeyHandle,
306 val_name,
307 0, /* Reserved */
308 dwDataType,
309 lpbData,
310 dwLen);
311 if (dwParseType == REG_BINARY)
312 HeapFree(GetProcessHeap(), 0, lpbData);
313 return res;
316 /******************************************************************************
317 * A helper function for processRegEntry() that opens the current key.
318 * That key must be closed by calling closeKey().
320 static LONG openKey(LPSTR stdInput)
322 HKEY keyClass;
323 LPSTR keyPath;
324 DWORD dwDisp;
325 LONG res;
327 /* Sanity checks */
328 if (stdInput == NULL)
329 return ERROR_INVALID_PARAMETER;
331 /* Get the registry class */
332 if (!parseKeyName(stdInput, &keyClass, &keyPath))
333 return ERROR_INVALID_PARAMETER;
335 res = RegCreateKeyEx(
336 keyClass, /* Class */
337 keyPath, /* Sub Key */
338 0, /* MUST BE 0 */
339 NULL, /* object type */
340 REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */
341 KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */
342 NULL, /* security attribute */
343 &currentKeyHandle, /* result */
344 &dwDisp); /* disposition, REG_CREATED_NEW_KEY or
345 REG_OPENED_EXISTING_KEY */
347 if (res == ERROR_SUCCESS)
349 currentKeyName = HeapAlloc(GetProcessHeap(), 0, strlen(stdInput)+1);
350 CHECK_ENOUGH_MEMORY(currentKeyName);
351 strcpy(currentKeyName, stdInput);
353 else
355 currentKeyHandle = NULL;
358 return res;
362 /******************************************************************************
363 * Close the currently opened key.
365 static void closeKey(void)
367 if (currentKeyHandle)
369 HeapFree(GetProcessHeap(), 0, currentKeyName);
370 RegCloseKey(currentKeyHandle);
371 currentKeyHandle = NULL;
375 /******************************************************************************
376 * This function is a wrapper for the setValue function. It prepares the
377 * land and clean the area once completed.
378 * Note: this function modifies the line parameter.
380 * line - registry file unwrapped line. Should have the registry value name and
381 * complete registry value data.
383 static void processSetValue(LPSTR line)
385 LPSTR val_name; /* registry value name */
386 LPSTR val_data; /* registry value data */
388 int line_idx = 0; /* current character under analysis */
389 LONG res;
391 /* get value name */
392 if (line[line_idx] == '@' && line[line_idx + 1] == '=') {
393 line[line_idx] = '\0';
394 val_name = line;
395 line_idx++;
396 } else if (line[line_idx] == '\"') {
397 line_idx++;
398 val_name = line + line_idx;
399 while (TRUE) {
400 if (line[line_idx] == '\\') /* skip escaped character */
402 line_idx += 2;
403 } else {
404 if (line[line_idx] == '\"') {
405 line[line_idx] = '\0';
406 line_idx++;
407 break;
408 } else {
409 line_idx++;
413 if (line[line_idx] != '=') {
414 line[line_idx] = '\"';
415 fprintf(stderr,"Warning! unrecognized line:\n%s\n", line);
416 return;
419 } else {
420 fprintf(stderr,"Warning! unrecognized line:\n%s\n", line);
421 return;
423 line_idx++; /* skip the '=' character */
424 val_data = line + line_idx;
426 REGPROC_unescape_string(val_name);
427 res = setValue(val_name, val_data);
428 if ( res != ERROR_SUCCESS )
429 fprintf(stderr,"%s: ERROR Key %s not created. Value: %s, Data: %s\n",
430 getAppName(),
431 currentKeyName,
432 val_name,
433 val_data);
436 /******************************************************************************
437 * This function receives the currently read entry and performs the
438 * corresponding action.
440 static void processRegEntry(LPSTR stdInput)
443 * We encountered the end of the file, make sure we
444 * close the opened key and exit
446 if (stdInput == NULL) {
447 closeKey();
448 return;
451 if ( stdInput[0] == '[') /* We are reading a new key */
453 LPSTR keyEnd;
454 closeKey(); /* Close the previous key */
456 /* Get rid of the square brackets */
457 stdInput++;
458 keyEnd = strrchr(stdInput, ']');
459 if (keyEnd)
460 *keyEnd='\0';
462 /* delete the key if we encounter '-' at the start of reg key */
463 if ( stdInput[0] == '-')
464 delete_registry_key(stdInput+1);
465 else if ( openKey(stdInput) != ERROR_SUCCESS )
466 fprintf(stderr,"%s: setValue failed to open key %s\n",
467 getAppName(), stdInput);
468 } else if( currentKeyHandle &&
469 (( stdInput[0] == '@') || /* reading a default @=data pair */
470 ( stdInput[0] == '\"'))) /* reading a new value=data pair */
472 processSetValue(stdInput);
473 } else
475 /* Since we are assuming that the file format is valid we must be
476 * reading a blank line which indicates the end of this key processing
478 closeKey();
482 /******************************************************************************
483 * Processes a registry file.
484 * Correctly processes comments (in # form), line continuation.
486 * Parameters:
487 * in - input stream to read from
489 void processRegLines(FILE *in)
491 LPSTR line = NULL; /* line read from input stream */
492 ULONG lineSize = REG_VAL_BUF_SIZE;
494 line = HeapAlloc(GetProcessHeap(), 0, lineSize);
495 CHECK_ENOUGH_MEMORY(line);
497 while (!feof(in)) {
498 LPSTR s; /* The pointer into line for where the current fgets should read */
499 s = line;
500 for (;;) {
501 size_t size_remaining;
502 int size_to_get;
503 char *s_eol; /* various local uses */
505 /* Do we need to expand the buffer ? */
506 assert (s >= line && s <= line + lineSize);
507 size_remaining = lineSize - (s-line);
508 if (size_remaining < 2) /* room for 1 character and the \0 */
510 char *new_buffer;
511 size_t new_size = lineSize + REG_VAL_BUF_SIZE;
512 if (new_size > lineSize) /* no arithmetic overflow */
513 new_buffer = HeapReAlloc (GetProcessHeap(), 0, line, new_size);
514 else
515 new_buffer = NULL;
516 CHECK_ENOUGH_MEMORY(new_buffer);
517 line = new_buffer;
518 s = line + lineSize - size_remaining;
519 lineSize = new_size;
520 size_remaining = lineSize - (s-line);
523 /* Get as much as possible into the buffer, terminated either by
524 * eof, error, eol or getting the maximum amount. Abort on error.
526 size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
527 if (NULL == fgets (s, size_to_get, in)) {
528 if (ferror(in)) {
529 perror ("While reading input");
530 exit (IO_ERROR);
531 } else {
532 assert (feof(in));
533 *s = '\0';
534 /* It is not clear to me from the definition that the
535 * contents of the buffer are well defined on detecting
536 * an eof without managing to read anything.
541 /* If we didn't read the eol nor the eof go around for the rest */
542 s_eol = strchr (s, '\n');
543 if (!feof (in) && !s_eol) {
544 s = strchr (s, '\0');
545 /* It should be s + size_to_get - 1 but this is safer */
546 continue;
549 /* If it is a comment line then discard it and go around again */
550 if (line [0] == '#') {
551 s = line;
552 continue;
555 /* Remove any line feed. Leave s_eol on the \0 */
556 if (s_eol) {
557 *s_eol = '\0';
558 if (s_eol > line && *(s_eol-1) == '\r')
559 *--s_eol = '\0';
560 } else
561 s_eol = strchr (s, '\0');
563 /* If there is a concatenating \\ then go around again */
564 if (s_eol > line && *(s_eol-1) == '\\') {
565 int c;
566 s = s_eol-1;
567 /* The following error protection could be made more self-
568 * correcting but I thought it not worth trying.
570 if ((c = fgetc (in)) == EOF || c != ' ' ||
571 (c = fgetc (in)) == EOF || c != ' ')
572 fprintf(stderr,"%s: ERROR - invalid continuation.\n",
573 getAppName());
574 continue;
577 break; /* That is the full virtual line */
580 processRegEntry(line);
582 processRegEntry(NULL);
584 HeapFree(GetProcessHeap(), 0, line);
587 /****************************************************************************
588 * REGPROC_print_error
590 * Print the message for GetLastError
593 static void REGPROC_print_error(void)
595 LPVOID lpMsgBuf;
596 DWORD error_code;
597 int status;
599 error_code = GetLastError ();
600 status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
601 NULL, error_code, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
602 if (!status) {
603 fprintf(stderr,"%s: Cannot display message for error %d, status %d\n",
604 getAppName(), error_code, GetLastError());
605 exit(1);
607 puts(lpMsgBuf);
608 LocalFree((HLOCAL)lpMsgBuf);
609 exit(1);
612 /******************************************************************************
613 * Checks whether the buffer has enough room for the string or required size.
614 * Resizes the buffer if necessary.
616 * Parameters:
617 * buffer - pointer to a buffer for string
618 * len - current length of the buffer in characters.
619 * required_len - length of the string to place to the buffer in characters.
620 * The length does not include the terminating null character.
622 static void REGPROC_resize_char_buffer(CHAR **buffer, DWORD *len, DWORD required_len)
624 required_len++;
625 if (required_len > *len) {
626 *len = required_len;
627 if (!*buffer)
628 *buffer = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(**buffer));
629 else
630 *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *len * sizeof(**buffer));
631 CHECK_ENOUGH_MEMORY(*buffer);
635 /******************************************************************************
636 * Prints string str to file
638 static void REGPROC_export_string(FILE *file, CHAR *str)
640 size_t len = strlen(str);
641 size_t i;
643 /* escaping characters */
644 for (i = 0; i < len; i++) {
645 CHAR c = str[i];
646 switch (c) {
647 case '\\':
648 fputs("\\\\", file);
649 break;
650 case '\"':
651 fputs("\\\"", file);
652 break;
653 case '\n':
654 fputs("\\\n", file);
655 break;
656 default:
657 fputc(c, file);
658 break;
663 /******************************************************************************
664 * Writes contents of the registry key to the specified file stream.
666 * Parameters:
667 * file - writable file stream to export registry branch to.
668 * key - registry branch to export.
669 * reg_key_name_buf - name of the key with registry class.
670 * Is resized if necessary.
671 * reg_key_name_len - length of the buffer for the registry class in characters.
672 * val_name_buf - buffer for storing value name.
673 * Is resized if necessary.
674 * val_name_len - length of the buffer for storing value names in characters.
675 * val_buf - buffer for storing values while extracting.
676 * Is resized if necessary.
677 * val_size - size of the buffer for storing values in bytes.
679 static void export_hkey(FILE *file, HKEY key,
680 CHAR **reg_key_name_buf, DWORD *reg_key_name_len,
681 CHAR **val_name_buf, DWORD *val_name_len,
682 BYTE **val_buf, DWORD *val_size)
684 DWORD max_sub_key_len;
685 DWORD max_val_name_len;
686 DWORD max_val_size;
687 DWORD curr_len;
688 DWORD i;
689 BOOL more_data;
690 LONG ret;
692 /* get size information and resize the buffers if necessary */
693 if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL,
694 &max_sub_key_len, NULL,
695 NULL, &max_val_name_len, &max_val_size, NULL, NULL
696 ) != ERROR_SUCCESS) {
697 REGPROC_print_error();
699 curr_len = strlen(*reg_key_name_buf);
700 REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_len,
701 max_sub_key_len + curr_len + 1);
702 REGPROC_resize_char_buffer(val_name_buf, val_name_len,
703 max_val_name_len);
704 if (max_val_size > *val_size) {
705 *val_size = max_val_size;
706 if (!*val_buf) *val_buf = HeapAlloc(GetProcessHeap(), 0, *val_size);
707 else *val_buf = HeapReAlloc(GetProcessHeap(), 0, *val_buf, *val_size);
708 CHECK_ENOUGH_MEMORY(val_buf);
711 /* output data for the current key */
712 fputs("\n[", file);
713 fputs(*reg_key_name_buf, file);
714 fputs("]\n", file);
715 /* print all the values */
716 i = 0;
717 more_data = TRUE;
718 while(more_data) {
719 DWORD value_type;
720 DWORD val_name_len1 = *val_name_len;
721 DWORD val_size1 = *val_size;
722 ret = RegEnumValue(key, i, *val_name_buf, &val_name_len1, NULL,
723 &value_type, *val_buf, &val_size1);
724 if (ret != ERROR_SUCCESS) {
725 more_data = FALSE;
726 if (ret != ERROR_NO_MORE_ITEMS) {
727 REGPROC_print_error();
729 } else {
730 i++;
732 if ((*val_name_buf)[0]) {
733 fputs("\"", file);
734 REGPROC_export_string(file, *val_name_buf);
735 fputs("\"=", file);
736 } else {
737 fputs("@=", file);
740 switch (value_type) {
741 case REG_SZ:
742 case REG_EXPAND_SZ:
743 fputs("\"", file);
744 REGPROC_export_string(file, (char*) *val_buf);
745 fputs("\"\n", file);
746 break;
748 case REG_DWORD:
749 fprintf(file, "dword:%08x\n", *((DWORD *)*val_buf));
750 break;
752 default:
753 fprintf(stderr,"%s: warning - unsupported registry format '%d', "
754 "treat as binary\n",
755 getAppName(), value_type);
756 fprintf(stderr,"key name: \"%s\"\n", *reg_key_name_buf);
757 fprintf(stderr,"value name:\"%s\"\n\n", *val_name_buf);
758 /* falls through */
759 case REG_MULTI_SZ:
760 /* falls through */
761 case REG_BINARY: {
762 DWORD i1;
763 const CHAR *hex_prefix;
764 CHAR buf[20];
765 int cur_pos;
767 if (value_type == REG_BINARY) {
768 hex_prefix = "hex:";
769 } else {
770 hex_prefix = buf;
771 sprintf(buf, "hex(%d):", value_type);
774 /* position of where the next character will be printed */
775 /* NOTE: yes, strlen("hex:") is used even for hex(x): */
776 cur_pos = strlen("\"\"=") + strlen("hex:") +
777 strlen(*val_name_buf);
779 fputs(hex_prefix, file);
780 for (i1 = 0; i1 < val_size1; i1++) {
781 fprintf(file, "%02x", (unsigned int)(*val_buf)[i1]);
782 if (i1 + 1 < val_size1) {
783 fputs(",", file);
785 cur_pos += 3;
787 /* wrap the line */
788 if (cur_pos > REG_FILE_HEX_LINE_LEN) {
789 fputs("\\\n ", file);
790 cur_pos = 2;
793 fputs("\n", file);
794 break;
800 i = 0;
801 more_data = TRUE;
802 (*reg_key_name_buf)[curr_len] = '\\';
803 while(more_data) {
804 DWORD buf_len = *reg_key_name_len - curr_len;
806 ret = RegEnumKeyEx(key, i, *reg_key_name_buf + curr_len + 1, &buf_len,
807 NULL, NULL, NULL, NULL);
808 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
809 more_data = FALSE;
810 if (ret != ERROR_NO_MORE_ITEMS) {
811 REGPROC_print_error();
813 } else {
814 HKEY subkey;
816 i++;
817 if (RegOpenKey(key, *reg_key_name_buf + curr_len + 1,
818 &subkey) == ERROR_SUCCESS) {
819 export_hkey(file, subkey, reg_key_name_buf, reg_key_name_len,
820 val_name_buf, val_name_len, val_buf, val_size);
821 RegCloseKey(subkey);
822 } else {
823 REGPROC_print_error();
827 (*reg_key_name_buf)[curr_len] = '\0';
830 /******************************************************************************
831 * Open file for export.
833 static FILE *REGPROC_open_export_file(CHAR *file_name)
835 FILE *file;
837 if (strcmp(file_name,"-")==0)
838 file=stdout;
839 else
841 file = fopen(file_name, "w");
842 if (!file) {
843 perror("");
844 fprintf(stderr,"%s: Can't open file \"%s\"\n", getAppName(), file_name);
845 exit(1);
848 fputs("REGEDIT4\n", file);
849 return file;
852 /******************************************************************************
853 * Writes contents of the registry key to the specified file stream.
855 * Parameters:
856 * file_name - name of a file to export registry branch to.
857 * reg_key_name - registry branch to export. The whole registry is exported if
858 * reg_key_name is NULL or contains an empty string.
860 BOOL export_registry_key(CHAR *file_name, CHAR *reg_key_name)
862 CHAR *reg_key_name_buf;
863 CHAR *val_name_buf;
864 BYTE *val_buf;
865 DWORD reg_key_name_len = KEY_MAX_LEN;
866 DWORD val_name_len = KEY_MAX_LEN;
867 DWORD val_size = REG_VAL_BUF_SIZE;
868 FILE *file = NULL;
870 reg_key_name_buf = HeapAlloc(GetProcessHeap(), 0,
871 reg_key_name_len * sizeof(*reg_key_name_buf));
872 val_name_buf = HeapAlloc(GetProcessHeap(), 0,
873 val_name_len * sizeof(*val_name_buf));
874 val_buf = HeapAlloc(GetProcessHeap(), 0, val_size);
875 CHECK_ENOUGH_MEMORY(reg_key_name_buf && val_name_buf && val_buf);
877 if (reg_key_name && reg_key_name[0]) {
878 HKEY reg_key_class;
879 CHAR *branch_name;
880 HKEY key;
882 REGPROC_resize_char_buffer(&reg_key_name_buf, &reg_key_name_len,
883 strlen(reg_key_name));
884 strcpy(reg_key_name_buf, reg_key_name);
886 /* open the specified key */
887 if (!parseKeyName(reg_key_name, &reg_key_class, &branch_name)) {
888 fprintf(stderr,"%s: Incorrect registry class specification in '%s'\n",
889 getAppName(), reg_key_name);
890 exit(1);
892 if (!branch_name[0]) {
893 /* no branch - registry class is specified */
894 file = REGPROC_open_export_file(file_name);
895 export_hkey(file, reg_key_class,
896 &reg_key_name_buf, &reg_key_name_len,
897 &val_name_buf, &val_name_len,
898 &val_buf, &val_size);
899 } else if (RegOpenKey(reg_key_class, branch_name, &key) == ERROR_SUCCESS) {
900 file = REGPROC_open_export_file(file_name);
901 export_hkey(file, key,
902 &reg_key_name_buf, &reg_key_name_len,
903 &val_name_buf, &val_name_len,
904 &val_buf, &val_size);
905 RegCloseKey(key);
906 } else {
907 fprintf(stderr,"%s: Can't export. Registry key '%s' does not exist!\n",
908 getAppName(), reg_key_name);
909 REGPROC_print_error();
911 } else {
912 unsigned int i;
914 /* export all registry classes */
915 file = REGPROC_open_export_file(file_name);
916 for (i = 0; i < REG_CLASS_NUMBER; i++) {
917 /* do not export HKEY_CLASSES_ROOT */
918 if (reg_class_keys[i] != HKEY_CLASSES_ROOT &&
919 reg_class_keys[i] != HKEY_CURRENT_USER &&
920 reg_class_keys[i] != HKEY_CURRENT_CONFIG &&
921 reg_class_keys[i] != HKEY_DYN_DATA) {
922 strcpy(reg_key_name_buf, reg_class_names[i]);
923 export_hkey(file, reg_class_keys[i],
924 &reg_key_name_buf, &reg_key_name_len,
925 &val_name_buf, &val_name_len,
926 &val_buf, &val_size);
931 if (file) {
932 fclose(file);
934 HeapFree(GetProcessHeap(), 0, reg_key_name);
935 HeapFree(GetProcessHeap(), 0, val_buf);
936 return TRUE;
939 /******************************************************************************
940 * Reads contents of the specified file into the registry.
942 BOOL import_registry_file(LPTSTR filename)
944 FILE* reg_file = fopen(filename, "r");
946 if (reg_file) {
947 processRegLines(reg_file);
948 return TRUE;
950 return FALSE;
953 /******************************************************************************
954 * Removes the registry key with all subkeys. Parses full key name.
956 * Parameters:
957 * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
958 * empty, points to register key class, does not exist.
960 void delete_registry_key(CHAR *reg_key_name)
962 CHAR *key_name;
963 HKEY key_class;
965 if (!reg_key_name || !reg_key_name[0])
966 return;
968 if (!parseKeyName(reg_key_name, &key_class, &key_name)) {
969 fprintf(stderr,"%s: Incorrect registry class specification in '%s'\n",
970 getAppName(), reg_key_name);
971 exit(1);
973 if (!*key_name) {
974 fprintf(stderr,"%s: Can't delete registry class '%s'\n",
975 getAppName(), reg_key_name);
976 exit(1);
979 RegDeleteTreeA(key_class, key_name);