2 * Registry processing routines. Routines, common for registry
3 * processing frontends.
5 * Copyright 1999 Sylvain St-Germain
6 * Copyright 2002 Andriy Palamarchuk
7 * Copyright 2008 Alexander N. Sørnes <alex@thehandofagony.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include <wine/unicode.h>
34 #include <wine/debug.h>
37 #define REG_VAL_BUF_SIZE 4096
39 /* maximal number of characters in hexadecimal data line,
40 * including the indentation, but not including the '\' character
42 #define REG_FILE_HEX_LINE_LEN (2 + 25 * 3)
44 extern const WCHAR
* reg_class_namesW
[];
46 static HKEY reg_class_keys
[] = {
47 HKEY_LOCAL_MACHINE
, HKEY_USERS
, HKEY_CLASSES_ROOT
,
48 HKEY_CURRENT_CONFIG
, HKEY_CURRENT_USER
, HKEY_DYN_DATA
51 #define ARRAY_SIZE(A) (sizeof(A)/sizeof(*A))
53 /******************************************************************************
54 * Allocates memory and converts input from multibyte to wide chars
55 * Returned string must be freed by the caller
57 static WCHAR
* GetWideString(const char* strA
)
62 int len
= MultiByteToWideChar(CP_ACP
, 0, strA
, -1, NULL
, 0);
64 strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
65 CHECK_ENOUGH_MEMORY(strW
);
66 MultiByteToWideChar(CP_ACP
, 0, strA
, -1, strW
, len
);
72 /******************************************************************************
73 * Allocates memory and converts input from multibyte to wide chars
74 * Returned string must be freed by the caller
76 static WCHAR
* GetWideStringN(const char* strA
, int chars
, DWORD
*len
)
81 *len
= MultiByteToWideChar(CP_ACP
, 0, strA
, chars
, NULL
, 0);
83 strW
= HeapAlloc(GetProcessHeap(), 0, *len
* sizeof(WCHAR
));
84 CHECK_ENOUGH_MEMORY(strW
);
85 MultiByteToWideChar(CP_ACP
, 0, strA
, chars
, strW
, *len
);
92 /******************************************************************************
93 * Allocates memory and converts input from wide chars to multibyte
94 * Returned string must be freed by the caller
96 char* GetMultiByteString(const WCHAR
* strW
)
101 int len
= WideCharToMultiByte(CP_ACP
, 0, strW
, -1, NULL
, 0, NULL
, NULL
);
103 strA
= HeapAlloc(GetProcessHeap(), 0, len
);
104 CHECK_ENOUGH_MEMORY(strA
);
105 WideCharToMultiByte(CP_ACP
, 0, strW
, -1, strA
, len
, NULL
, NULL
);
111 /******************************************************************************
112 * Allocates memory and converts input from wide chars to multibyte
113 * Returned string must be freed by the caller
115 static char* GetMultiByteStringN(const WCHAR
* strW
, int chars
, DWORD
* len
)
120 *len
= WideCharToMultiByte(CP_ACP
, 0, strW
, chars
, NULL
, 0, NULL
, NULL
);
122 strA
= HeapAlloc(GetProcessHeap(), 0, *len
);
123 CHECK_ENOUGH_MEMORY(strA
);
124 WideCharToMultiByte(CP_ACP
, 0, strW
, chars
, strA
, *len
, NULL
, NULL
);
131 static WCHAR
*(*get_line
)(FILE *);
133 /* parser definitions */
136 HEADER
, /* parsing the registry file version header */
137 PARSE_WIN31_LINE
, /* parsing a Windows 3.1 registry line */
138 LINE_START
, /* at the beginning of a registry line */
139 KEY_NAME
, /* parsing a key name */
140 DELETE_KEY
, /* deleting a registry key */
141 SET_VALUE
, /* adding a value to the registry */
147 FILE *file
; /* pointer to a registry file */
148 WCHAR two_wchars
[2]; /* first two characters from the encoding check */
149 BOOL is_unicode
; /* parsing Unicode or ASCII data */
150 short int reg_version
; /* registry file version */
151 WCHAR
*value_name
; /* value name */
152 DWORD data_type
; /* data type */
153 void *data
; /* value data */
154 DWORD data_size
; /* size of the data (in bytes) */
155 enum parser_state state
; /* current parser state */
158 typedef WCHAR
*(*parser_state_func
)(struct parser
*parser
, WCHAR
*pos
);
160 /* parser state machine functions */
161 static WCHAR
*header_state(struct parser
*parser
, WCHAR
*pos
);
162 static WCHAR
*parse_win31_line_state(struct parser
*parser
, WCHAR
*pos
);
163 static WCHAR
*line_start_state(struct parser
*parser
, WCHAR
*pos
);
164 static WCHAR
*key_name_state(struct parser
*parser
, WCHAR
*pos
);
165 static WCHAR
*delete_key_state(struct parser
*parser
, WCHAR
*pos
);
166 static WCHAR
*set_value_state(struct parser
*parser
, WCHAR
*pos
);
168 static const parser_state_func parser_funcs
[NB_PARSER_STATES
] =
170 header_state
, /* HEADER */
171 parse_win31_line_state
, /* PARSE_WIN31_LINE */
172 line_start_state
, /* LINE_START */
173 key_name_state
, /* KEY_NAME */
174 delete_key_state
, /* DELETE_KEY */
175 set_value_state
, /* SET_VALUE */
178 /* set the new parser state and return the previous one */
179 static inline enum parser_state
set_state(struct parser
*parser
, enum parser_state state
)
181 enum parser_state ret
= parser
->state
;
182 parser
->state
= state
;
186 /******************************************************************************
187 * Converts a hex representation of a DWORD into a DWORD.
189 static BOOL
convertHexToDWord(WCHAR
* str
, DWORD
*dw
)
194 while (*str
== ' ' || *str
== '\t') str
++;
195 if (!*str
) goto error
;
198 while (isxdigitW(*p
))
203 if (count
> 8) goto error
;
206 while (*p
== ' ' || *p
== '\t') p
++;
207 if (*p
&& *p
!= ';') goto error
;
210 *dw
= strtoulW(str
, &end
, 16);
214 output_message(STRING_INVALID_HEX
);
218 /******************************************************************************
219 * Converts a hex comma separated values list into a binary string.
221 static BYTE
* convertHexCSVToHex(WCHAR
*str
, DWORD
*size
)
226 /* The worst case is 1 digit + 1 comma per byte */
227 *size
=(lstrlenW(str
)+1)/2;
228 data
=HeapAlloc(GetProcessHeap(), 0, *size
);
229 CHECK_ENOUGH_MEMORY(data
);
238 wc
= strtoulW(s
,&end
,16);
239 if (end
== s
|| wc
> 0xff || (*end
&& *end
!= ',')) {
240 output_message(STRING_CSV_HEX_ERROR
, s
);
241 HeapFree(GetProcessHeap(), 0, data
);
253 #define REG_UNKNOWN_TYPE 99
255 /******************************************************************************
256 * This function returns the HKEY associated with the data type encoded in the
257 * value. It modifies the input parameter (key value) in order to skip this
258 * "now useless" data type information.
260 * Note: Updated based on the algorithm used in 'server/registry.c'
262 static DWORD
getDataType(LPWSTR
*lpValue
, DWORD
* parse_type
)
264 struct data_type
{ const WCHAR
*tag
; int len
; int type
; int parse_type
; };
266 static const WCHAR quote
[] = {'"'};
267 static const WCHAR hex
[] = {'h','e','x',':'};
268 static const WCHAR dword
[] = {'d','w','o','r','d',':'};
269 static const WCHAR hexp
[] = {'h','e','x','('};
271 static const struct data_type data_types
[] = {
272 /* tag len type parse type */
273 { quote
, 1, REG_SZ
, REG_SZ
},
274 { hex
, 4, REG_BINARY
, REG_BINARY
},
275 { dword
, 6, REG_DWORD
, REG_DWORD
},
276 { hexp
, 4, -1, REG_BINARY
}, /* REG_NONE, REG_EXPAND_SZ, REG_MULTI_SZ */
280 const struct data_type
*ptr
;
283 for (ptr
= data_types
; ptr
->tag
; ptr
++) {
284 if (strncmpW( ptr
->tag
, *lpValue
, ptr
->len
))
288 *parse_type
= ptr
->parse_type
;
294 /* "hex(xx):" is special */
295 type
= (int)strtoulW( *lpValue
, &end
, 16 );
296 if (**lpValue
=='\0' || *end
!=')' || *(end
+1)!=':') {
297 type
= REG_UNKNOWN_TYPE
;
304 *parse_type
= REG_UNKNOWN_TYPE
;
305 return REG_UNKNOWN_TYPE
;
308 /******************************************************************************
309 * Replaces escape sequences with their character equivalents and
310 * null-terminates the string on the first non-escaped double quote.
312 * Assigns a pointer to the remaining unparsed data in the line.
313 * Returns TRUE or FALSE to indicate whether a closing double quote was found.
315 static BOOL
REGPROC_unescape_string(WCHAR
*str
, WCHAR
**unparsed
)
317 int str_idx
= 0; /* current character under analysis */
318 int val_idx
= 0; /* the last character of the unescaped string */
319 int len
= lstrlenW(str
);
322 for (str_idx
= 0; str_idx
< len
; str_idx
++, val_idx
++) {
323 if (str
[str_idx
] == '\\') {
325 switch (str
[str_idx
]) {
337 str
[val_idx
] = str
[str_idx
];
340 output_message(STRING_ESCAPE_SEQUENCE
, str
[str_idx
]);
341 str
[val_idx
] = str
[str_idx
];
344 } else if (str
[str_idx
] == '"') {
347 str
[val_idx
] = str
[str_idx
];
351 ret
= (str
[str_idx
] == '"');
352 *unparsed
= str
+ str_idx
+ 1;
357 static HKEY
parse_key_name(WCHAR
*key_name
, WCHAR
**key_path
)
361 if (!key_name
) return 0;
363 *key_path
= strchrW(key_name
, '\\');
364 if (*key_path
) (*key_path
)++;
366 for (i
= 0; i
< ARRAY_SIZE(reg_class_keys
); i
++)
368 int len
= lstrlenW(reg_class_namesW
[i
]);
369 if (!strncmpW(key_name
, reg_class_namesW
[i
], len
) &&
370 (key_name
[len
] == 0 || key_name
[len
] == '\\'))
372 return reg_class_keys
[i
];
379 /* Globals used by the setValue() & co */
380 static WCHAR
*currentKeyName
;
381 static HKEY currentKeyHandle
= NULL
;
383 /* Registry data types */
384 static const WCHAR type_none
[] = {'R','E','G','_','N','O','N','E',0};
385 static const WCHAR type_sz
[] = {'R','E','G','_','S','Z',0};
386 static const WCHAR type_expand_sz
[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0};
387 static const WCHAR type_binary
[] = {'R','E','G','_','B','I','N','A','R','Y',0};
388 static const WCHAR type_dword
[] = {'R','E','G','_','D','W','O','R','D',0};
389 static const WCHAR type_dword_le
[] = {'R','E','G','_','D','W','O','R','D','_','L','I','T','T','L','E','_','E','N','D','I','A','N',0};
390 static const WCHAR type_dword_be
[] = {'R','E','G','_','D','W','O','R','D','_','B','I','G','_','E','N','D','I','A','N',0};
391 static const WCHAR type_multi_sz
[] = {'R','E','G','_','M','U','L','T','I','_','S','Z',0};
400 {REG_NONE
, type_none
},
402 {REG_EXPAND_SZ
, type_expand_sz
},
403 {REG_BINARY
, type_binary
},
404 {REG_DWORD
, type_dword
},
405 {REG_DWORD_LITTLE_ENDIAN
, type_dword_le
},
406 {REG_DWORD_BIG_ENDIAN
, type_dword_be
},
407 {REG_MULTI_SZ
, type_multi_sz
},
410 static const WCHAR
*reg_type_to_wchar(DWORD type
)
412 int i
, array_size
= ARRAY_SIZE(type_rels
);
414 for (i
= 0; i
< array_size
; i
++)
416 if (type
== type_rels
[i
].type
)
417 return type_rels
[i
].name
;
422 /******************************************************************************
423 * Sets the value with name val_name to the data in val_data for the currently
427 * val_name - name of the registry value
428 * val_data - registry value data
430 static LONG
setValue(WCHAR
* val_name
, WCHAR
* val_data
, BOOL is_unicode
)
433 DWORD dwDataType
, dwParseType
;
436 WCHAR del
[] = {'-',0};
438 if ( (val_name
== NULL
) || (val_data
== NULL
) )
439 return ERROR_INVALID_PARAMETER
;
441 if (lstrcmpW(val_data
, del
) == 0)
443 res
=RegDeleteValueW(currentKeyHandle
,val_name
);
444 return (res
== ERROR_FILE_NOT_FOUND
? ERROR_SUCCESS
: res
);
447 /* Get the data type stored into the value field */
448 dwDataType
= getDataType(&val_data
, &dwParseType
);
450 if (dwParseType
== REG_SZ
) /* no conversion for string */
453 if (!REGPROC_unescape_string(val_data
, &line
))
454 return ERROR_INVALID_DATA
;
455 while (*line
== ' ' || *line
== '\t') line
++;
456 if (*line
&& *line
!= ';')
457 return ERROR_INVALID_DATA
;
458 lpbData
= (BYTE
*) val_data
;
459 dwLen
= (lstrlenW(val_data
) + 1) * sizeof(WCHAR
); /* size is in bytes */
461 else if (dwParseType
== REG_DWORD
) /* Convert the dword types */
463 if (!convertHexToDWord(val_data
, &dwData
))
464 return ERROR_INVALID_DATA
;
465 lpbData
= (BYTE
*)&dwData
;
466 dwLen
= sizeof(dwData
);
468 else if (dwParseType
== REG_BINARY
) /* Convert the binary data */
470 lpbData
= convertHexCSVToHex(val_data
, &dwLen
);
472 return ERROR_INVALID_DATA
;
474 if((dwDataType
== REG_MULTI_SZ
|| dwDataType
== REG_EXPAND_SZ
) && !is_unicode
)
476 LPBYTE tmp
= lpbData
;
477 lpbData
= (LPBYTE
)GetWideStringN((char*)lpbData
, dwLen
, &dwLen
);
478 dwLen
*= sizeof(WCHAR
);
479 HeapFree(GetProcessHeap(), 0, tmp
);
482 else /* unknown format */
484 if (dwDataType
== REG_UNKNOWN_TYPE
)
487 LoadStringW(GetModuleHandleW(NULL
), STRING_UNKNOWN_TYPE
, buf
, ARRAY_SIZE(buf
));
488 output_message(STRING_UNKNOWN_DATA_FORMAT
, buf
);
491 output_message(STRING_UNKNOWN_DATA_FORMAT
, reg_type_to_wchar(dwDataType
));
493 return ERROR_INVALID_DATA
;
496 res
= RegSetValueExW(
503 if (dwParseType
== REG_BINARY
)
504 HeapFree(GetProcessHeap(), 0, lpbData
);
508 static void closeKey(void)
510 if (currentKeyHandle
)
512 HeapFree(GetProcessHeap(), 0, currentKeyName
);
513 currentKeyName
= NULL
;
515 RegCloseKey(currentKeyHandle
);
516 currentKeyHandle
= NULL
;
520 /******************************************************************************
521 * Opens the registry key given by the input path.
522 * This key must be closed by calling close_key().
524 static LONG
openKeyW(WCHAR
* stdInput
)
532 /* Get the registry class */
533 if (!stdInput
|| !(key_class
= parse_key_name(stdInput
, &key_path
)))
534 return ERROR_INVALID_PARAMETER
;
536 res
= RegCreateKeyExW(key_class
, key_path
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
537 KEY_ALL_ACCESS
, NULL
, ¤tKeyHandle
, NULL
);
539 if (res
== ERROR_SUCCESS
)
541 currentKeyName
= HeapAlloc(GetProcessHeap(), 0, (strlenW(stdInput
) + 1) * sizeof(WCHAR
));
542 CHECK_ENOUGH_MEMORY(currentKeyName
);
543 strcpyW(currentKeyName
, stdInput
);
546 currentKeyHandle
= NULL
;
552 /******************************************************************************
553 * This function is a wrapper for the setValue function. It prepares the
554 * land and cleans the area once completed.
555 * Note: this function modifies the line parameter.
557 * line - registry file unwrapped line. Should have the registry value name and
558 * complete registry value data.
560 static void processSetValue(WCHAR
* line
, BOOL is_unicode
)
571 else if (!REGPROC_unescape_string(++val_name
, &line
))
574 while (*line
== ' ' || *line
== '\t') line
++;
578 while (*line
== ' ' || *line
== '\t') line
++;
580 /* trim trailing blanks */
582 while (len
> 0 && (line
[len
- 1] == ' ' || line
[len
- 1] == '\t')) len
--;
585 res
= setValue(val_name
, line
, is_unicode
);
586 if ( res
!= ERROR_SUCCESS
)
587 output_message(STRING_SETVALUE_FAILED
, val_name
, currentKeyName
);
591 output_message(STRING_SETVALUE_FAILED
, val_name
, currentKeyName
);
592 output_message(STRING_INVALID_LINE_SYNTAX
);
603 static enum reg_versions
parse_file_header(const WCHAR
*s
)
605 static const WCHAR header_31
[] = {'R','E','G','E','D','I','T',0};
606 static const WCHAR header_40
[] = {'R','E','G','E','D','I','T','4',0};
607 static const WCHAR header_50
[] = {'W','i','n','d','o','w','s',' ',
608 'R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ',
609 'V','e','r','s','i','o','n',' ','5','.','0','0',0};
611 while (*s
&& (*s
== ' ' || *s
== '\t')) s
++;
613 if (!strcmpW(s
, header_31
))
614 return REG_VERSION_31
;
616 if (!strcmpW(s
, header_40
))
617 return REG_VERSION_40
;
619 if (!strcmpW(s
, header_50
))
620 return REG_VERSION_50
;
622 /* The Windows version accepts registry file headers beginning with "REGEDIT" and ending
623 * with other characters, as long as "REGEDIT" appears at the start of the line. For example,
624 * "REGEDIT 4", "REGEDIT9" and "REGEDIT4FOO" are all treated as valid file headers.
625 * In all such cases, however, the contents of the registry file are not imported.
627 if (!strncmpW(s
, header_31
, 7)) /* "REGEDIT" without NUL */
628 return REG_VERSION_FUZZY
;
630 return REG_VERSION_INVALID
;
633 /* handler for parser HEADER state */
634 static WCHAR
*header_state(struct parser
*parser
, WCHAR
*pos
)
636 WCHAR
*line
, *header
;
638 if (!(line
= get_line(parser
->file
)))
641 if (!parser
->is_unicode
)
643 header
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(line
) + 3) * sizeof(WCHAR
));
644 CHECK_ENOUGH_MEMORY(header
);
645 header
[0] = parser
->two_wchars
[0];
646 header
[1] = parser
->two_wchars
[1];
647 lstrcpyW(header
+ 2, line
);
648 parser
->reg_version
= parse_file_header(header
);
649 HeapFree(GetProcessHeap(), 0, header
);
651 else parser
->reg_version
= parse_file_header(line
);
653 switch (parser
->reg_version
)
656 set_state(parser
, PARSE_WIN31_LINE
);
660 set_state(parser
, LINE_START
);
663 get_line(NULL
); /* Reset static variables */
670 /* handler for parser PARSE_WIN31_LINE state */
671 static WCHAR
*parse_win31_line_state(struct parser
*parser
, WCHAR
*pos
)
674 static WCHAR hkcr
[] = {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T'};
675 unsigned int key_end
= 0;
677 if (!(line
= get_line(parser
->file
)))
680 if (strncmpW(line
, hkcr
, ARRAY_SIZE(hkcr
)))
684 while (line
[key_end
] && !isspaceW(line
[key_end
])) key_end
++;
686 value
= line
+ key_end
;
687 while (*value
== ' ' || *value
== '\t') value
++;
689 if (*value
== '=') value
++;
690 if (*value
== ' ') value
++; /* at most one space is skipped */
696 if (openKeyW(line
) != ERROR_SUCCESS
)
698 output_message(STRING_OPEN_KEY_FAILED
, line
);
702 parser
->value_name
= NULL
;
703 parser
->data_type
= REG_SZ
;
704 parser
->data
= value
;
705 parser
->data_size
= (lstrlenW(value
) + 1) * sizeof(WCHAR
);
707 set_state(parser
, SET_VALUE
);
711 set_state(parser
, PARSE_WIN31_LINE
);
715 /* handler for parser LINE_START state */
716 static WCHAR
*line_start_state(struct parser
*parser
, WCHAR
*pos
)
720 if (!(line
= get_line(parser
->file
)))
723 for (p
= line
; *p
; p
++)
728 set_state(parser
, KEY_NAME
);
732 processSetValue(p
, parser
->is_unicode
);
738 set_state(parser
, LINE_START
);
746 /* handler for parser KEY_NAME state */
747 static WCHAR
*key_name_state(struct parser
*parser
, WCHAR
*pos
)
749 WCHAR
*p
= pos
, *key_end
;
751 if (*p
== ' ' || *p
== '\t' || !(key_end
= strrchrW(p
, ']')))
758 set_state(parser
, DELETE_KEY
);
761 else if (openKeyW(p
) != ERROR_SUCCESS
)
762 output_message(STRING_OPEN_KEY_FAILED
, p
);
765 set_state(parser
, LINE_START
);
769 /* handler for parser DELETE_KEY state */
770 static WCHAR
*delete_key_state(struct parser
*parser
, WCHAR
*pos
)
775 delete_registry_key(p
);
777 set_state(parser
, LINE_START
);
781 /* handler for parser SET_VALUE state */
782 static WCHAR
*set_value_state(struct parser
*parser
, WCHAR
*pos
)
784 RegSetValueExW(currentKeyHandle
, parser
->value_name
, 0, parser
->data_type
,
785 parser
->data
, parser
->data_size
);
787 set_state(parser
, PARSE_WIN31_LINE
);
792 static WCHAR
*get_lineA(FILE *fp
)
796 static char *buf
, *next
;
799 HeapFree(GetProcessHeap(), 0, lineW
);
801 if (!fp
) goto cleanup
;
805 size
= REG_VAL_BUF_SIZE
;
806 buf
= HeapAlloc(GetProcessHeap(), 0, size
);
807 CHECK_ENOUGH_MEMORY(buf
);
815 char *p
= strpbrk(line
, "\r\n");
820 memmove(buf
, next
, len
+ 1);
823 char *new_buf
= HeapReAlloc(GetProcessHeap(), 0, buf
, size
* 2);
824 CHECK_ENOUGH_MEMORY(new_buf
);
828 if (!(count
= fread(buf
+ len
, 1, size
- len
- 1, fp
)))
831 lineW
= GetWideString(buf
);
834 buf
[len
+ count
] = 0;
840 if (*p
== '\r' && *(p
+ 1) == '\n') next
++;
842 if (p
> buf
&& *(p
- 1) == '\\')
844 while (*next
== ' ' || *next
== '\t') next
++;
845 memmove(p
- 1, next
, strlen(next
) + 1);
849 if (*line
== ';' || *line
== '#')
854 lineW
= GetWideString(line
);
860 if (size
) HeapFree(GetProcessHeap(), 0, buf
);
865 static WCHAR
*get_lineW(FILE *fp
)
868 static WCHAR
*buf
, *next
;
871 if (!fp
) goto cleanup
;
875 size
= REG_VAL_BUF_SIZE
;
876 buf
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
877 CHECK_ENOUGH_MEMORY(buf
);
885 static const WCHAR line_endings
[] = {'\r','\n',0};
886 WCHAR
*p
= strpbrkW(line
, line_endings
);
891 memmove(buf
, next
, (len
+ 1) * sizeof(WCHAR
));
894 WCHAR
*new_buf
= HeapReAlloc(GetProcessHeap(), 0, buf
, (size
* 2) * sizeof(WCHAR
));
895 CHECK_ENOUGH_MEMORY(new_buf
);
899 if (!(count
= fread(buf
+ len
, sizeof(WCHAR
), size
- len
- 1, fp
)))
904 buf
[len
+ count
] = 0;
910 if (*p
== '\r' && *(p
+ 1) == '\n') next
++;
912 if (p
> buf
&& *(p
- 1) == '\\')
914 while (*next
== ' ' || *next
== '\t') next
++;
915 memmove(p
- 1, next
, (strlenW(next
) + 1) * sizeof(WCHAR
));
919 if (*line
== ';' || *line
== '#')
928 if (size
) HeapFree(GetProcessHeap(), 0, buf
);
933 /******************************************************************************
934 * Checks whether the buffer has enough room for the string or required size.
935 * Resizes the buffer if necessary.
938 * buffer - pointer to a buffer for string
939 * len - current length of the buffer in characters.
940 * required_len - length of the string to place to the buffer in characters.
941 * The length does not include the terminating null character.
943 static void REGPROC_resize_char_buffer(WCHAR
**buffer
, DWORD
*len
, DWORD required_len
)
946 if (required_len
> *len
) {
949 *buffer
= HeapAlloc(GetProcessHeap(), 0, *len
* sizeof(**buffer
));
951 *buffer
= HeapReAlloc(GetProcessHeap(), 0, *buffer
, *len
* sizeof(**buffer
));
952 CHECK_ENOUGH_MEMORY(*buffer
);
956 /******************************************************************************
957 * Same as REGPROC_resize_char_buffer() but on a regular buffer.
960 * buffer - pointer to a buffer
961 * len - current size of the buffer in bytes
962 * required_size - size of the data to place in the buffer in bytes
964 static void REGPROC_resize_binary_buffer(BYTE
**buffer
, DWORD
*size
, DWORD required_size
)
966 if (required_size
> *size
) {
967 *size
= required_size
;
969 *buffer
= HeapAlloc(GetProcessHeap(), 0, *size
);
971 *buffer
= HeapReAlloc(GetProcessHeap(), 0, *buffer
, *size
);
972 CHECK_ENOUGH_MEMORY(*buffer
);
976 /******************************************************************************
977 * Prints string str to file
979 static void REGPROC_export_string(WCHAR
**line_buf
, DWORD
*line_buf_size
, DWORD
*line_len
, WCHAR
*str
, DWORD str_len
)
984 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, *line_len
+ str_len
+ 10);
986 /* escaping characters */
988 for (i
= 0; i
< str_len
; i
++) {
993 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, *line_len
+ str_len
+ extra
);
994 (*line_buf
)[pos
++] = '\\';
995 (*line_buf
)[pos
++] = 'n';
1000 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, *line_len
+ str_len
+ extra
);
1001 (*line_buf
)[pos
++] = '\\';
1002 (*line_buf
)[pos
++] = 'r';
1008 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, *line_len
+ str_len
+ extra
);
1009 (*line_buf
)[pos
++] = '\\';
1013 (*line_buf
)[pos
++] = c
;
1017 (*line_buf
)[pos
] = '\0';
1021 static void REGPROC_export_binary(WCHAR
**line_buf
, DWORD
*line_buf_size
, DWORD
*line_len
, DWORD type
, BYTE
*value
, DWORD value_size
, BOOL unicode
)
1023 DWORD hex_pos
, data_pos
;
1024 const WCHAR
*hex_prefix
;
1025 const WCHAR hex
[] = {'h','e','x',':',0};
1027 const WCHAR concat
[] = {'\\','\r','\n',' ',' ',0};
1028 DWORD concat_prefix
, concat_len
;
1029 const WCHAR newline
[] = {'\r','\n',0};
1030 CHAR
* value_multibyte
= NULL
;
1032 if (type
== REG_BINARY
) {
1035 const WCHAR hex_format
[] = {'h','e','x','(','%','x',')',':',0};
1036 hex_prefix
= hex_buf
;
1037 sprintfW(hex_buf
, hex_format
, type
);
1038 if ((type
== REG_SZ
|| type
== REG_EXPAND_SZ
|| type
== REG_MULTI_SZ
) && !unicode
)
1040 value_multibyte
= GetMultiByteStringN((WCHAR
*)value
, value_size
/ sizeof(WCHAR
), &value_size
);
1041 value
= (BYTE
*)value_multibyte
;
1045 concat_len
= lstrlenW(concat
);
1048 hex_pos
= *line_len
;
1049 *line_len
+= lstrlenW(hex_prefix
);
1050 data_pos
= *line_len
;
1051 *line_len
+= value_size
* 3;
1052 /* - The 2 spaces that concat places at the start of the
1053 * line effectively reduce the space available for data.
1054 * - If the value name and hex prefix are very long
1055 * ( > REG_FILE_HEX_LINE_LEN) or *line_len divides
1056 * without a remainder then we may overestimate
1057 * the needed number of lines by one. But that's ok.
1058 * - The trailing '\r' takes the place of a comma so
1059 * we only need to add 1 for the trailing '\n'
1061 *line_len
+= *line_len
/ (REG_FILE_HEX_LINE_LEN
- concat_prefix
) * concat_len
+ 1;
1062 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, *line_len
);
1063 lstrcpyW(*line_buf
+ hex_pos
, hex_prefix
);
1066 const WCHAR format
[] = {'%','0','2','x',0};
1069 column
= data_pos
; /* no line wrap yet */
1073 sprintfW(*line_buf
+ data_pos
, format
, (unsigned int)value
[i
]);
1075 if (++i
== value_size
)
1078 (*line_buf
)[data_pos
++] = ',';
1082 if (column
>= REG_FILE_HEX_LINE_LEN
) {
1083 lstrcpyW(*line_buf
+ data_pos
, concat
);
1084 data_pos
+= concat_len
;
1085 column
= concat_prefix
;
1089 lstrcpyW(*line_buf
+ data_pos
, newline
);
1090 HeapFree(GetProcessHeap(), 0, value_multibyte
);
1093 /******************************************************************************
1094 * Writes the given line to a file, in multi-byte or wide characters
1096 static void REGPROC_write_line(FILE *file
, const WCHAR
* str
, BOOL unicode
)
1100 fwrite(str
, sizeof(WCHAR
), lstrlenW(str
), file
);
1103 char* strA
= GetMultiByteString(str
);
1105 HeapFree(GetProcessHeap(), 0, strA
);
1109 /******************************************************************************
1110 * Writes contents of the registry key to the specified file stream.
1113 * file - writable file stream to export registry branch to.
1114 * key - registry branch to export.
1115 * reg_key_name_buf - name of the key with registry class.
1116 * Is resized if necessary.
1117 * reg_key_name_size - length of the buffer for the registry class in characters.
1118 * val_name_buf - buffer for storing value name.
1119 * Is resized if necessary.
1120 * val_name_size - length of the buffer for storing value names in characters.
1121 * val_buf - buffer for storing values while extracting.
1122 * Is resized if necessary.
1123 * val_size - size of the buffer for storing values in bytes.
1125 static void export_hkey(FILE *file
, HKEY key
,
1126 WCHAR
**reg_key_name_buf
, DWORD
*reg_key_name_size
,
1127 WCHAR
**val_name_buf
, DWORD
*val_name_size
,
1128 BYTE
**val_buf
, DWORD
*val_size
,
1129 WCHAR
**line_buf
, DWORD
*line_buf_size
,
1132 DWORD max_sub_key_len
;
1133 DWORD max_val_name_len
;
1138 WCHAR key_format
[] = {'\r','\n','[','%','s',']','\r','\n',0};
1140 /* get size information and resize the buffers if necessary */
1141 if (RegQueryInfoKeyW(key
, NULL
, NULL
, NULL
, NULL
,
1142 &max_sub_key_len
, NULL
,
1143 NULL
, &max_val_name_len
, &max_val_size
, NULL
, NULL
1146 curr_len
= strlenW(*reg_key_name_buf
);
1147 REGPROC_resize_char_buffer(reg_key_name_buf
, reg_key_name_size
,
1148 max_sub_key_len
+ curr_len
+ 1);
1149 REGPROC_resize_char_buffer(val_name_buf
, val_name_size
,
1151 REGPROC_resize_binary_buffer(val_buf
, val_size
, max_val_size
);
1152 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, lstrlenW(*reg_key_name_buf
) + 4);
1153 /* output data for the current key */
1154 sprintfW(*line_buf
, key_format
, *reg_key_name_buf
);
1155 REGPROC_write_line(file
, *line_buf
, unicode
);
1157 /* print all the values */
1161 DWORD val_name_size1
= *val_name_size
;
1162 DWORD val_size1
= *val_size
;
1163 ret
= RegEnumValueW(key
, i
, *val_name_buf
, &val_name_size1
, NULL
,
1164 &value_type
, *val_buf
, &val_size1
);
1165 if (ret
== ERROR_MORE_DATA
) {
1166 /* Increase the size of the buffers and retry */
1167 REGPROC_resize_char_buffer(val_name_buf
, val_name_size
, val_name_size1
);
1168 REGPROC_resize_binary_buffer(val_buf
, val_size
, val_size1
);
1169 } else if (ret
== ERROR_SUCCESS
) {
1173 if ((*val_name_buf
)[0]) {
1174 const WCHAR val_start
[] = {'"','%','s','"','=',0};
1177 REGPROC_export_string(line_buf
, line_buf_size
, &line_len
, *val_name_buf
, lstrlenW(*val_name_buf
));
1178 REGPROC_resize_char_buffer(val_name_buf
, val_name_size
, lstrlenW(*line_buf
) + 1);
1179 lstrcpyW(*val_name_buf
, *line_buf
);
1181 line_len
= 3 + lstrlenW(*val_name_buf
);
1182 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, line_len
);
1183 sprintfW(*line_buf
, val_start
, *val_name_buf
);
1185 const WCHAR std_val
[] = {'@','=',0};
1187 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, line_len
);
1188 lstrcpyW(*line_buf
, std_val
);
1191 switch (value_type
) {
1194 WCHAR
* wstr
= (WCHAR
*)*val_buf
;
1196 if (val_size1
< sizeof(WCHAR
) || val_size1
% sizeof(WCHAR
) ||
1197 wstr
[val_size1
/ sizeof(WCHAR
) - 1]) {
1198 REGPROC_export_binary(line_buf
, line_buf_size
, &line_len
, value_type
, *val_buf
, val_size1
, unicode
);
1200 const WCHAR start
[] = {'"',0};
1201 const WCHAR end
[] = {'"','\r','\n',0};
1204 len
= lstrlenW(start
);
1205 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, line_len
+ len
);
1206 lstrcpyW(*line_buf
+ line_len
, start
);
1209 REGPROC_export_string(line_buf
, line_buf_size
, &line_len
, wstr
, lstrlenW(wstr
));
1211 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, line_len
+ lstrlenW(end
));
1212 lstrcpyW(*line_buf
+ line_len
, end
);
1219 WCHAR format
[] = {'d','w','o','r','d',':','%','0','8','x','\r','\n',0};
1221 REGPROC_resize_char_buffer(line_buf
, line_buf_size
, line_len
+ 15);
1222 sprintfW(*line_buf
+ line_len
, format
, *((DWORD
*)*val_buf
));
1228 output_message(STRING_UNSUPPORTED_TYPE
, reg_type_to_wchar(value_type
), *reg_key_name_buf
);
1229 output_message(STRING_EXPORT_AS_BINARY
, *val_name_buf
);
1236 REGPROC_export_binary(line_buf
, line_buf_size
, &line_len
, value_type
, *val_buf
, val_size1
, unicode
);
1238 REGPROC_write_line(file
, *line_buf
, unicode
);
1244 (*reg_key_name_buf
)[curr_len
] = '\\';
1246 DWORD buf_size
= *reg_key_name_size
- curr_len
- 1;
1248 ret
= RegEnumKeyExW(key
, i
, *reg_key_name_buf
+ curr_len
+ 1, &buf_size
,
1249 NULL
, NULL
, NULL
, NULL
);
1250 if (ret
== ERROR_MORE_DATA
) {
1251 /* Increase the size of the buffer and retry */
1252 REGPROC_resize_char_buffer(reg_key_name_buf
, reg_key_name_size
, curr_len
+ 1 + buf_size
);
1253 } else if (ret
== ERROR_SUCCESS
) {
1257 if (RegOpenKeyW(key
, *reg_key_name_buf
+ curr_len
+ 1,
1258 &subkey
) == ERROR_SUCCESS
) {
1259 export_hkey(file
, subkey
, reg_key_name_buf
, reg_key_name_size
,
1260 val_name_buf
, val_name_size
, val_buf
, val_size
,
1261 line_buf
, line_buf_size
, unicode
);
1262 RegCloseKey(subkey
);
1268 (*reg_key_name_buf
)[curr_len
] = '\0';
1271 /******************************************************************************
1272 * Open file in binary mode for export.
1274 static FILE *REGPROC_open_export_file(WCHAR
*file_name
, BOOL unicode
)
1279 if (strncmpW(file_name
,&dash
,1)==0) {
1281 _setmode(_fileno(file
), _O_BINARY
);
1284 WCHAR wb_mode
[] = {'w','b',0};
1285 WCHAR regedit
[] = {'r','e','g','e','d','i','t',0};
1287 file
= _wfopen(file_name
, wb_mode
);
1290 output_message(STRING_CANNOT_OPEN_FILE
, file_name
);
1296 const BYTE unicode_seq
[] = {0xff,0xfe};
1297 const WCHAR header
[] = {'W','i','n','d','o','w','s',' ','R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ','V','e','r','s','i','o','n',' ','5','.','0','0','\r','\n'};
1298 fwrite(unicode_seq
, sizeof(BYTE
), sizeof(unicode_seq
)/sizeof(unicode_seq
[0]), file
);
1299 fwrite(header
, sizeof(WCHAR
), sizeof(header
)/sizeof(header
[0]), file
);
1302 fputs("REGEDIT4\r\n", file
);
1308 /******************************************************************************
1309 * Writes contents of the registry key to the specified file stream.
1312 * file_name - name of a file to export registry branch to.
1313 * reg_key_name - registry branch to export. The whole registry is exported if
1314 * reg_key_name is NULL or contains an empty string.
1316 BOOL
export_registry_key(WCHAR
*file_name
, WCHAR
*reg_key_name
, DWORD format
)
1318 WCHAR
*reg_key_name_buf
;
1319 WCHAR
*val_name_buf
;
1322 DWORD reg_key_name_size
= KEY_MAX_LEN
;
1323 DWORD val_name_size
= KEY_MAX_LEN
;
1324 DWORD val_size
= REG_VAL_BUF_SIZE
;
1325 DWORD line_buf_size
= KEY_MAX_LEN
+ REG_VAL_BUF_SIZE
;
1327 BOOL unicode
= (format
== REG_FORMAT_5
);
1329 reg_key_name_buf
= HeapAlloc(GetProcessHeap(), 0,
1330 reg_key_name_size
* sizeof(*reg_key_name_buf
));
1331 val_name_buf
= HeapAlloc(GetProcessHeap(), 0,
1332 val_name_size
* sizeof(*val_name_buf
));
1333 val_buf
= HeapAlloc(GetProcessHeap(), 0, val_size
);
1334 line_buf
= HeapAlloc(GetProcessHeap(), 0, line_buf_size
* sizeof(*line_buf
));
1335 CHECK_ENOUGH_MEMORY(reg_key_name_buf
&& val_name_buf
&& val_buf
&& line_buf
);
1337 if (reg_key_name
&& reg_key_name
[0]) {
1339 WCHAR
*branch_name
= NULL
;
1342 REGPROC_resize_char_buffer(®_key_name_buf
, ®_key_name_size
,
1343 lstrlenW(reg_key_name
));
1344 lstrcpyW(reg_key_name_buf
, reg_key_name
);
1346 /* open the specified key */
1347 if (!(reg_key_class
= parse_key_name(reg_key_name
, &branch_name
))) {
1348 output_message(STRING_INCORRECT_REG_CLASS
, reg_key_name
);
1351 if (!branch_name
|| !*branch_name
) {
1352 /* no branch - registry class is specified */
1353 file
= REGPROC_open_export_file(file_name
, unicode
);
1354 export_hkey(file
, reg_key_class
,
1355 ®_key_name_buf
, ®_key_name_size
,
1356 &val_name_buf
, &val_name_size
,
1357 &val_buf
, &val_size
, &line_buf
,
1358 &line_buf_size
, unicode
);
1359 } else if (RegOpenKeyW(reg_key_class
, branch_name
, &key
) == ERROR_SUCCESS
) {
1360 file
= REGPROC_open_export_file(file_name
, unicode
);
1361 export_hkey(file
, key
,
1362 ®_key_name_buf
, ®_key_name_size
,
1363 &val_name_buf
, &val_name_size
,
1364 &val_buf
, &val_size
, &line_buf
,
1365 &line_buf_size
, unicode
);
1368 output_message(STRING_REG_KEY_NOT_FOUND
, reg_key_name
);
1373 /* export all registry classes */
1374 file
= REGPROC_open_export_file(file_name
, unicode
);
1375 for (i
= 0; i
< ARRAY_SIZE(reg_class_keys
); i
++) {
1376 /* do not export HKEY_CLASSES_ROOT */
1377 if (reg_class_keys
[i
] != HKEY_CLASSES_ROOT
&&
1378 reg_class_keys
[i
] != HKEY_CURRENT_USER
&&
1379 reg_class_keys
[i
] != HKEY_CURRENT_CONFIG
&&
1380 reg_class_keys
[i
] != HKEY_DYN_DATA
) {
1381 lstrcpyW(reg_key_name_buf
, reg_class_namesW
[i
]);
1382 export_hkey(file
, reg_class_keys
[i
],
1383 ®_key_name_buf
, ®_key_name_size
,
1384 &val_name_buf
, &val_name_size
,
1385 &val_buf
, &val_size
, &line_buf
,
1386 &line_buf_size
, unicode
);
1394 HeapFree(GetProcessHeap(), 0, reg_key_name
);
1395 HeapFree(GetProcessHeap(), 0, val_name_buf
);
1396 HeapFree(GetProcessHeap(), 0, val_buf
);
1397 HeapFree(GetProcessHeap(), 0, line_buf
);
1401 /******************************************************************************
1402 * Reads contents of the specified file into the registry.
1404 BOOL
import_registry_file(FILE *reg_file
)
1407 struct parser parser
;
1410 if (!reg_file
|| (fread(s
, 2, 1, reg_file
) != 1))
1413 parser
.is_unicode
= (s
[0] == 0xff && s
[1] == 0xfe);
1414 get_line
= parser
.is_unicode
? get_lineW
: get_lineA
;
1416 parser
.file
= reg_file
;
1417 parser
.two_wchars
[0] = s
[0];
1418 parser
.two_wchars
[1] = s
[1];
1419 parser
.reg_version
= -1;
1420 parser
.value_name
= NULL
;
1421 parser
.data_type
= 0;
1423 parser
.data_size
= 0;
1424 parser
.state
= HEADER
;
1426 pos
= parser
.two_wchars
;
1428 /* parser main loop */
1430 pos
= (parser_funcs
[parser
.state
])(&parser
, pos
);
1432 if (parser
.reg_version
== REG_VERSION_FUZZY
|| parser
.reg_version
== REG_VERSION_INVALID
)
1433 return parser
.reg_version
== REG_VERSION_FUZZY
;
1439 /******************************************************************************
1440 * Removes the registry key with all subkeys. Parses full key name.
1443 * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
1444 * empty, points to register key class, does not exist.
1446 void delete_registry_key(WCHAR
*reg_key_name
)
1448 WCHAR
*key_name
= NULL
;
1451 if (!reg_key_name
|| !reg_key_name
[0])
1454 if (!(key_class
= parse_key_name(reg_key_name
, &key_name
))) {
1455 output_message(STRING_INCORRECT_REG_CLASS
, reg_key_name
);
1459 output_message(STRING_DELETE_REG_CLASS_FAILED
, reg_key_name
);
1463 RegDeleteTreeW(key_class
, key_name
);