2 * Copyright 2017 Hugh McMaster
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <wine/heap.h>
27 static void write_file(HANDLE hFile
, const WCHAR
*str
)
31 WriteFile(hFile
, str
, lstrlenW(str
) * sizeof(WCHAR
), &written
, NULL
);
34 static WCHAR
*escape_string(WCHAR
*str
, size_t str_len
, size_t *line_len
)
36 size_t i
, escape_count
, pos
;
39 for (i
= 0, escape_count
= 0; i
< str_len
; i
++)
45 if (c
== '\r' || c
== '\n' || c
== '\\' || c
== '"')
49 buf
= heap_xalloc((str_len
+ escape_count
+ 1) * sizeof(WCHAR
));
51 for (i
= 0, pos
= 0; i
< str_len
; i
++, pos
++)
85 static size_t export_value_name(HANDLE hFile
, WCHAR
*name
, size_t len
)
87 static const WCHAR quoted_fmt
[] = {'"','%','s','"','=',0};
88 static const WCHAR default_name
[] = {'@','=',0};
93 WCHAR
*str
= escape_string(name
, len
, &line_len
);
94 WCHAR
*buf
= heap_xalloc((line_len
+ 4) * sizeof(WCHAR
));
95 line_len
= swprintf(buf
, line_len
+ 4, quoted_fmt
, str
);
96 write_file(hFile
, buf
);
102 line_len
= lstrlenW(default_name
);
103 write_file(hFile
, default_name
);
109 static void export_string_data(WCHAR
**buf
, WCHAR
*data
, size_t size
)
111 size_t len
= 0, line_len
;
113 static const WCHAR fmt
[] = {'"','%','s','"',0};
116 len
= size
/ sizeof(WCHAR
) - 1;
117 str
= escape_string(data
, len
, &line_len
);
118 *buf
= heap_xalloc((line_len
+ 3) * sizeof(WCHAR
));
119 swprintf(*buf
, line_len
+ 3, fmt
, str
);
123 static void export_dword_data(WCHAR
**buf
, DWORD
*data
)
125 static const WCHAR fmt
[] = {'d','w','o','r','d',':','%','0','8','x',0};
127 *buf
= heap_xalloc(15 * sizeof(WCHAR
));
128 swprintf(*buf
, 15, fmt
, *data
);
131 static size_t export_hex_data_type(HANDLE hFile
, DWORD type
)
133 static const WCHAR hex
[] = {'h','e','x',':',0};
134 static const WCHAR hexp_fmt
[] = {'h','e','x','(','%','x',')',':',0};
137 if (type
== REG_BINARY
)
139 line_len
= lstrlenW(hex
);
140 write_file(hFile
, hex
);
144 WCHAR
*buf
= heap_xalloc(15 * sizeof(WCHAR
));
145 line_len
= swprintf(buf
, 15, hexp_fmt
, type
);
146 write_file(hFile
, buf
);
153 #define MAX_HEX_CHARS 77
155 static void export_hex_data(HANDLE hFile
, WCHAR
**buf
, DWORD type
,
156 DWORD line_len
, void *data
, DWORD size
)
158 static const WCHAR fmt
[] = {'%','0','2','x',0};
159 static const WCHAR hex_concat
[] = {'\\','\r','\n',' ',' ',0};
160 size_t num_commas
, i
, pos
;
162 line_len
+= export_hex_data_type(hFile
, type
);
166 num_commas
= size
- 1;
167 *buf
= heap_xalloc(size
* 3 * sizeof(WCHAR
));
169 for (i
= 0, pos
= 0; i
< size
; i
++)
171 pos
+= swprintf(*buf
+ pos
, 3, fmt
, ((BYTE
*)data
)[i
]);
172 if (i
== num_commas
) break;
177 if (line_len
>= MAX_HEX_CHARS
)
179 write_file(hFile
, *buf
);
180 write_file(hFile
, hex_concat
);
187 static void export_newline(HANDLE hFile
)
189 static const WCHAR newline
[] = {'\r','\n',0};
191 write_file(hFile
, newline
);
194 static void export_data(HANDLE hFile
, WCHAR
*value_name
, DWORD value_len
,
195 DWORD type
, void *data
, size_t size
)
198 size_t line_len
= export_value_name(hFile
, value_name
, value_len
);
203 export_string_data(&buf
, data
, size
);
208 export_dword_data(&buf
, data
);
217 export_hex_data(hFile
, &buf
, type
, line_len
, data
, size
);
221 if (size
|| type
== REG_SZ
)
223 write_file(hFile
, buf
);
227 export_newline(hFile
);
230 static void export_key_name(HANDLE hFile
, WCHAR
*name
)
232 static const WCHAR fmt
[] = {'\r','\n','[','%','s',']','\r','\n',0};
235 buf
= heap_xalloc((lstrlenW(name
) + 7) * sizeof(WCHAR
));
236 swprintf(buf
, lstrlenW(name
) + 7, fmt
, name
);
237 write_file(hFile
, buf
);
241 static int export_registry_data(HANDLE hFile
, HKEY key
, WCHAR
*path
)
244 DWORD max_value_len
= 256, value_len
;
245 DWORD max_data_bytes
= 2048, data_size
;
247 DWORD i
, type
, path_len
;
248 WCHAR
*value_name
, *subkey_name
, *subkey_path
;
252 export_key_name(hFile
, path
);
254 value_name
= heap_xalloc(max_value_len
* sizeof(WCHAR
));
255 data
= heap_xalloc(max_data_bytes
);
260 value_len
= max_value_len
;
261 data_size
= max_data_bytes
;
262 rc
= RegEnumValueW(key
, i
, value_name
, &value_len
, NULL
, &type
, data
, &data_size
);
264 if (rc
== ERROR_SUCCESS
)
266 export_data(hFile
, value_name
, value_len
, type
, data
, data_size
);
269 else if (rc
== ERROR_MORE_DATA
)
271 if (data_size
> max_data_bytes
)
273 max_data_bytes
= data_size
;
274 data
= heap_xrealloc(data
, max_data_bytes
);
279 value_name
= heap_xrealloc(value_name
, max_value_len
* sizeof(WCHAR
));
286 heap_free(value_name
);
288 subkey_name
= heap_xalloc(MAX_SUBKEY_LEN
* sizeof(WCHAR
));
290 path_len
= lstrlenW(path
);
295 subkey_len
= MAX_SUBKEY_LEN
;
296 rc
= RegEnumKeyExW(key
, i
, subkey_name
, &subkey_len
, NULL
, NULL
, NULL
, NULL
);
297 if (rc
== ERROR_SUCCESS
)
299 subkey_path
= build_subkey_path(path
, path_len
, subkey_name
, subkey_len
);
300 if (!RegOpenKeyExW(key
, subkey_name
, 0, KEY_READ
, &subkey
))
302 export_registry_data(hFile
, subkey
, subkey_path
);
305 heap_free(subkey_path
);
311 heap_free(subkey_name
);
315 static void export_file_header(HANDLE hFile
)
317 static const WCHAR header
[] = { 0xfeff,'W','i','n','d','o','w','s',' ',
318 'R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ',
319 'V','e','r','s','i','o','n',' ','5','.','0','0','\r','\n',0};
321 write_file(hFile
, header
);
324 static HANDLE
create_file(const WCHAR
*filename
, DWORD action
)
326 return CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, action
, FILE_ATTRIBUTE_NORMAL
, NULL
);
329 static HANDLE
get_file_handle(WCHAR
*filename
, BOOL overwrite_file
)
331 HANDLE hFile
= create_file(filename
, overwrite_file
? CREATE_ALWAYS
: CREATE_NEW
);
333 if (hFile
== INVALID_HANDLE_VALUE
)
335 DWORD error
= GetLastError();
337 if (error
== ERROR_FILE_EXISTS
)
339 if (!ask_confirm(STRING_OVERWRITE_FILE
, filename
))
341 output_message(STRING_CANCELLED
);
345 hFile
= create_file(filename
, CREATE_ALWAYS
);
351 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
352 FORMAT_MESSAGE_IGNORE_INSERTS
, NULL
, error
, 0, (WCHAR
*)&str
, 0, NULL
);
353 output_writeconsole(str
, lstrlenW(str
));
362 static BOOL
is_overwrite_switch(const WCHAR
*s
)
367 if ((s
[0] == '/' || s
[0] == '-') && (s
[1] == 'y' || s
[1] == 'Y'))
373 int reg_export(int argc
, WCHAR
*argv
[])
376 WCHAR
*path
, *long_key
;
377 BOOL overwrite_file
= FALSE
;
381 if (argc
== 3 || argc
> 5)
384 if (!parse_registry_key(argv
[2], &root
, &path
, &long_key
))
387 if (argc
== 5 && !(overwrite_file
= is_overwrite_switch(argv
[4])))
390 if (RegOpenKeyExW(root
, path
, 0, KEY_READ
, &hkey
))
392 output_message(STRING_INVALID_KEY
);
396 hFile
= get_file_handle(argv
[3], overwrite_file
);
397 export_file_header(hFile
);
398 ret
= export_registry_data(hFile
, hkey
, long_key
);
399 export_newline(hFile
);
407 output_message(STRING_INVALID_SYNTAX
);
408 output_message(STRING_FUNC_HELP
, wcsupr(argv
[1]));