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
22 #include <wine/unicode.h>
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
++)
42 if (c
== '\r' || c
== '\n' || c
== '\\' || c
== '"' || c
== '\0')
46 buf
= heap_xalloc((str_len
+ escape_count
+ 1) * sizeof(WCHAR
));
48 for (i
= 0, pos
= 0; i
< str_len
; i
++, pos
++)
84 static size_t export_value_name(HANDLE hFile
, WCHAR
*name
, size_t len
)
86 static const WCHAR quoted_fmt
[] = {'"','%','s','"','=',0};
87 static const WCHAR default_name
[] = {'@','=',0};
92 WCHAR
*str
= escape_string(name
, len
, &line_len
);
93 WCHAR
*buf
= heap_xalloc((line_len
+ 4) * sizeof(WCHAR
));
94 line_len
= sprintfW(buf
, quoted_fmt
, str
);
95 write_file(hFile
, buf
);
101 line_len
= lstrlenW(default_name
);
102 write_file(hFile
, default_name
);
108 static void export_string_data(WCHAR
**buf
, WCHAR
*data
, size_t size
)
110 size_t len
= 0, line_len
;
112 static const WCHAR fmt
[] = {'"','%','s','"',0};
115 len
= size
/ sizeof(WCHAR
) - 1;
116 str
= escape_string(data
, len
, &line_len
);
117 *buf
= heap_xalloc((line_len
+ 3) * sizeof(WCHAR
));
118 sprintfW(*buf
, fmt
, str
);
122 static void export_dword_data(WCHAR
**buf
, DWORD
*data
)
124 static const WCHAR fmt
[] = {'d','w','o','r','d',':','%','0','8','x',0};
126 *buf
= heap_xalloc(15 * sizeof(WCHAR
));
127 sprintfW(*buf
, fmt
, *data
);
130 static size_t export_hex_data_type(HANDLE hFile
, DWORD type
)
132 static const WCHAR hex
[] = {'h','e','x',':',0};
133 static const WCHAR hexp_fmt
[] = {'h','e','x','(','%','x',')',':',0};
136 if (type
== REG_BINARY
)
138 line_len
= lstrlenW(hex
);
139 write_file(hFile
, hex
);
143 WCHAR
*buf
= heap_xalloc(15 * sizeof(WCHAR
));
144 line_len
= sprintfW(buf
, hexp_fmt
, type
);
145 write_file(hFile
, buf
);
152 #define MAX_HEX_CHARS 77
154 static void export_hex_data(HANDLE hFile
, WCHAR
**buf
, DWORD type
,
155 DWORD line_len
, void *data
, DWORD size
)
157 static const WCHAR fmt
[] = {'%','0','2','x',0};
158 static const WCHAR hex_concat
[] = {'\\','\r','\n',' ',' ',0};
159 size_t num_commas
, i
, pos
;
161 line_len
+= export_hex_data_type(hFile
, type
);
165 num_commas
= size
- 1;
166 *buf
= heap_xalloc(size
* 3 * sizeof(WCHAR
));
168 for (i
= 0, pos
= 0; i
< size
; i
++)
170 pos
+= sprintfW(*buf
+ pos
, fmt
, ((BYTE
*)data
)[i
]);
171 if (i
== num_commas
) break;
176 if (line_len
>= MAX_HEX_CHARS
)
178 write_file(hFile
, *buf
);
179 write_file(hFile
, hex_concat
);
186 static void export_newline(HANDLE hFile
)
188 static const WCHAR newline
[] = {'\r','\n',0};
190 write_file(hFile
, newline
);
193 static void export_data(HANDLE hFile
, WCHAR
*value_name
, DWORD value_len
,
194 DWORD type
, void *data
, size_t size
)
197 size_t line_len
= export_value_name(hFile
, value_name
, value_len
);
202 export_string_data(&buf
, data
, size
);
207 export_dword_data(&buf
, data
);
216 export_hex_data(hFile
, &buf
, type
, line_len
, data
, size
);
220 if (size
|| type
== REG_SZ
)
222 write_file(hFile
, buf
);
226 export_newline(hFile
);
229 static void export_key_name(HANDLE hFile
, WCHAR
*name
)
231 static const WCHAR fmt
[] = {'\r','\n','[','%','s',']','\r','\n',0};
234 buf
= heap_xalloc((lstrlenW(name
) + 7) * sizeof(WCHAR
));
235 sprintfW(buf
, fmt
, name
);
236 write_file(hFile
, buf
);
240 static int export_registry_data(HANDLE hFile
, HKEY key
, WCHAR
*path
)
243 DWORD max_value_len
= 256, value_len
;
244 DWORD max_data_bytes
= 2048, data_size
;
246 DWORD i
, type
, path_len
;
247 WCHAR
*value_name
, *subkey_name
, *subkey_path
;
251 export_key_name(hFile
, path
);
253 value_name
= heap_xalloc(max_value_len
* sizeof(WCHAR
));
254 data
= heap_xalloc(max_data_bytes
);
259 value_len
= max_value_len
;
260 data_size
= max_data_bytes
;
261 rc
= RegEnumValueW(key
, i
, value_name
, &value_len
, NULL
, &type
, data
, &data_size
);
263 if (rc
== ERROR_SUCCESS
)
265 export_data(hFile
, value_name
, value_len
, type
, data
, data_size
);
268 else if (rc
== ERROR_MORE_DATA
)
270 if (data_size
> max_data_bytes
)
272 max_data_bytes
= data_size
;
273 data
= heap_xrealloc(data
, max_data_bytes
);
278 value_name
= heap_xrealloc(value_name
, max_value_len
* sizeof(WCHAR
));
285 heap_free(value_name
);
287 subkey_name
= heap_xalloc(MAX_SUBKEY_LEN
* sizeof(WCHAR
));
289 path_len
= lstrlenW(path
);
294 subkey_len
= MAX_SUBKEY_LEN
;
295 rc
= RegEnumKeyExW(key
, i
, subkey_name
, &subkey_len
, NULL
, NULL
, NULL
, NULL
);
296 if (rc
== ERROR_SUCCESS
)
298 subkey_path
= build_subkey_path(path
, path_len
, subkey_name
, subkey_len
);
299 if (!RegOpenKeyExW(key
, subkey_name
, 0, KEY_READ
, &subkey
))
301 export_registry_data(hFile
, subkey
, subkey_path
);
304 heap_free(subkey_path
);
310 heap_free(subkey_name
);
314 static void export_file_header(HANDLE hFile
)
316 static const WCHAR header
[] = { 0xfeff,'W','i','n','d','o','w','s',' ',
317 'R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ',
318 'V','e','r','s','i','o','n',' ','5','.','0','0','\r','\n'};
320 write_file(hFile
, header
);
323 static HANDLE
create_file(const WCHAR
*filename
, DWORD action
)
325 return CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, action
, FILE_ATTRIBUTE_NORMAL
, NULL
);
328 static HANDLE
get_file_handle(WCHAR
*filename
, BOOL overwrite_file
)
330 HANDLE hFile
= create_file(filename
, overwrite_file
? CREATE_ALWAYS
: CREATE_NEW
);
332 if (hFile
== INVALID_HANDLE_VALUE
)
334 DWORD error
= GetLastError();
336 if (error
== ERROR_FILE_EXISTS
)
338 if (!ask_confirm(STRING_OVERWRITE_FILE
, filename
))
340 output_message(STRING_CANCELLED
);
344 hFile
= create_file(filename
, CREATE_ALWAYS
);
350 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
351 FORMAT_MESSAGE_IGNORE_INSERTS
, NULL
, error
, 0, (WCHAR
*)&str
, 0, NULL
);
352 output_writeconsole(str
, lstrlenW(str
));
361 static BOOL
is_overwrite_switch(const WCHAR
*s
)
366 if ((s
[0] == '/' || s
[0] == '-') && (s
[1] == 'y' || s
[1] == 'Y'))
372 int reg_export(int argc
, WCHAR
*argv
[])
375 WCHAR
*path
, *long_key
;
376 BOOL overwrite_file
= FALSE
;
380 if (argc
== 3 || argc
> 5)
383 if (!parse_registry_key(argv
[2], &root
, &path
, &long_key
))
386 if (argc
== 5 && !(overwrite_file
= is_overwrite_switch(argv
[4])))
389 if (RegOpenKeyExW(root
, path
, 0, KEY_READ
, &hkey
))
391 output_message(STRING_INVALID_KEY
);
395 hFile
= get_file_handle(argv
[3], overwrite_file
);
396 export_file_header(hFile
);
397 ret
= export_registry_data(hFile
, hkey
, long_key
);
398 export_newline(hFile
);
406 output_message(STRING_INVALID_SYNTAX
);
407 output_message(STRING_FUNC_HELP
, struprW(argv
[1]));