push 553a83299288f61678d62ade87a3a2a5489a8ad8
[wine/hacks.git] / programs / regedit / regproc.c
blobb9825d4a8e0919325ff0fceef9b1f773a18f9277
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 <wine/unicode.h>
30 #include "regproc.h"
32 #define REG_VAL_BUF_SIZE 4096
34 /* maximal number of characters in hexadecimal data line,
35 not including '\' character */
36 #define REG_FILE_HEX_LINE_LEN 76
38 static const CHAR *reg_class_names[] = {
39 "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CLASSES_ROOT",
40 "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA"
43 #define REG_CLASS_NUMBER (sizeof(reg_class_names) / sizeof(reg_class_names[0]))
45 extern const WCHAR* reg_class_namesW[];
47 static HKEY reg_class_keys[REG_CLASS_NUMBER] = {
48 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
49 HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA
52 /* return values */
53 #define NOT_ENOUGH_MEMORY 1
54 #define IO_ERROR 2
56 /* processing macros */
58 /* common check of memory allocation results */
59 #define CHECK_ENOUGH_MEMORY(p) \
60 if (!(p)) \
61 { \
62 fprintf(stderr,"%s: file %s, line %d: Not enough memory\n", \
63 getAppName(), __FILE__, __LINE__); \
64 exit(NOT_ENOUGH_MEMORY); \
67 /******************************************************************************
68 * Allocates memory and convers input from multibyte to wide chars
69 * Returned string must be freed by the caller
71 WCHAR* GetWideString(const char* strA)
73 if(strA)
75 WCHAR* strW = NULL;
76 int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0);
78 strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
79 CHECK_ENOUGH_MEMORY(strW);
80 MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len);
81 return strW;
83 return NULL;
86 /******************************************************************************
87 * Allocates memory and convers input from wide chars to multibyte
88 * Returned string must be freed by the caller
90 char* GetMultiByteString(const WCHAR* strW)
92 if(strW)
94 char* strA = NULL;
95 int len = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL);
97 strA = HeapAlloc(GetProcessHeap(), 0, len);
98 CHECK_ENOUGH_MEMORY(strA);
99 WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, len, NULL, NULL);
100 return strA;
102 return NULL;
105 /******************************************************************************
106 * Converts a hex representation of a DWORD into a DWORD.
108 static BOOL convertHexToDWord(WCHAR* str, DWORD *dw)
110 char buf[9];
111 char dummy;
113 WideCharToMultiByte(CP_ACP, 0, str, -1, buf, 9, NULL, NULL);
114 if (lstrlenW(str) > 8 || sscanf(buf, "%x%c", dw, &dummy) != 1) {
115 fprintf(stderr,"%s: ERROR, invalid hex value\n", getAppName());
116 return FALSE;
118 return TRUE;
121 /******************************************************************************
122 * Converts a hex comma separated values list into a binary string.
124 static BYTE* convertHexCSVToHex(WCHAR *str, DWORD *size)
126 WCHAR *s;
127 BYTE *d, *data;
129 /* The worst case is 1 digit + 1 comma per byte */
130 *size=(lstrlenW(str)+1)/2;
131 data=HeapAlloc(GetProcessHeap(), 0, *size);
132 CHECK_ENOUGH_MEMORY(data);
134 s = str;
135 d = data;
136 *size=0;
137 while (*s != '\0') {
138 UINT wc;
139 WCHAR *end;
141 wc = strtoulW(s,&end,16);
142 if (end == s || wc > 0xff || (*end && *end != ',')) {
143 char* strA = GetMultiByteString(s);
144 fprintf(stderr,"%s: ERROR converting CSV hex stream. Invalid value at '%s'\n",
145 getAppName(), strA);
146 HeapFree(GetProcessHeap(), 0, data);
147 HeapFree(GetProcessHeap(), 0, strA);
148 return NULL;
150 *d++ =(BYTE)wc;
151 (*size)++;
152 if (*end) end++;
153 s = end;
156 return data;
159 /******************************************************************************
160 * This function returns the HKEY associated with the data type encoded in the
161 * value. It modifies the input parameter (key value) in order to skip this
162 * "now useless" data type information.
164 * Note: Updated based on the algorithm used in 'server/registry.c'
166 static DWORD getDataType(LPWSTR *lpValue, DWORD* parse_type)
168 struct data_type { const WCHAR *tag; int len; int type; int parse_type; };
170 static const WCHAR quote[] = {'"'};
171 static const WCHAR str[] = {'s','t','r',':','"'};
172 static const WCHAR str2[] = {'s','t','r','(','2',')',':','"'};
173 static const WCHAR hex[] = {'h','e','x',':'};
174 static const WCHAR dword[] = {'d','w','o','r','d',':'};
175 static const WCHAR hexp[] = {'h','e','x','('};
177 static const struct data_type data_types[] = { /* actual type */ /* type to assume for parsing */
178 { quote, 1, REG_SZ, REG_SZ },
179 { str, 5, REG_SZ, REG_SZ },
180 { str2, 8, REG_EXPAND_SZ, REG_SZ },
181 { hex, 4, REG_BINARY, REG_BINARY },
182 { dword, 6, REG_DWORD, REG_DWORD },
183 { hexp, 4, -1, REG_BINARY },
184 { NULL, 0, 0, 0 }
187 const struct data_type *ptr;
188 int type;
190 for (ptr = data_types; ptr->tag; ptr++) {
191 if (strncmpW( ptr->tag, *lpValue, ptr->len ))
192 continue;
194 /* Found! */
195 *parse_type = ptr->parse_type;
196 type=ptr->type;
197 *lpValue+=ptr->len;
198 if (type == -1) {
199 WCHAR* end;
201 /* "hex(xx):" is special */
202 type = (int)strtoulW( *lpValue , &end, 16 );
203 if (**lpValue=='\0' || *end!=')' || *(end+1)!=':') {
204 type=REG_NONE;
205 } else {
206 *lpValue = end + 2;
209 return type;
211 *parse_type=REG_NONE;
212 return REG_NONE;
215 /******************************************************************************
216 * Replaces escape sequences with the characters.
218 static void REGPROC_unescape_string(WCHAR* str)
220 int str_idx = 0; /* current character under analysis */
221 int val_idx = 0; /* the last character of the unescaped string */
222 int len = lstrlenW(str);
223 for (str_idx = 0; str_idx < len; str_idx++, val_idx++) {
224 if (str[str_idx] == '\\') {
225 str_idx++;
226 switch (str[str_idx]) {
227 case 'n':
228 str[val_idx] = '\n';
229 break;
230 case '\\':
231 case '"':
232 str[val_idx] = str[str_idx];
233 break;
234 default:
235 fprintf(stderr,"Warning! Unrecognized escape sequence: \\%c'\n",
236 str[str_idx]);
237 str[val_idx] = str[str_idx];
238 break;
240 } else {
241 str[val_idx] = str[str_idx];
244 str[val_idx] = '\0';
247 /******************************************************************************
248 * Parses HKEY_SOME_ROOT\some\key\path to get the root key handle and
249 * extract the key path (what comes after the first '\').
251 static BOOL parseKeyName(LPSTR lpKeyName, HKEY *hKey, LPSTR *lpKeyPath)
253 LPSTR lpSlash;
254 unsigned int i, len;
256 if (lpKeyName == NULL)
257 return FALSE;
259 lpSlash = strchr(lpKeyName, '\\');
260 if (lpSlash)
262 len = lpSlash-lpKeyName;
264 else
266 len = strlen(lpKeyName);
267 lpSlash = lpKeyName+len;
269 *hKey = NULL;
270 for (i = 0; i < REG_CLASS_NUMBER; i++) {
271 if (strncmp(lpKeyName, reg_class_names[i], len) == 0 &&
272 len == strlen(reg_class_names[i])) {
273 *hKey = reg_class_keys[i];
274 break;
277 if (*hKey == NULL)
278 return FALSE;
280 if (*lpSlash != '\0')
281 lpSlash++;
282 *lpKeyPath = lpSlash;
283 return TRUE;
286 static BOOL parseKeyNameW(LPWSTR lpKeyName, HKEY *hKey, LPWSTR *lpKeyPath)
288 WCHAR* lpSlash = NULL;
289 unsigned int i, len;
291 if (lpKeyName == NULL)
292 return FALSE;
294 for(i = 0; *(lpKeyName+i) != 0; i++)
296 if(*(lpKeyName+i) == '\\')
298 lpSlash = lpKeyName+i;
299 break;
303 if (lpSlash)
305 len = lpSlash-lpKeyName;
307 else
309 len = lstrlenW(lpKeyName);
310 lpSlash = lpKeyName+len;
312 *hKey = NULL;
314 for (i = 0; i < REG_CLASS_NUMBER; i++) {
315 if (CompareStringW(LOCALE_USER_DEFAULT, 0, lpKeyName, len, reg_class_namesW[i], len) == CSTR_EQUAL &&
316 len == lstrlenW(reg_class_namesW[i])) {
317 *hKey = reg_class_keys[i];
318 break;
322 if (*hKey == NULL)
323 return FALSE;
326 if (*lpSlash != '\0')
327 lpSlash++;
328 *lpKeyPath = lpSlash;
329 return TRUE;
332 /* Globals used by the setValue() & co */
333 static LPSTR currentKeyName;
334 static HKEY currentKeyHandle = NULL;
336 /******************************************************************************
337 * Sets the value with name val_name to the data in val_data for the currently
338 * opened key.
340 * Parameters:
341 * val_name - name of the registry value
342 * val_data - registry value data
344 static LONG setValue(WCHAR* val_name, WCHAR* val_data)
346 LONG res;
347 DWORD dwDataType, dwParseType;
348 LPBYTE lpbData;
349 DWORD dwData, dwLen;
350 WCHAR del[] = {'-',0};
352 if ( (val_name == NULL) || (val_data == NULL) )
353 return ERROR_INVALID_PARAMETER;
355 if (lstrcmpW(val_data, del) == 0)
357 res=RegDeleteValueW(currentKeyHandle,val_name);
358 return (res == ERROR_FILE_NOT_FOUND ? ERROR_SUCCESS : res);
361 /* Get the data type stored into the value field */
362 dwDataType = getDataType(&val_data, &dwParseType);
364 if (dwParseType == REG_SZ) /* no conversion for string */
366 REGPROC_unescape_string(val_data);
367 /* Compute dwLen after REGPROC_unescape_string because it may
368 * have changed the string length and we don't want to store
369 * the extra garbage in the registry.
371 dwLen = lstrlenW(val_data);
372 if (dwLen>0 && val_data[dwLen-1]=='"')
374 dwLen--;
375 val_data[dwLen]='\0';
377 lpbData = (BYTE*) val_data;
378 dwLen++; /* include terminating null */
379 dwLen = dwLen * sizeof(WCHAR); /* size is in bytes */
381 else if (dwParseType == REG_DWORD) /* Convert the dword types */
383 if (!convertHexToDWord(val_data, &dwData))
384 return ERROR_INVALID_DATA;
385 lpbData = (BYTE*)&dwData;
386 dwLen = sizeof(dwData);
388 else if (dwParseType == REG_BINARY) /* Convert the binary data */
390 lpbData = convertHexCSVToHex(val_data, &dwLen);
391 if (!lpbData)
392 return ERROR_INVALID_DATA;
394 else /* unknown format */
396 fprintf(stderr,"%s: ERROR, unknown data format\n", getAppName());
397 return ERROR_INVALID_DATA;
400 res = RegSetValueExW(
401 currentKeyHandle,
402 val_name,
403 0, /* Reserved */
404 dwDataType,
405 lpbData,
406 dwLen);
407 if (dwParseType == REG_BINARY)
408 HeapFree(GetProcessHeap(), 0, lpbData);
409 return res;
412 /******************************************************************************
413 * A helper function for processRegEntry() that opens the current key.
414 * That key must be closed by calling closeKey().
416 static LONG openKeyW(WCHAR* stdInput)
418 HKEY keyClass;
419 WCHAR* keyPath;
420 DWORD dwDisp;
421 LONG res;
423 /* Sanity checks */
424 if (stdInput == NULL)
425 return ERROR_INVALID_PARAMETER;
427 /* Get the registry class */
428 if (!parseKeyNameW(stdInput, &keyClass, &keyPath))
429 return ERROR_INVALID_PARAMETER;
431 res = RegCreateKeyExW(
432 keyClass, /* Class */
433 keyPath, /* Sub Key */
434 0, /* MUST BE 0 */
435 NULL, /* object type */
436 REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */
437 KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */
438 NULL, /* security attribute */
439 &currentKeyHandle, /* result */
440 &dwDisp); /* disposition, REG_CREATED_NEW_KEY or
441 REG_OPENED_EXISTING_KEY */
443 if (res == ERROR_SUCCESS)
444 currentKeyName = GetMultiByteString(stdInput);
445 else
446 currentKeyHandle = NULL;
448 return res;
452 /******************************************************************************
453 * Close the currently opened key.
455 static void closeKey(void)
457 if (currentKeyHandle)
459 HeapFree(GetProcessHeap(), 0, currentKeyName);
460 RegCloseKey(currentKeyHandle);
461 currentKeyHandle = NULL;
465 /******************************************************************************
466 * This function is a wrapper for the setValue function. It prepares the
467 * land and cleans the area once completed.
468 * Note: this function modifies the line parameter.
470 * line - registry file unwrapped line. Should have the registry value name and
471 * complete registry value data.
473 static void processSetValue(WCHAR* line)
475 WCHAR* val_name; /* registry value name */
476 WCHAR* val_data; /* registry value data */
477 int line_idx = 0; /* current character under analysis */
478 LONG res;
480 /* get value name */
481 if (line[line_idx] == '@' && line[line_idx + 1] == '=') {
482 line[line_idx] = '\0';
483 val_name = line;
484 line_idx++;
485 } else if (line[line_idx] == '\"') {
486 line_idx++;
487 val_name = line + line_idx;
488 while (TRUE) {
489 if (line[line_idx] == '\\') /* skip escaped character */
491 line_idx += 2;
492 } else {
493 if (line[line_idx] == '\"') {
494 line[line_idx] = '\0';
495 line_idx++;
496 break;
497 } else {
498 line_idx++;
502 if (line[line_idx] != '=') {
503 char* lineA;
504 line[line_idx] = '\"';
505 lineA = GetMultiByteString(line);
506 fprintf(stderr,"Warning! unrecognized line:\n%s\n", lineA);
507 HeapFree(GetProcessHeap(), 0, lineA);
508 return;
511 } else {
512 char* lineA = GetMultiByteString(line);
513 fprintf(stderr,"Warning! unrecognized line:\n%s\n", lineA);
514 HeapFree(GetProcessHeap(), 0, lineA);
515 return;
517 line_idx++; /* skip the '=' character */
518 val_data = line + line_idx;
520 REGPROC_unescape_string(val_name);
521 res = setValue(val_name, val_data);
522 if ( res != ERROR_SUCCESS )
524 char* val_nameA = GetMultiByteString(val_name);
525 char* val_dataA = GetMultiByteString(val_data);
526 fprintf(stderr,"%s: ERROR Key %s not created. Value: %s, Data: %s\n",
527 getAppName(),
528 currentKeyName,
529 val_nameA,
530 val_dataA);
531 HeapFree(GetProcessHeap(), 0, val_nameA);
532 HeapFree(GetProcessHeap(), 0, val_dataA);
536 /******************************************************************************
537 * This function receives the currently read entry and performs the
538 * corresponding action.
540 static void processRegEntry(WCHAR* stdInput)
543 * We encountered the end of the file, make sure we
544 * close the opened key and exit
546 if (stdInput == NULL) {
547 closeKey();
548 return;
551 if ( stdInput[0] == '[') /* We are reading a new key */
553 WCHAR* keyEnd;
554 closeKey(); /* Close the previous key */
556 /* Get rid of the square brackets */
557 stdInput++;
558 keyEnd = strrchrW(stdInput, ']');
559 if (keyEnd)
560 *keyEnd='\0';
562 /* delete the key if we encounter '-' at the start of reg key */
563 if ( stdInput[0] == '-')
565 delete_registry_key(stdInput + 1);
566 } else if ( openKeyW(stdInput) != ERROR_SUCCESS )
568 fprintf(stderr,"%s: setValue failed to open key %s\n",
569 getAppName(), stdInput);
571 } else if( currentKeyHandle &&
572 (( stdInput[0] == '@') || /* reading a default @=data pair */
573 ( stdInput[0] == '\"'))) /* reading a new value=data pair */
575 processSetValue(stdInput);
576 } else
578 /* Since we are assuming that the file format is valid we must be
579 * reading a blank line which indicates the end of this key processing
581 closeKey();
585 /******************************************************************************
586 * Processes a registry file.
587 * Correctly processes comments (in # form), line continuation.
589 * Parameters:
590 * in - input stream to read from
592 void processRegLinesA(FILE *in)
594 LPSTR line = NULL; /* line read from input stream */
595 ULONG lineSize = REG_VAL_BUF_SIZE;
597 line = HeapAlloc(GetProcessHeap(), 0, lineSize);
598 CHECK_ENOUGH_MEMORY(line);
600 while (!feof(in)) {
601 LPSTR s; /* The pointer into line for where the current fgets should read */
602 LPSTR check;
603 WCHAR* lineW;
604 s = line;
605 for (;;) {
606 size_t size_remaining;
607 int size_to_get;
608 char *s_eol; /* various local uses */
610 /* Do we need to expand the buffer ? */
611 assert (s >= line && s <= line + lineSize);
612 size_remaining = lineSize - (s-line);
613 if (size_remaining < 2) /* room for 1 character and the \0 */
615 char *new_buffer;
616 size_t new_size = lineSize + REG_VAL_BUF_SIZE;
617 if (new_size > lineSize) /* no arithmetic overflow */
618 new_buffer = HeapReAlloc (GetProcessHeap(), 0, line, new_size);
619 else
620 new_buffer = NULL;
621 CHECK_ENOUGH_MEMORY(new_buffer);
622 line = new_buffer;
623 s = line + lineSize - size_remaining;
624 lineSize = new_size;
625 size_remaining = lineSize - (s-line);
628 /* Get as much as possible into the buffer, terminated either by
629 * eof, error, eol or getting the maximum amount. Abort on error.
631 size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
633 check = fgets (s, size_to_get, in);
635 if (check == NULL) {
636 if (ferror(in)) {
637 perror ("While reading input");
638 exit (IO_ERROR);
639 } else {
640 assert (feof(in));
641 *s = '\0';
642 /* It is not clear to me from the definition that the
643 * contents of the buffer are well defined on detecting
644 * an eof without managing to read anything.
649 /* If we didn't read the eol nor the eof go around for the rest */
650 s_eol = strchr (s, '\n');
651 if (!feof (in) && !s_eol) {
652 s = strchr (s, '\0');
653 /* It should be s + size_to_get - 1 but this is safer */
654 continue;
657 /* If it is a comment line then discard it and go around again */
658 if (line [0] == '#') {
659 s = line;
660 continue;
663 /* Remove any line feed. Leave s_eol on the \0 */
664 if (s_eol) {
665 *s_eol = '\0';
666 if (s_eol > line && *(s_eol-1) == '\r')
667 *--s_eol = '\0';
668 } else
669 s_eol = strchr (s, '\0');
671 /* If there is a concatenating \\ then go around again */
672 if (s_eol > line && *(s_eol-1) == '\\') {
673 int c;
674 s = s_eol-1;
678 c = fgetc(in);
679 } while(c == ' ' || c == '\t');
681 if(c == EOF)
683 fprintf(stderr,"%s: ERROR - invalid continuation.\n",
684 getAppName());
686 else
688 *s = c;
689 s++;
691 continue;
694 lineW = GetWideString(line);
696 break; /* That is the full virtual line */
699 processRegEntry(lineW);
700 HeapFree(GetProcessHeap(), 0, lineW);
702 processRegEntry(NULL);
704 HeapFree(GetProcessHeap(), 0, line);
707 void processRegLinesW(FILE *in)
709 WCHAR* buf = NULL; /* line read from input stream */
710 ULONG lineSize = REG_VAL_BUF_SIZE;
711 size_t CharsInBuf = -1;
713 WCHAR* s; /* The pointer into line for where the current fgets should read */
715 buf = HeapAlloc(GetProcessHeap(), 0, lineSize * sizeof(WCHAR));
716 CHECK_ENOUGH_MEMORY(buf);
718 s = buf;
720 while(!feof(in)) {
721 size_t size_remaining;
722 int size_to_get;
723 WCHAR *s_eol = NULL; /* various local uses */
725 /* Do we need to expand the buffer ? */
726 assert (s >= buf && s <= buf + lineSize);
727 size_remaining = lineSize - (s-buf);
728 if (size_remaining < 2) /* room for 1 character and the \0 */
730 WCHAR *new_buffer;
731 size_t new_size = lineSize + (REG_VAL_BUF_SIZE / sizeof(WCHAR));
732 if (new_size > lineSize) /* no arithmetic overflow */
733 new_buffer = HeapReAlloc (GetProcessHeap(), 0, buf, new_size * sizeof(WCHAR));
734 else
735 new_buffer = NULL;
736 CHECK_ENOUGH_MEMORY(new_buffer);
737 buf = new_buffer;
738 s = buf + lineSize - size_remaining;
739 lineSize = new_size;
740 size_remaining = lineSize - (s-buf);
743 /* Get as much as possible into the buffer, terminated either by
744 * eof, error or getting the maximum amount. Abort on error.
746 size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
748 CharsInBuf = fread(s, sizeof(WCHAR), size_to_get - 1, in);
749 s[CharsInBuf] = 0;
751 if (CharsInBuf == 0) {
752 if (ferror(in)) {
753 perror ("While reading input");
754 exit (IO_ERROR);
755 } else {
756 assert (feof(in));
757 *s = '\0';
758 /* It is not clear to me from the definition that the
759 * contents of the buffer are well defined on detecting
760 * an eof without managing to read anything.
765 /* If we didn't read the eol nor the eof go around for the rest */
766 while(1)
768 s_eol = strchrW(s, '\n');
770 if(!s_eol)
771 break;
773 /* If it is a comment line then discard it and go around again */
774 if (*s == '#') {
775 s = s_eol + 1;
776 continue;
779 /* If there is a concatenating \\ then go around again */
780 if ((*(s_eol-1) == '\\') ||
781 (*(s_eol-1) == '\r' && *(s_eol-2) == '\\')) {
782 WCHAR* NextLine = s_eol;
784 while(*(NextLine+1) == ' ' || *(NextLine+1) == '\t')
785 NextLine++;
787 NextLine++;
789 if(*(s_eol-1) == '\r')
790 s_eol--;
792 MoveMemory(s_eol - 1, NextLine, (CharsInBuf - (NextLine - buf) + 1)*sizeof(WCHAR));
793 CharsInBuf -= NextLine - s_eol + 1;
794 s_eol = 0;
795 continue;
798 /* Remove any line feed. Leave s_eol on the \0 */
799 if (s_eol) {
800 *s_eol = '\0';
801 if (s_eol > buf && *(s_eol-1) == '\r')
802 *(s_eol-1) = '\0';
805 if(!s_eol)
806 break;
808 processRegEntry(s);
809 s = s_eol + 1;
810 s_eol = 0;
811 continue; /* That is the full virtual line */
815 processRegEntry(NULL);
817 HeapFree(GetProcessHeap(), 0, buf);
820 /****************************************************************************
821 * REGPROC_print_error
823 * Print the message for GetLastError
826 static void REGPROC_print_error(void)
828 LPVOID lpMsgBuf;
829 DWORD error_code;
830 int status;
832 error_code = GetLastError ();
833 status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
834 NULL, error_code, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
835 if (!status) {
836 fprintf(stderr,"%s: Cannot display message for error %d, status %d\n",
837 getAppName(), error_code, GetLastError());
838 exit(1);
840 puts(lpMsgBuf);
841 LocalFree((HLOCAL)lpMsgBuf);
842 exit(1);
845 /******************************************************************************
846 * Checks whether the buffer has enough room for the string or required size.
847 * Resizes the buffer if necessary.
849 * Parameters:
850 * buffer - pointer to a buffer for string
851 * len - current length of the buffer in characters.
852 * required_len - length of the string to place to the buffer in characters.
853 * The length does not include the terminating null character.
855 static void REGPROC_resize_char_buffer(CHAR **buffer, DWORD *len, DWORD required_len)
857 required_len++;
858 if (required_len > *len) {
859 *len = required_len;
860 if (!*buffer)
861 *buffer = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(**buffer));
862 else
863 *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *len * sizeof(**buffer));
864 CHECK_ENOUGH_MEMORY(*buffer);
868 /******************************************************************************
869 * Prints string str to file
871 static void REGPROC_export_string(FILE *file, CHAR *str)
873 size_t len = strlen(str);
874 size_t i;
876 /* escaping characters */
877 for (i = 0; i < len; i++) {
878 CHAR c = str[i];
879 switch (c) {
880 case '\\':
881 fputs("\\\\", file);
882 break;
883 case '\"':
884 fputs("\\\"", file);
885 break;
886 case '\n':
887 fputs("\\\n", file);
888 break;
889 default:
890 fputc(c, file);
891 break;
896 /******************************************************************************
897 * Writes contents of the registry key to the specified file stream.
899 * Parameters:
900 * file - writable file stream to export registry branch to.
901 * key - registry branch to export.
902 * reg_key_name_buf - name of the key with registry class.
903 * Is resized if necessary.
904 * reg_key_name_len - length of the buffer for the registry class in characters.
905 * val_name_buf - buffer for storing value name.
906 * Is resized if necessary.
907 * val_name_len - length of the buffer for storing value names in characters.
908 * val_buf - buffer for storing values while extracting.
909 * Is resized if necessary.
910 * val_size - size of the buffer for storing values in bytes.
912 static void export_hkey(FILE *file, HKEY key,
913 CHAR **reg_key_name_buf, DWORD *reg_key_name_len,
914 CHAR **val_name_buf, DWORD *val_name_len,
915 BYTE **val_buf, DWORD *val_size)
917 DWORD max_sub_key_len;
918 DWORD max_val_name_len;
919 DWORD max_val_size;
920 DWORD curr_len;
921 DWORD i;
922 BOOL more_data;
923 LONG ret;
925 /* get size information and resize the buffers if necessary */
926 if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL,
927 &max_sub_key_len, NULL,
928 NULL, &max_val_name_len, &max_val_size, NULL, NULL
929 ) != ERROR_SUCCESS) {
930 REGPROC_print_error();
932 curr_len = strlen(*reg_key_name_buf);
933 REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_len,
934 max_sub_key_len + curr_len + 1);
935 REGPROC_resize_char_buffer(val_name_buf, val_name_len,
936 max_val_name_len);
937 if (max_val_size > *val_size) {
938 *val_size = max_val_size;
939 if (!*val_buf) *val_buf = HeapAlloc(GetProcessHeap(), 0, *val_size);
940 else *val_buf = HeapReAlloc(GetProcessHeap(), 0, *val_buf, *val_size);
941 CHECK_ENOUGH_MEMORY(val_buf);
944 /* output data for the current key */
945 fputs("\n[", file);
946 fputs(*reg_key_name_buf, file);
947 fputs("]\n", file);
948 /* print all the values */
949 i = 0;
950 more_data = TRUE;
951 while(more_data) {
952 DWORD value_type;
953 DWORD val_name_len1 = *val_name_len;
954 DWORD val_size1 = *val_size;
955 ret = RegEnumValue(key, i, *val_name_buf, &val_name_len1, NULL,
956 &value_type, *val_buf, &val_size1);
957 if (ret != ERROR_SUCCESS) {
958 more_data = FALSE;
959 if (ret != ERROR_NO_MORE_ITEMS) {
960 REGPROC_print_error();
962 } else {
963 i++;
965 if ((*val_name_buf)[0]) {
966 fputs("\"", file);
967 REGPROC_export_string(file, *val_name_buf);
968 fputs("\"=", file);
969 } else {
970 fputs("@=", file);
973 switch (value_type) {
974 case REG_SZ:
975 case REG_EXPAND_SZ:
976 fputs("\"", file);
977 if (val_size1) REGPROC_export_string(file, (char*) *val_buf);
978 fputs("\"\n", file);
979 break;
981 case REG_DWORD:
982 fprintf(file, "dword:%08x\n", *((DWORD *)*val_buf));
983 break;
985 default:
986 fprintf(stderr,"%s: warning - unsupported registry format '%d', "
987 "treat as binary\n",
988 getAppName(), value_type);
989 fprintf(stderr,"key name: \"%s\"\n", *reg_key_name_buf);
990 fprintf(stderr,"value name:\"%s\"\n\n", *val_name_buf);
991 /* falls through */
992 case REG_MULTI_SZ:
993 /* falls through */
994 case REG_BINARY: {
995 DWORD i1;
996 const CHAR *hex_prefix;
997 CHAR buf[20];
998 int cur_pos;
1000 if (value_type == REG_BINARY) {
1001 hex_prefix = "hex:";
1002 } else {
1003 hex_prefix = buf;
1004 sprintf(buf, "hex(%d):", value_type);
1007 /* position of where the next character will be printed */
1008 /* NOTE: yes, strlen("hex:") is used even for hex(x): */
1009 cur_pos = strlen("\"\"=") + strlen("hex:") +
1010 strlen(*val_name_buf);
1012 fputs(hex_prefix, file);
1013 for (i1 = 0; i1 < val_size1; i1++) {
1014 fprintf(file, "%02x", (unsigned int)(*val_buf)[i1]);
1015 if (i1 + 1 < val_size1) {
1016 fputs(",", file);
1018 cur_pos += 3;
1020 /* wrap the line */
1021 if (cur_pos > REG_FILE_HEX_LINE_LEN) {
1022 fputs("\\\n ", file);
1023 cur_pos = 2;
1026 fputs("\n", file);
1027 break;
1033 i = 0;
1034 more_data = TRUE;
1035 (*reg_key_name_buf)[curr_len] = '\\';
1036 while(more_data) {
1037 DWORD buf_len = *reg_key_name_len - curr_len;
1039 ret = RegEnumKeyEx(key, i, *reg_key_name_buf + curr_len + 1, &buf_len,
1040 NULL, NULL, NULL, NULL);
1041 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1042 more_data = FALSE;
1043 if (ret != ERROR_NO_MORE_ITEMS) {
1044 REGPROC_print_error();
1046 } else {
1047 HKEY subkey;
1049 i++;
1050 if (RegOpenKey(key, *reg_key_name_buf + curr_len + 1,
1051 &subkey) == ERROR_SUCCESS) {
1052 export_hkey(file, subkey, reg_key_name_buf, reg_key_name_len,
1053 val_name_buf, val_name_len, val_buf, val_size);
1054 RegCloseKey(subkey);
1055 } else {
1056 REGPROC_print_error();
1060 (*reg_key_name_buf)[curr_len] = '\0';
1063 /******************************************************************************
1064 * Open file for export.
1066 static FILE *REGPROC_open_export_file(CHAR *file_name)
1068 FILE *file;
1070 if (strcmp(file_name,"-")==0)
1071 file=stdout;
1072 else
1074 file = fopen(file_name, "w");
1075 if (!file) {
1076 perror("");
1077 fprintf(stderr,"%s: Can't open file \"%s\"\n", getAppName(), file_name);
1078 exit(1);
1081 fputs("REGEDIT4\n", file);
1082 return file;
1085 /******************************************************************************
1086 * Writes contents of the registry key to the specified file stream.
1088 * Parameters:
1089 * file_name - name of a file to export registry branch to.
1090 * reg_key_name - registry branch to export. The whole registry is exported if
1091 * reg_key_name is NULL or contains an empty string.
1093 BOOL export_registry_key(CHAR *file_name, CHAR *reg_key_name)
1095 CHAR *reg_key_name_buf;
1096 CHAR *val_name_buf;
1097 BYTE *val_buf;
1098 DWORD reg_key_name_len = KEY_MAX_LEN;
1099 DWORD val_name_len = KEY_MAX_LEN;
1100 DWORD val_size = REG_VAL_BUF_SIZE;
1101 FILE *file = NULL;
1103 reg_key_name_buf = HeapAlloc(GetProcessHeap(), 0,
1104 reg_key_name_len * sizeof(*reg_key_name_buf));
1105 val_name_buf = HeapAlloc(GetProcessHeap(), 0,
1106 val_name_len * sizeof(*val_name_buf));
1107 val_buf = HeapAlloc(GetProcessHeap(), 0, val_size);
1108 CHECK_ENOUGH_MEMORY(reg_key_name_buf && val_name_buf && val_buf);
1110 if (reg_key_name && reg_key_name[0]) {
1111 HKEY reg_key_class;
1112 CHAR *branch_name = NULL;
1113 HKEY key;
1115 REGPROC_resize_char_buffer(&reg_key_name_buf, &reg_key_name_len,
1116 strlen(reg_key_name));
1117 strcpy(reg_key_name_buf, reg_key_name);
1119 /* open the specified key */
1120 if (!parseKeyName(reg_key_name, &reg_key_class, &branch_name)) {
1121 fprintf(stderr,"%s: Incorrect registry class specification in '%s'\n",
1122 getAppName(), reg_key_name);
1123 exit(1);
1125 if (!branch_name[0]) {
1126 /* no branch - registry class is specified */
1127 file = REGPROC_open_export_file(file_name);
1128 export_hkey(file, reg_key_class,
1129 &reg_key_name_buf, &reg_key_name_len,
1130 &val_name_buf, &val_name_len,
1131 &val_buf, &val_size);
1132 } else if (RegOpenKey(reg_key_class, branch_name, &key) == ERROR_SUCCESS) {
1133 file = REGPROC_open_export_file(file_name);
1134 export_hkey(file, key,
1135 &reg_key_name_buf, &reg_key_name_len,
1136 &val_name_buf, &val_name_len,
1137 &val_buf, &val_size);
1138 RegCloseKey(key);
1139 } else {
1140 fprintf(stderr,"%s: Can't export. Registry key '%s' does not exist!\n",
1141 getAppName(), reg_key_name);
1142 REGPROC_print_error();
1144 } else {
1145 unsigned int i;
1147 /* export all registry classes */
1148 file = REGPROC_open_export_file(file_name);
1149 for (i = 0; i < REG_CLASS_NUMBER; i++) {
1150 /* do not export HKEY_CLASSES_ROOT */
1151 if (reg_class_keys[i] != HKEY_CLASSES_ROOT &&
1152 reg_class_keys[i] != HKEY_CURRENT_USER &&
1153 reg_class_keys[i] != HKEY_CURRENT_CONFIG &&
1154 reg_class_keys[i] != HKEY_DYN_DATA) {
1155 strcpy(reg_key_name_buf, reg_class_names[i]);
1156 export_hkey(file, reg_class_keys[i],
1157 &reg_key_name_buf, &reg_key_name_len,
1158 &val_name_buf, &val_name_len,
1159 &val_buf, &val_size);
1164 if (file) {
1165 fclose(file);
1167 HeapFree(GetProcessHeap(), 0, reg_key_name);
1168 HeapFree(GetProcessHeap(), 0, val_name_buf);
1169 HeapFree(GetProcessHeap(), 0, val_buf);
1170 return TRUE;
1173 /******************************************************************************
1174 * Reads contents of the specified file into the registry.
1176 BOOL import_registry_file(FILE* reg_file)
1178 if (reg_file)
1180 BYTE s[2];
1181 if (fread( s, 2, 1, reg_file) == 1)
1183 if (s[0] == 0xff && s[1] == 0xfe)
1185 processRegLinesW(reg_file);
1186 } else
1188 rewind(reg_file);
1189 processRegLinesA(reg_file);
1192 return TRUE;
1194 return FALSE;
1197 /******************************************************************************
1198 * Removes the registry key with all subkeys. Parses full key name.
1200 * Parameters:
1201 * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
1202 * empty, points to register key class, does not exist.
1204 void delete_registry_key(WCHAR *reg_key_name)
1206 WCHAR *key_name = NULL;
1207 HKEY key_class;
1209 if (!reg_key_name || !reg_key_name[0])
1210 return;
1212 if (!parseKeyNameW(reg_key_name, &key_class, &key_name)) {
1213 char* reg_key_nameA = GetMultiByteString(reg_key_name);
1214 fprintf(stderr,"%s: Incorrect registry class specification in '%s'\n",
1215 getAppName(), reg_key_nameA);
1216 HeapFree(GetProcessHeap(), 0, reg_key_nameA);
1217 exit(1);
1219 if (!*key_name) {
1220 char* reg_key_nameA = GetMultiByteString(reg_key_name);
1221 fprintf(stderr,"%s: Can't delete registry class '%s'\n",
1222 getAppName(), reg_key_nameA);
1223 HeapFree(GetProcessHeap(), 0, reg_key_nameA);
1224 exit(1);
1227 RegDeleteTreeW(key_class, key_name);