Sync with trunk r62529.
[reactos.git] / base / applications / regedit / regproc.c
1 /*
2 * Registry processing routines. Routines, common for registry
3 * processing frontends.
4 *
5 * Copyright (C) 1999 Sylvain St-Germain
6 * Copyright (C) 2002 Andriy Palamarchuk
7 * Copyright (C) 2008 Alexander N. Sørnes <alex@thehandofagony.com>
8 *
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.
13 *
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.
18 *
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
22 */
23
24 #include "regedit.h"
25
26 #include <assert.h>
27
28 #define REG_VAL_BUF_SIZE 4096
29
30 /* maximal number of characters in hexadecimal data line,
31 * including the indentation, but not including the '\' character
32 */
33 #define REG_FILE_HEX_LINE_LEN (2 + 25 * 3)
34
35 static const CHAR *reg_class_names[] =
36 {
37 "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CLASSES_ROOT",
38 "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA"
39 };
40
41 #define REG_CLASS_NUMBER (COUNT_OF(reg_class_names))
42
43 const WCHAR* reg_class_namesW[REG_CLASS_NUMBER] =
44 {
45 L"HKEY_LOCAL_MACHINE", L"HKEY_USERS", L"HKEY_CLASSES_ROOT",
46 L"HKEY_CURRENT_CONFIG", L"HKEY_CURRENT_USER", L"HKEY_DYN_DATA"
47 };
48
49 static HKEY reg_class_keys[REG_CLASS_NUMBER] =
50 {
51 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
52 HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA
53 };
54
55 /* return values */
56 #define NOT_ENOUGH_MEMORY 1
57 #define IO_ERROR 2
58
59 /* processing macros */
60
61 /* common check of memory allocation results */
62 #define CHECK_ENOUGH_MEMORY(p) \
63 if (!(p)) \
64 { \
65 fprintf(stderr,"%S: file %s, line %d: Not enough memory\n", \
66 getAppName(), __FILE__, __LINE__); \
67 exit(NOT_ENOUGH_MEMORY); \
68 }
69
70 /******************************************************************************
71 * Allocates memory and converts input from multibyte to wide chars
72 * Returned string must be freed by the caller
73 */
74 WCHAR* GetWideString(const char* strA)
75 {
76 if(strA)
77 {
78 WCHAR* strW;
79 int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0);
80
81 strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
82 CHECK_ENOUGH_MEMORY(strW);
83 MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len);
84 return strW;
85 }
86 return NULL;
87 }
88
89 /******************************************************************************
90 * Allocates memory and converts input from multibyte to wide chars
91 * Returned string must be freed by the caller
92 */
93 static WCHAR* GetWideStringN(const char* strA, int chars, DWORD *len)
94 {
95 if(strA)
96 {
97 WCHAR* strW;
98 *len = MultiByteToWideChar(CP_ACP, 0, strA, chars, NULL, 0);
99
100 strW = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(WCHAR));
101 CHECK_ENOUGH_MEMORY(strW);
102 MultiByteToWideChar(CP_ACP, 0, strA, chars, strW, *len);
103 return strW;
104 }
105 *len = 0;
106 return NULL;
107 }
108
109 /******************************************************************************
110 * Allocates memory and converts input from wide chars to multibyte
111 * Returned string must be freed by the caller
112 */
113 char* GetMultiByteString(const WCHAR* strW)
114 {
115 if(strW)
116 {
117 char* strA;
118 int len = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL);
119
120 strA = HeapAlloc(GetProcessHeap(), 0, len);
121 CHECK_ENOUGH_MEMORY(strA);
122 WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, len, NULL, NULL);
123 return strA;
124 }
125 return NULL;
126 }
127
128 /******************************************************************************
129 * Allocates memory and converts input from wide chars to multibyte
130 * Returned string must be freed by the caller
131 */
132 static char* GetMultiByteStringN(const WCHAR* strW, int chars, DWORD* len)
133 {
134 if(strW)
135 {
136 char* strA;
137 *len = WideCharToMultiByte(CP_ACP, 0, strW, chars, NULL, 0, NULL, NULL);
138
139 strA = HeapAlloc(GetProcessHeap(), 0, *len);
140 CHECK_ENOUGH_MEMORY(strA);
141 WideCharToMultiByte(CP_ACP, 0, strW, chars, strA, *len, NULL, NULL);
142 return strA;
143 }
144 *len = 0;
145 return NULL;
146 }
147
148 /******************************************************************************
149 * Converts a hex representation of a DWORD into a DWORD.
150 */
151 static BOOL convertHexToDWord(WCHAR* str, DWORD *dw)
152 {
153 char buf[9];
154 char dummy;
155
156 WideCharToMultiByte(CP_ACP, 0, str, -1, buf, 9, NULL, NULL);
157 if (lstrlenW(str) > 8 || sscanf(buf, "%lx%c", dw, &dummy) != 1)
158 {
159 fprintf(stderr,"%S: ERROR, invalid hex value\n", getAppName());
160 return FALSE;
161 }
162 return TRUE;
163 }
164
165 /******************************************************************************
166 * Converts a hex comma separated values list into a binary string.
167 */
168 static BYTE* convertHexCSVToHex(WCHAR *str, DWORD *size)
169 {
170 WCHAR *s;
171 BYTE *d, *data;
172
173 /* The worst case is 1 digit + 1 comma per byte */
174 *size=(lstrlenW(str)+1)/2;
175 data=HeapAlloc(GetProcessHeap(), 0, *size);
176 CHECK_ENOUGH_MEMORY(data);
177
178 s = str;
179 d = data;
180 *size=0;
181 while (*s != '\0')
182 {
183 UINT wc;
184 WCHAR *end;
185
186 wc = wcstoul(s,&end, 16);
187 if (end == s || wc > 0xff || (*end && *end != L','))
188 {
189 char* strA = GetMultiByteString(s);
190 fprintf(stderr,"%S: ERROR converting CSV hex stream. Invalid value at '%s'\n",
191 getAppName(), strA);
192 HeapFree(GetProcessHeap(), 0, data);
193 HeapFree(GetProcessHeap(), 0, strA);
194 return NULL;
195 }
196 *d++ =(BYTE)wc;
197 (*size)++;
198 if (*end) end++;
199 s = end;
200 }
201
202 return data;
203 }
204
205 /******************************************************************************
206 * This function returns the HKEY associated with the data type encoded in the
207 * value. It modifies the input parameter (key value) in order to skip this
208 * "now useless" data type information.
209 *
210 * Note: Updated based on the algorithm used in 'server/registry.c'
211 */
212 static DWORD getDataType(LPWSTR *lpValue, DWORD* parse_type)
213 {
214 struct data_type
215 {
216 const WCHAR *tag;
217 int len;
218 int type;
219 int parse_type;
220 };
221
222 static const WCHAR quote[] = {'"'};
223 static const WCHAR str[] = {'s','t','r',':','"'};
224 static const WCHAR str2[] = {'s','t','r','(','2',')',':','"'};
225 static const WCHAR hex[] = {'h','e','x',':'};
226 static const WCHAR dword[] = {'d','w','o','r','d',':'};
227 static const WCHAR hexp[] = {'h','e','x','('};
228
229 static const struct data_type data_types[] = { /* actual type */ /* type to assume for parsing */
230 { quote, 1, REG_SZ, REG_SZ },
231 { str, 5, REG_SZ, REG_SZ },
232 { str2, 8, REG_EXPAND_SZ, REG_SZ },
233 { hex, 4, REG_BINARY, REG_BINARY },
234 { dword, 6, REG_DWORD, REG_DWORD },
235 { hexp, 4, -1, REG_BINARY },
236 { NULL, 0, 0, 0 }
237 };
238
239 const struct data_type *ptr;
240 int type;
241
242 for (ptr = data_types; ptr->tag; ptr++)
243 {
244 if (wcsncmp(ptr->tag, *lpValue, ptr->len))
245 continue;
246
247 /* Found! */
248 *parse_type = ptr->parse_type;
249 type=ptr->type;
250 *lpValue+=ptr->len;
251 if (type == -1)
252 {
253 WCHAR* end;
254
255 /* "hex(xx):" is special */
256 type = (int)wcstoul( *lpValue , &end, 16 );
257 if (**lpValue=='\0' || *end!=')' || *(end+1)!=':')
258 {
259 type=REG_NONE;
260 }
261 else
262 {
263 *lpValue = end + 2;
264 }
265 }
266 return type;
267 }
268 *parse_type=REG_NONE;
269 return REG_NONE;
270 }
271
272 /******************************************************************************
273 * Replaces escape sequences with the characters.
274 */
275 static void REGPROC_unescape_string(WCHAR* str)
276 {
277 int str_idx = 0; /* current character under analysis */
278 int val_idx = 0; /* the last character of the unescaped string */
279 int len = lstrlenW(str);
280 for (str_idx = 0; str_idx < len; str_idx++, val_idx++)
281 {
282 if (str[str_idx] == '\\')
283 {
284 str_idx++;
285 switch (str[str_idx])
286 {
287 case 'n':
288 str[val_idx] = '\n';
289 break;
290 case '\\':
291 case '"':
292 str[val_idx] = str[str_idx];
293 break;
294 default:
295 fprintf(stderr,"Warning! Unrecognized escape sequence: \\%C'\n",
296 str[str_idx]);
297 str[val_idx] = str[str_idx];
298 break;
299 }
300 }
301 else
302 {
303 str[val_idx] = str[str_idx];
304 }
305 }
306 str[val_idx] = '\0';
307 }
308
309 static BOOL parseKeyName(LPWSTR lpKeyName, HKEY *hKey, LPWSTR *lpKeyPath)
310 {
311 WCHAR* lpSlash = NULL;
312 unsigned int i, len;
313
314 if (lpKeyName == NULL)
315 return FALSE;
316
317 for(i = 0; *(lpKeyName + i) != 0; i++)
318 {
319 if(*(lpKeyName+i) == '\\')
320 {
321 lpSlash = lpKeyName + i;
322 break;
323 }
324 }
325
326 if (lpSlash)
327 {
328 len = lpSlash-lpKeyName;
329 }
330 else
331 {
332 len = lstrlenW(lpKeyName);
333 lpSlash = lpKeyName+len;
334 }
335 *hKey = NULL;
336
337 for (i = 0; i < REG_CLASS_NUMBER; i++)
338 {
339 if (CompareStringW(LOCALE_USER_DEFAULT, 0, lpKeyName, len, reg_class_namesW[i], len) == CSTR_EQUAL &&
340 len == lstrlenW(reg_class_namesW[i]))
341 {
342 *hKey = reg_class_keys[i];
343 break;
344 }
345 }
346
347 if (*hKey == NULL)
348 return FALSE;
349
350 if (*lpSlash != '\0')
351 lpSlash++;
352 *lpKeyPath = lpSlash;
353 return TRUE;
354 }
355
356 /* Globals used by the setValue() & co */
357 static LPSTR currentKeyName;
358 static HKEY currentKeyHandle = NULL;
359
360 /******************************************************************************
361 * Sets the value with name val_name to the data in val_data for the currently
362 * opened key.
363 *
364 * Parameters:
365 * val_name - name of the registry value
366 * val_data - registry value data
367 */
368 static LONG setValue(WCHAR* val_name, WCHAR* val_data, BOOL is_unicode)
369 {
370 LONG res;
371 DWORD dwDataType, dwParseType;
372 LPBYTE lpbData;
373 DWORD dwData, dwLen;
374 WCHAR del[] = {'-',0};
375
376 if ( (val_name == NULL) || (val_data == NULL) )
377 return ERROR_INVALID_PARAMETER;
378
379 if (lstrcmpW(val_data, del) == 0)
380 {
381 res=RegDeleteValueW(currentKeyHandle,val_name);
382 return (res == ERROR_FILE_NOT_FOUND ? ERROR_SUCCESS : res);
383 }
384
385 /* Get the data type stored into the value field */
386 dwDataType = getDataType(&val_data, &dwParseType);
387
388 if (dwParseType == REG_SZ) /* no conversion for string */
389 {
390 REGPROC_unescape_string(val_data);
391 /* Compute dwLen after REGPROC_unescape_string because it may
392 * have changed the string length and we don't want to store
393 * the extra garbage in the registry.
394 */
395 dwLen = lstrlenW(val_data);
396 if (dwLen>0 && val_data[dwLen-1]=='"')
397 {
398 dwLen--;
399 val_data[dwLen]='\0';
400 }
401 lpbData = (BYTE*) val_data;
402 dwLen++; /* include terminating null */
403 dwLen = dwLen * sizeof(WCHAR); /* size is in bytes */
404 }
405 else if (dwParseType == REG_DWORD) /* Convert the dword types */
406 {
407 if (!convertHexToDWord(val_data, &dwData))
408 return ERROR_INVALID_DATA;
409 lpbData = (BYTE*)&dwData;
410 dwLen = sizeof(dwData);
411 }
412 else if (dwParseType == REG_BINARY) /* Convert the binary data */
413 {
414 lpbData = convertHexCSVToHex(val_data, &dwLen);
415 if (!lpbData)
416 return ERROR_INVALID_DATA;
417
418 if((dwDataType == REG_MULTI_SZ || dwDataType == REG_EXPAND_SZ) && !is_unicode)
419 {
420 LPBYTE tmp = lpbData;
421 lpbData = (LPBYTE)GetWideStringN((char*)lpbData, dwLen, &dwLen);
422 dwLen *= sizeof(WCHAR);
423 HeapFree(GetProcessHeap(), 0, tmp);
424 }
425 }
426 else /* unknown format */
427 {
428 fprintf(stderr,"%S: ERROR, unknown data format\n", getAppName());
429 return ERROR_INVALID_DATA;
430 }
431
432 res = RegSetValueExW(
433 currentKeyHandle,
434 val_name,
435 0, /* Reserved */
436 dwDataType,
437 lpbData,
438 dwLen);
439 if (dwParseType == REG_BINARY)
440 HeapFree(GetProcessHeap(), 0, lpbData);
441 return res;
442 }
443
444 /******************************************************************************
445 * A helper function for processRegEntry() that opens the current key.
446 * That key must be closed by calling closeKey().
447 */
448 static LONG openKeyW(WCHAR* stdInput)
449 {
450 HKEY keyClass;
451 WCHAR* keyPath;
452 DWORD dwDisp;
453 LONG res;
454
455 /* Sanity checks */
456 if (stdInput == NULL)
457 return ERROR_INVALID_PARAMETER;
458
459 /* Get the registry class */
460 if (!parseKeyName(stdInput, &keyClass, &keyPath))
461 return ERROR_INVALID_PARAMETER;
462
463 res = RegCreateKeyExW(keyClass, /* Class */
464 keyPath, /* Sub Key */
465 0, /* MUST BE 0 */
466 NULL, /* object type */
467 REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */
468 KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */
469 NULL, /* security attribute */
470 &currentKeyHandle, /* result */
471 &dwDisp); /* disposition, REG_CREATED_NEW_KEY or
472 REG_OPENED_EXISTING_KEY */
473
474 if (res == ERROR_SUCCESS)
475 currentKeyName = GetMultiByteString(stdInput);
476 else
477 currentKeyHandle = NULL;
478
479 return res;
480
481 }
482
483 /******************************************************************************
484 * Close the currently opened key.
485 */
486 static void closeKey(void)
487 {
488 if (currentKeyHandle)
489 {
490 HeapFree(GetProcessHeap(), 0, currentKeyName);
491 RegCloseKey(currentKeyHandle);
492 currentKeyHandle = NULL;
493 }
494 }
495
496 /******************************************************************************
497 * This function is a wrapper for the setValue function. It prepares the
498 * land and cleans the area once completed.
499 * Note: this function modifies the line parameter.
500 *
501 * line - registry file unwrapped line. Should have the registry value name and
502 * complete registry value data.
503 */
504 static void processSetValue(WCHAR* line, BOOL is_unicode)
505 {
506 WCHAR* val_name; /* registry value name */
507 WCHAR* val_data; /* registry value data */
508 int line_idx = 0; /* current character under analysis */
509 LONG res;
510
511 /* get value name */
512 while ( iswspace(line[line_idx]) ) line_idx++;
513 if (line[line_idx] == '@' && line[line_idx + 1] == '=')
514 {
515 line[line_idx] = '\0';
516 val_name = line;
517 line_idx++;
518 }
519 else if (line[line_idx] == '\"')
520 {
521 line_idx++;
522 val_name = line + line_idx;
523 while (TRUE)
524 {
525 if (line[line_idx] == '\\') /* skip escaped character */
526 {
527 line_idx += 2;
528 }
529 else
530 {
531 if (line[line_idx] == '\"')
532 {
533 line[line_idx] = '\0';
534 line_idx++;
535 break;
536 }
537 else
538 {
539 line_idx++;
540 }
541 }
542 }
543 while ( iswspace(line[line_idx]) ) line_idx++;
544 if (line[line_idx] != '=')
545 {
546 char* lineA;
547 line[line_idx] = '\"';
548 lineA = GetMultiByteString(line);
549 fprintf(stderr,"Warning! unrecognized line:\n%s\n", lineA);
550 HeapFree(GetProcessHeap(), 0, lineA);
551 return;
552 }
553
554 }
555 else
556 {
557 char* lineA = GetMultiByteString(line);
558 fprintf(stderr,"Warning! unrecognized line:\n%s\n", lineA);
559 HeapFree(GetProcessHeap(), 0, lineA);
560 return;
561 }
562 line_idx++; /* skip the '=' character */
563
564 while ( iswspace(line[line_idx]) ) line_idx++;
565 val_data = line + line_idx;
566 /* trim trailing blanks */
567 line_idx = lstrlenW(val_data);
568 while (line_idx > 0 && iswspace(val_data[line_idx-1])) line_idx--;
569 val_data[line_idx] = '\0';
570
571 REGPROC_unescape_string(val_name);
572 res = setValue(val_name, val_data, is_unicode);
573 if ( res != ERROR_SUCCESS )
574 {
575 char* val_nameA = GetMultiByteString(val_name);
576 char* val_dataA = GetMultiByteString(val_data);
577 fprintf(stderr,"%S: ERROR Key %s not created. Value: %s, Data: %s\n",
578 getAppName(),
579 currentKeyName,
580 val_nameA,
581 val_dataA);
582 HeapFree(GetProcessHeap(), 0, val_nameA);
583 HeapFree(GetProcessHeap(), 0, val_dataA);
584 }
585 }
586
587 /******************************************************************************
588 * This function receives the currently read entry and performs the
589 * corresponding action.
590 * isUnicode affects parsing of REG_MULTI_SZ values
591 */
592 static void processRegEntry(WCHAR* stdInput, BOOL isUnicode)
593 {
594 /*
595 * We encountered the end of the file, make sure we
596 * close the opened key and exit
597 */
598 if (stdInput == NULL)
599 {
600 closeKey();
601 return;
602 }
603
604 if ( stdInput[0] == L'[') /* We are reading a new key */
605 {
606 WCHAR* keyEnd;
607 closeKey(); /* Close the previous key */
608
609 /* Get rid of the square brackets */
610 stdInput++;
611 keyEnd = wcsrchr(stdInput, L']');
612 if (keyEnd)
613 *keyEnd='\0';
614
615 /* delete the key if we encounter '-' at the start of reg key */
616 if ( stdInput[0] == '-')
617 {
618 delete_registry_key(stdInput + 1);
619 }
620 else if ( openKeyW(stdInput) != ERROR_SUCCESS )
621 {
622 char* stdInputA = GetMultiByteString(stdInput);
623 fprintf(stderr,"%S: setValue failed to open key %s\n",
624 getAppName(), stdInputA);
625 HeapFree(GetProcessHeap(), 0, stdInputA);
626 }
627 }
628 else if( currentKeyHandle &&
629 (( stdInput[0] == '@') || /* reading a default @=data pair */
630 ( stdInput[0] == '\"'))) /* reading a new value=data pair */
631 {
632 processSetValue(stdInput, isUnicode);
633 }
634 else
635 {
636 /* Since we are assuming that the file format is valid we must be
637 * reading a blank line which indicates the end of this key processing
638 */
639 closeKey();
640 }
641 }
642
643 /******************************************************************************
644 * Processes a registry file.
645 * Correctly processes comments (in # form), line continuation.
646 *
647 * Parameters:
648 * in - input stream to read from
649 */
650 static void processRegLinesA(FILE *in)
651 {
652 LPSTR line = NULL; /* line read from input stream */
653 ULONG lineSize = REG_VAL_BUF_SIZE;
654
655 line = HeapAlloc(GetProcessHeap(), 0, lineSize);
656 CHECK_ENOUGH_MEMORY(line);
657
658 while (!feof(in))
659 {
660 LPSTR s; /* The pointer into line for where the current fgets should read */
661 LPSTR check;
662 WCHAR* lineW;
663 s = line;
664
665 for (;;)
666 {
667 size_t size_remaining;
668 int size_to_get;
669 char *s_eol; /* various local uses */
670
671 /* Do we need to expand the buffer ? */
672 assert (s >= line && s <= line + lineSize);
673 size_remaining = lineSize - (s-line);
674 if (size_remaining < 2) /* room for 1 character and the \0 */
675 {
676 char *new_buffer;
677 size_t new_size = lineSize + REG_VAL_BUF_SIZE;
678 if (new_size > lineSize) /* no arithmetic overflow */
679 new_buffer = HeapReAlloc (GetProcessHeap(), 0, line, new_size);
680 else
681 new_buffer = NULL;
682 CHECK_ENOUGH_MEMORY(new_buffer);
683 line = new_buffer;
684 s = line + lineSize - size_remaining;
685 lineSize = new_size;
686 size_remaining = lineSize - (s-line);
687 }
688
689 /* Get as much as possible into the buffer, terminated either by
690 * eof, error, eol or getting the maximum amount. Abort on error.
691 */
692 size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
693
694 check = fgets (s, size_to_get, in);
695
696 if (check == NULL)
697 {
698 if (ferror(in))
699 {
700 perror ("While reading input");
701 exit (IO_ERROR);
702 }
703 else
704 {
705 assert (feof(in));
706 *s = '\0';
707 /* It is not clear to me from the definition that the
708 * contents of the buffer are well defined on detecting
709 * an eof without managing to read anything.
710 */
711 }
712 }
713
714 /* If we didn't read the eol nor the eof go around for the rest */
715 s_eol = strchr (s, '\n');
716 if (!feof (in) && !s_eol)
717 {
718 s = strchr (s, '\0');
719 /* It should be s + size_to_get - 1 but this is safer */
720 continue;
721 }
722
723 /* If it is a comment line then discard it and go around again */
724 if (line [0] == '#')
725 {
726 s = line;
727 continue;
728 }
729
730 /* Remove any line feed. Leave s_eol on the \0 */
731 if (s_eol)
732 {
733 *s_eol = '\0';
734 if (s_eol > line && *(s_eol-1) == '\r')
735 *--s_eol = '\0';
736 }
737 else
738 s_eol = strchr (s, '\0');
739
740 /* If there is a concatenating \\ then go around again */
741 if (s_eol > line && *(s_eol-1) == '\\')
742 {
743 int c;
744 s = s_eol-1;
745
746 do
747 {
748 c = fgetc(in);
749 }
750 while(c == ' ' || c == '\t');
751
752 if(c == EOF)
753 {
754 fprintf(stderr,"%S: ERROR - invalid continuation.\n",
755 getAppName());
756 }
757 else
758 {
759 *s = c;
760 s++;
761 }
762 continue;
763 }
764
765 lineW = GetWideString(line);
766
767 break; /* That is the full virtual line */
768 }
769
770 processRegEntry(lineW, FALSE);
771 HeapFree(GetProcessHeap(), 0, lineW);
772 }
773 processRegEntry(NULL, FALSE);
774
775 HeapFree(GetProcessHeap(), 0, line);
776 }
777
778 static void processRegLinesW(FILE *in)
779 {
780 WCHAR* buf = NULL; /* line read from input stream */
781 ULONG lineSize = REG_VAL_BUF_SIZE;
782 size_t CharsInBuf = -1;
783
784 WCHAR* s; /* The pointer into buf for where the current fgets should read */
785 WCHAR* line; /* The start of the current line */
786
787 buf = HeapAlloc(GetProcessHeap(), 0, lineSize * sizeof(WCHAR));
788 CHECK_ENOUGH_MEMORY(buf);
789
790 s = buf;
791 line = buf;
792
793 while(!feof(in))
794 {
795 size_t size_remaining;
796 int size_to_get;
797 WCHAR *s_eol = NULL; /* various local uses */
798
799 /* Do we need to expand the buffer ? */
800 assert (s >= buf && s <= buf + lineSize);
801 size_remaining = lineSize - (s-buf);
802 if (size_remaining < 2) /* room for 1 character and the \0 */
803 {
804 WCHAR *new_buffer;
805 size_t new_size = lineSize + (REG_VAL_BUF_SIZE / sizeof(WCHAR));
806 if (new_size > lineSize) /* no arithmetic overflow */
807 new_buffer = HeapReAlloc (GetProcessHeap(), 0, buf, new_size * sizeof(WCHAR));
808 else
809 new_buffer = NULL;
810 CHECK_ENOUGH_MEMORY(new_buffer);
811 buf = new_buffer;
812 line = buf;
813 s = buf + lineSize - size_remaining;
814 lineSize = new_size;
815 size_remaining = lineSize - (s-buf);
816 }
817
818 /* Get as much as possible into the buffer, terminated either by
819 * eof, error or getting the maximum amount. Abort on error.
820 */
821 size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
822
823 CharsInBuf = fread(s, sizeof(WCHAR), size_to_get - 1, in);
824 s[CharsInBuf] = 0;
825
826 if (CharsInBuf == 0)
827 {
828 if (ferror(in))
829 {
830 perror ("While reading input");
831 exit (IO_ERROR);
832 }
833 else
834 {
835 assert (feof(in));
836 *s = '\0';
837 /* It is not clear to me from the definition that the
838 * contents of the buffer are well defined on detecting
839 * an eof without managing to read anything.
840 */
841 }
842 }
843
844 /* If we didn't read the eol nor the eof go around for the rest */
845 while(1)
846 {
847 s_eol = wcschr(line, '\n');
848
849 if(!s_eol)
850 {
851 /* Move the stub of the line to the start of the buffer so
852 * we get the maximum space to read into, and so we don't
853 * have to recalculate 'line' if the buffer expands */
854 MoveMemory(buf, line, (lstrlenW(line) + 1) * sizeof(WCHAR));
855 line = buf;
856 s = wcschr(line, '\0');
857 break;
858 }
859
860 /* If it is a comment line then discard it and go around again */
861 if (*line == '#')
862 {
863 line = s_eol + 1;
864 continue;
865 }
866
867 /* If there is a concatenating \\ then go around again */
868 if ((*(s_eol-1) == '\\') ||
869 (*(s_eol-1) == '\r' && *(s_eol-2) == '\\'))
870 {
871 WCHAR* NextLine = s_eol;
872
873 while(*(NextLine+1) == ' ' || *(NextLine+1) == '\t')
874 NextLine++;
875
876 NextLine++;
877
878 if(*(s_eol-1) == '\r')
879 s_eol--;
880
881 MoveMemory(s_eol - 1, NextLine, (CharsInBuf - (NextLine - s) + 1)*sizeof(WCHAR));
882 CharsInBuf -= NextLine - s_eol + 1;
883 s_eol = 0;
884 continue;
885 }
886
887 /* Remove any line feed. Leave s_eol on the \0 */
888 if (s_eol)
889 {
890 *s_eol = '\0';
891 if (s_eol > buf && *(s_eol-1) == '\r')
892 *(s_eol-1) = '\0';
893 }
894
895 if(!s_eol)
896 break;
897
898 processRegEntry(line, TRUE);
899 line = s_eol + 1;
900 s_eol = 0;
901 continue; /* That is the full virtual line */
902 }
903 }
904
905 processRegEntry(NULL, TRUE);
906
907 HeapFree(GetProcessHeap(), 0, buf);
908 }
909
910 /****************************************************************************
911 * REGPROC_print_error
912 *
913 * Print the message for GetLastError
914 */
915
916 static void REGPROC_print_error(void)
917 {
918 LPVOID lpMsgBuf;
919 DWORD error_code;
920 int status;
921
922 error_code = GetLastError ();
923 status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
924 NULL, error_code, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
925 if (!status)
926 {
927 fprintf(stderr,"%S: Cannot display message for error %ld, status %ld\n",
928 getAppName(), error_code, GetLastError());
929 exit(1);
930 }
931 puts(lpMsgBuf);
932 LocalFree(lpMsgBuf);
933 exit(1);
934 }
935
936 /******************************************************************************
937 * Checks whether the buffer has enough room for the string or required size.
938 * Resizes the buffer if necessary.
939 *
940 * Parameters:
941 * buffer - pointer to a buffer for string
942 * len - current length of the buffer in characters.
943 * required_len - length of the string to place to the buffer in characters.
944 * The length does not include the terminating null character.
945 */
946 static void REGPROC_resize_char_buffer(WCHAR **buffer, DWORD *len, DWORD required_len)
947 {
948 required_len++;
949 if (required_len > *len)
950 {
951 *len = required_len;
952 if (!*buffer)
953 *buffer = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(**buffer));
954 else
955 *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *len * sizeof(**buffer));
956 CHECK_ENOUGH_MEMORY(*buffer);
957 }
958 }
959
960 /******************************************************************************
961 * Same as REGPROC_resize_char_buffer() but on a regular buffer.
962 *
963 * Parameters:
964 * buffer - pointer to a buffer
965 * len - current size of the buffer in bytes
966 * required_size - size of the data to place in the buffer in bytes
967 */
968 static void REGPROC_resize_binary_buffer(BYTE **buffer, DWORD *size, DWORD required_size)
969 {
970 if (required_size > *size)
971 {
972 *size = required_size;
973 if (!*buffer)
974 *buffer = HeapAlloc(GetProcessHeap(), 0, *size);
975 else
976 *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *size);
977 CHECK_ENOUGH_MEMORY(*buffer);
978 }
979 }
980
981 /******************************************************************************
982 * Prints string str to file
983 */
984 static void REGPROC_export_string(WCHAR **line_buf, DWORD *line_buf_size, DWORD *line_len, WCHAR *str, DWORD str_len)
985 {
986 DWORD i, pos;
987 DWORD extra = 0;
988
989 REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + 10);
990
991 /* escaping characters */
992 pos = *line_len;
993 for (i = 0; i < str_len; i++)
994 {
995 WCHAR c = str[i];
996 switch (c)
997 {
998 case '\n':
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++] = 'n';
1003 break;
1004
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 */
1011
1012 default:
1013 (*line_buf)[pos++] = c;
1014 break;
1015 }
1016 }
1017 (*line_buf)[pos] = '\0';
1018 *line_len = pos;
1019 }
1020
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)
1022 {
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[] = {'\\','\n',' ',' ',0};
1028 DWORD concat_prefix, concat_len;
1029 const WCHAR newline[] = {'\n',0};
1030 CHAR* value_multibyte = NULL;
1031
1032 if (type == REG_BINARY)
1033 {
1034 hex_prefix = hex;
1035 }
1036 else
1037 {
1038 const WCHAR hex_format[] = {'h','e','x','(','%','u',')',':',0};
1039 hex_prefix = hex_buf;
1040 wsprintfW(hex_buf, hex_format, type);
1041 if ((type == REG_SZ || type == REG_EXPAND_SZ || type == REG_MULTI_SZ) && !unicode)
1042 {
1043 value_multibyte = GetMultiByteStringN((WCHAR*)value, value_size / sizeof(WCHAR), &value_size);
1044 value = (BYTE*)value_multibyte;
1045 }
1046 }
1047
1048 concat_len = lstrlenW(concat);
1049 concat_prefix = 2;
1050
1051 hex_pos = *line_len;
1052 *line_len += lstrlenW(hex_prefix);
1053 data_pos = *line_len;
1054 *line_len += value_size * 3;
1055 /* - The 2 spaces that concat places at the start of the
1056 * line effectively reduce the space available for data.
1057 * - If the value name and hex prefix are very long
1058 * ( > REG_FILE_HEX_LINE_LEN) then we may overestimate
1059 * the needed number of lines by one. But that's ok.
1060 * - The trailing linefeed takes the place of a comma so
1061 * it's accounted for already.
1062 */
1063 *line_len += *line_len / (REG_FILE_HEX_LINE_LEN - concat_prefix) * concat_len;
1064 REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len);
1065 lstrcpyW(*line_buf + hex_pos, hex_prefix);
1066 if (value_size)
1067 {
1068 const WCHAR format[] = {'%','0','2','x',0};
1069 DWORD i, column;
1070
1071 column = data_pos; /* no line wrap yet */
1072 i = 0;
1073 while (1)
1074 {
1075 wsprintfW(*line_buf + data_pos, format, (unsigned int)value[i]);
1076 data_pos += 2;
1077 if (++i == value_size)
1078 break;
1079
1080 (*line_buf)[data_pos++] = ',';
1081 column += 3;
1082
1083 /* wrap the line */
1084 if (column >= REG_FILE_HEX_LINE_LEN)
1085 {
1086 lstrcpyW(*line_buf + data_pos, concat);
1087 data_pos += concat_len;
1088 column = concat_prefix;
1089 }
1090 }
1091 }
1092 lstrcpyW(*line_buf + data_pos, newline);
1093 HeapFree(GetProcessHeap(), 0, value_multibyte);
1094 }
1095
1096 /******************************************************************************
1097 * Writes the given line to a file, in multi-byte or wide characters
1098 */
1099 static void REGPROC_write_line(FILE *file, const WCHAR* str, BOOL unicode)
1100 {
1101 int i;
1102 if (unicode)
1103 {
1104 for(i = 0; str[i]; i++)
1105 {
1106 if (str[i] == L'\n')
1107 fputwc(L'\r', file);
1108 fputwc(str[i], file);
1109 }
1110 }
1111 else
1112 {
1113 char* strA = GetMultiByteString(str);
1114 fputs(strA, file);
1115 HeapFree(GetProcessHeap(), 0, strA);
1116 }
1117 }
1118
1119 /******************************************************************************
1120 * Writes contents of the registry key to the specified file stream.
1121 *
1122 * Parameters:
1123 * file - writable file stream to export registry branch to.
1124 * key - registry branch to export.
1125 * reg_key_name_buf - name of the key with registry class.
1126 * Is resized if necessary.
1127 * reg_key_name_size - length of the buffer for the registry class in characters.
1128 * val_name_buf - buffer for storing value name.
1129 * Is resized if necessary.
1130 * val_name_size - length of the buffer for storing value names in characters.
1131 * val_buf - buffer for storing values while extracting.
1132 * Is resized if necessary.
1133 * val_size - size of the buffer for storing values in bytes.
1134 */
1135 static void export_hkey(FILE *file, HKEY key,
1136 WCHAR **reg_key_name_buf, DWORD *reg_key_name_size,
1137 WCHAR **val_name_buf, DWORD *val_name_size,
1138 BYTE **val_buf, DWORD *val_size,
1139 WCHAR **line_buf, DWORD *line_buf_size,
1140 BOOL unicode)
1141 {
1142 DWORD max_sub_key_len;
1143 DWORD max_val_name_len;
1144 DWORD max_val_size;
1145 DWORD curr_len;
1146 DWORD i;
1147 BOOL more_data;
1148 LONG ret;
1149 WCHAR key_format[] = {'\n','[','%','s',']','\n',0};
1150
1151 /* get size information and resize the buffers if necessary */
1152 if (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL,
1153 &max_sub_key_len, NULL,
1154 NULL, &max_val_name_len, &max_val_size, NULL, NULL
1155 ) != ERROR_SUCCESS)
1156 {
1157 REGPROC_print_error();
1158 }
1159 curr_len = lstrlenW(*reg_key_name_buf);
1160 REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_size,
1161 max_sub_key_len + curr_len + 1);
1162 REGPROC_resize_char_buffer(val_name_buf, val_name_size,
1163 max_val_name_len);
1164 REGPROC_resize_binary_buffer(val_buf, val_size, max_val_size);
1165 REGPROC_resize_char_buffer(line_buf, line_buf_size, lstrlenW(*reg_key_name_buf) + 4);
1166 /* output data for the current key */
1167 wsprintfW(*line_buf, key_format, *reg_key_name_buf);
1168 REGPROC_write_line(file, *line_buf, unicode);
1169
1170 /* print all the values */
1171 i = 0;
1172 more_data = TRUE;
1173 while(more_data)
1174 {
1175 DWORD value_type;
1176 DWORD val_name_size1 = *val_name_size;
1177 DWORD val_size1 = *val_size;
1178 ret = RegEnumValueW(key, i, *val_name_buf, &val_name_size1, NULL,
1179 &value_type, *val_buf, &val_size1);
1180 if (ret == ERROR_MORE_DATA)
1181 {
1182 /* Increase the size of the buffers and retry */
1183 REGPROC_resize_char_buffer(val_name_buf, val_name_size, val_name_size1);
1184 REGPROC_resize_binary_buffer(val_buf, val_size, val_size1);
1185 }
1186 else if (ret != ERROR_SUCCESS)
1187 {
1188 more_data = FALSE;
1189 if (ret != ERROR_NO_MORE_ITEMS)
1190 {
1191 REGPROC_print_error();
1192 }
1193 }
1194 else
1195 {
1196 DWORD line_len;
1197 i++;
1198
1199 if ((*val_name_buf)[0])
1200 {
1201 const WCHAR val_start[] = {'"','%','s','"','=',0};
1202
1203 line_len = 0;
1204 REGPROC_export_string(line_buf, line_buf_size, &line_len, *val_name_buf, lstrlenW(*val_name_buf));
1205 REGPROC_resize_char_buffer(val_name_buf, val_name_size, lstrlenW(*line_buf) + 1);
1206 lstrcpyW(*val_name_buf, *line_buf);
1207
1208 line_len = 3 + lstrlenW(*val_name_buf);
1209 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len);
1210 wsprintfW(*line_buf, val_start, *val_name_buf);
1211 }
1212 else
1213 {
1214 const WCHAR std_val[] = {'@','=',0};
1215 line_len = 2;
1216 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len);
1217 lstrcpyW(*line_buf, std_val);
1218 }
1219
1220 switch (value_type)
1221 {
1222 case REG_SZ:
1223 {
1224 WCHAR* wstr = (WCHAR*)*val_buf;
1225
1226 if (val_size1 < sizeof(WCHAR) || val_size1 % sizeof(WCHAR) ||
1227 wstr[val_size1 / sizeof(WCHAR) - 1])
1228 {
1229 REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode);
1230 }
1231 else
1232 {
1233 const WCHAR start[] = {'"',0};
1234 const WCHAR end[] = {'"','\n',0};
1235 DWORD len;
1236
1237 len = lstrlenW(start);
1238 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + len);
1239 lstrcpyW(*line_buf + line_len, start);
1240 line_len += len;
1241
1242 /* At this point we know wstr is '\0'-terminated
1243 * so we can substract 1 from the size
1244 */
1245 REGPROC_export_string(line_buf, line_buf_size, &line_len, wstr, val_size1 / sizeof(WCHAR) - 1);
1246
1247 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + lstrlenW(end));
1248 lstrcpyW(*line_buf + line_len, end);
1249 }
1250 break;
1251 }
1252
1253 case REG_DWORD:
1254 {
1255 WCHAR format[] = {'d','w','o','r','d',':','%','0','8','x','\n',0};
1256
1257 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + 15);
1258 wsprintfW(*line_buf + line_len, format, *((DWORD *)*val_buf));
1259 break;
1260 }
1261
1262 default:
1263 {
1264 char* key_nameA = GetMultiByteString(*reg_key_name_buf);
1265 char* value_nameA = GetMultiByteString(*val_name_buf);
1266 fprintf(stderr,"%S: warning - unsupported registry format '%ld', "
1267 "treat as binary\n",
1268 getAppName(), value_type);
1269 fprintf(stderr,"key name: \"%s\"\n", key_nameA);
1270 fprintf(stderr,"value name:\"%s\"\n\n", value_nameA);
1271 HeapFree(GetProcessHeap(), 0, key_nameA);
1272 HeapFree(GetProcessHeap(), 0, value_nameA);
1273 }
1274 /* falls through */
1275 case REG_EXPAND_SZ:
1276 case REG_MULTI_SZ:
1277 /* falls through */
1278 case REG_BINARY:
1279 REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode);
1280 }
1281 REGPROC_write_line(file, *line_buf, unicode);
1282 }
1283 }
1284
1285 i = 0;
1286 more_data = TRUE;
1287 (*reg_key_name_buf)[curr_len] = '\\';
1288 while(more_data)
1289 {
1290 DWORD buf_size = *reg_key_name_size - curr_len - 1;
1291
1292 ret = RegEnumKeyExW(key, i, *reg_key_name_buf + curr_len + 1, &buf_size,
1293 NULL, NULL, NULL, NULL);
1294 if (ret == ERROR_MORE_DATA)
1295 {
1296 /* Increase the size of the buffer and retry */
1297 REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_size, curr_len + 1 + buf_size);
1298 }
1299 else if (ret != ERROR_SUCCESS)
1300 {
1301 more_data = FALSE;
1302 if (ret != ERROR_NO_MORE_ITEMS)
1303 {
1304 REGPROC_print_error();
1305 }
1306 }
1307 else
1308 {
1309 HKEY subkey;
1310
1311 i++;
1312 if (RegOpenKeyW(key, *reg_key_name_buf + curr_len + 1,
1313 &subkey) == ERROR_SUCCESS)
1314 {
1315 export_hkey(file, subkey, reg_key_name_buf, reg_key_name_size,
1316 val_name_buf, val_name_size, val_buf, val_size,
1317 line_buf, line_buf_size, unicode);
1318 RegCloseKey(subkey);
1319 }
1320 else
1321 {
1322 REGPROC_print_error();
1323 }
1324 }
1325 }
1326 (*reg_key_name_buf)[curr_len] = '\0';
1327 }
1328
1329 /******************************************************************************
1330 * Open file for export.
1331 */
1332 static FILE *REGPROC_open_export_file(WCHAR *file_name, BOOL unicode)
1333 {
1334 FILE *file;
1335 WCHAR dash = '-';
1336
1337 if (wcsncmp(file_name, &dash, 1) == 0)
1338 file = stdout;
1339 else
1340 {
1341 if (unicode)
1342 file = _wfopen(file_name, L"wb");
1343 else
1344 file = _wfopen(file_name, L"w");
1345 if (!file)
1346 {
1347 CHAR* file_nameA = GetMultiByteString(file_name);
1348 perror("");
1349 fprintf(stderr,"%S: Can't open file \"%s\"\n", getAppName(), file_nameA);
1350 HeapFree(GetProcessHeap(), 0, file_nameA);
1351 exit(1);
1352 }
1353 }
1354 if (unicode)
1355 {
1356 const BYTE unicode_seq[] = {0xff,0xfe};
1357 const WCHAR header[] = L"Windows Registry Editor Version 5.00\r\n";
1358 fwrite(unicode_seq, sizeof(BYTE), COUNT_OF(unicode_seq), file);
1359 fwrite(header, sizeof(WCHAR), lstrlenW(header), file);
1360 }
1361 else
1362 {
1363 fputs("REGEDIT4\n", file);
1364 }
1365
1366 return file;
1367 }
1368
1369 /******************************************************************************
1370 * Writes contents of the registry key to the specified file stream.
1371 *
1372 * Parameters:
1373 * file_name - name of a file to export registry branch to.
1374 * reg_key_name - registry branch to export. The whole registry is exported if
1375 * reg_key_name is NULL or contains an empty string.
1376 */
1377 BOOL export_registry_key(WCHAR *file_name, WCHAR *reg_key_name, DWORD format)
1378 {
1379 WCHAR *reg_key_name_buf;
1380 WCHAR *val_name_buf;
1381 BYTE *val_buf;
1382 WCHAR *line_buf;
1383 DWORD reg_key_name_size = KEY_MAX_LEN;
1384 DWORD val_name_size = KEY_MAX_LEN;
1385 DWORD val_size = REG_VAL_BUF_SIZE;
1386 DWORD line_buf_size = KEY_MAX_LEN + REG_VAL_BUF_SIZE;
1387 FILE *file = NULL;
1388 BOOL unicode = (format == REG_FORMAT_5);
1389
1390 reg_key_name_buf = HeapAlloc(GetProcessHeap(), 0,
1391 reg_key_name_size * sizeof(*reg_key_name_buf));
1392 val_name_buf = HeapAlloc(GetProcessHeap(), 0,
1393 val_name_size * sizeof(*val_name_buf));
1394 val_buf = HeapAlloc(GetProcessHeap(), 0, val_size);
1395 line_buf = HeapAlloc(GetProcessHeap(), 0, line_buf_size * sizeof(*line_buf));
1396 CHECK_ENOUGH_MEMORY(reg_key_name_buf && val_name_buf && val_buf && line_buf);
1397
1398 if (reg_key_name && reg_key_name[0])
1399 {
1400 HKEY reg_key_class;
1401 WCHAR *branch_name = NULL;
1402 HKEY key;
1403
1404 REGPROC_resize_char_buffer(&reg_key_name_buf, &reg_key_name_size,
1405 lstrlenW(reg_key_name));
1406 lstrcpyW(reg_key_name_buf, reg_key_name);
1407
1408 /* open the specified key */
1409 if (!parseKeyName(reg_key_name, &reg_key_class, &branch_name))
1410 {
1411 CHAR* key_nameA = GetMultiByteString(reg_key_name);
1412 fprintf(stderr,"%S: Incorrect registry class specification in '%s'\n",
1413 getAppName(), key_nameA);
1414 HeapFree(GetProcessHeap(), 0, key_nameA);
1415 exit(1);
1416 }
1417 if (!branch_name[0])
1418 {
1419 /* no branch - registry class is specified */
1420 file = REGPROC_open_export_file(file_name, unicode);
1421 export_hkey(file, reg_key_class,
1422 &reg_key_name_buf, &reg_key_name_size,
1423 &val_name_buf, &val_name_size,
1424 &val_buf, &val_size, &line_buf,
1425 &line_buf_size, unicode);
1426 }
1427 else if (RegOpenKeyW(reg_key_class, branch_name, &key) == ERROR_SUCCESS)
1428 {
1429 file = REGPROC_open_export_file(file_name, unicode);
1430 export_hkey(file, key,
1431 &reg_key_name_buf, &reg_key_name_size,
1432 &val_name_buf, &val_name_size,
1433 &val_buf, &val_size, &line_buf,
1434 &line_buf_size, unicode);
1435 RegCloseKey(key);
1436 }
1437 else
1438 {
1439 CHAR* key_nameA = GetMultiByteString(reg_key_name);
1440 fprintf(stderr,"%S: Can't export. Registry key '%s' does not exist!\n",
1441 getAppName(), key_nameA);
1442 HeapFree(GetProcessHeap(), 0, key_nameA);
1443 REGPROC_print_error();
1444 }
1445 }
1446 else
1447 {
1448 unsigned int i;
1449
1450 /* export all registry classes */
1451 file = REGPROC_open_export_file(file_name, unicode);
1452 for (i = 0; i < REG_CLASS_NUMBER; i++)
1453 {
1454 /* do not export HKEY_CLASSES_ROOT */
1455 if (reg_class_keys[i] != HKEY_CLASSES_ROOT &&
1456 reg_class_keys[i] != HKEY_CURRENT_USER &&
1457 reg_class_keys[i] != HKEY_CURRENT_CONFIG &&
1458 reg_class_keys[i] != HKEY_DYN_DATA)
1459 {
1460 lstrcpyW(reg_key_name_buf, reg_class_namesW[i]);
1461 export_hkey(file, reg_class_keys[i],
1462 &reg_key_name_buf, &reg_key_name_size,
1463 &val_name_buf, &val_name_size,
1464 &val_buf, &val_size, &line_buf,
1465 &line_buf_size, unicode);
1466 }
1467 }
1468 }
1469
1470 if (file)
1471 {
1472 fclose(file);
1473 }
1474 HeapFree(GetProcessHeap(), 0, reg_key_name);
1475 HeapFree(GetProcessHeap(), 0, val_name_buf);
1476 HeapFree(GetProcessHeap(), 0, val_buf);
1477 HeapFree(GetProcessHeap(), 0, line_buf);
1478 return TRUE;
1479 }
1480
1481 /******************************************************************************
1482 * Reads contents of the specified file into the registry.
1483 */
1484 BOOL import_registry_file(FILE* reg_file)
1485 {
1486 if (reg_file)
1487 {
1488 BYTE s[2];
1489 if (fread( s, 2, 1, reg_file) == 1)
1490 {
1491 if (s[0] == 0xff && s[1] == 0xfe)
1492 {
1493 processRegLinesW(reg_file);
1494 }
1495 else
1496 {
1497 fseek(reg_file, 0, SEEK_SET);
1498 processRegLinesA(reg_file);
1499 }
1500 }
1501 return TRUE;
1502 }
1503 return FALSE;
1504 }
1505
1506 /******************************************************************************
1507 * Removes the registry key with all subkeys. Parses full key name.
1508 *
1509 * Parameters:
1510 * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
1511 * empty, points to register key class, does not exist.
1512 */
1513 void delete_registry_key(WCHAR *reg_key_name)
1514 {
1515 WCHAR *key_name = NULL;
1516 HKEY key_class;
1517
1518 if (!reg_key_name || !reg_key_name[0])
1519 return;
1520
1521 if (!parseKeyName(reg_key_name, &key_class, &key_name))
1522 {
1523 char* reg_key_nameA = GetMultiByteString(reg_key_name);
1524 fprintf(stderr,"%S: Incorrect registry class specification in '%s'\n",
1525 getAppName(), reg_key_nameA);
1526 HeapFree(GetProcessHeap(), 0, reg_key_nameA);
1527 exit(1);
1528 }
1529 if (!*key_name)
1530 {
1531 char* reg_key_nameA = GetMultiByteString(reg_key_name);
1532 fprintf(stderr,"%S: Can't delete registry class '%s'\n",
1533 getAppName(), reg_key_nameA);
1534 HeapFree(GetProcessHeap(), 0, reg_key_nameA);
1535 exit(1);
1536 }
1537
1538 SHDeleteKey(key_class, key_name);
1539 }