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 static void write_file(HANDLE hFile
, const WCHAR
*str
)
27 WriteFile(hFile
, str
, lstrlenW(str
) * sizeof(WCHAR
), &written
, NULL
);
30 static WCHAR
*escape_string(WCHAR
*str
, size_t str_len
, size_t *line_len
)
32 size_t i
, escape_count
, pos
;
35 for (i
= 0, escape_count
= 0; i
< str_len
; i
++)
41 if (c
== '\r' || c
== '\n' || c
== '\\' || c
== '"')
45 buf
= heap_xalloc((str_len
+ escape_count
+ 1) * sizeof(WCHAR
));
47 for (i
= 0, pos
= 0; i
< str_len
; i
++, pos
++)
81 static size_t export_value_name(HANDLE hFile
, WCHAR
*name
, size_t len
)
83 static const WCHAR quoted_fmt
[] = {'"','%','s','"','=',0};
84 static const WCHAR default_name
[] = {'@','=',0};
89 WCHAR
*str
= escape_string(name
, len
, &line_len
);
90 WCHAR
*buf
= heap_xalloc((line_len
+ 4) * sizeof(WCHAR
));
91 line_len
= swprintf(buf
, line_len
+ 4, quoted_fmt
, str
);
92 write_file(hFile
, buf
);
98 line_len
= lstrlenW(default_name
);
99 write_file(hFile
, default_name
);
105 static void export_string_data(WCHAR
**buf
, WCHAR
*data
, size_t size
)
107 size_t len
= 0, line_len
;
109 static const WCHAR fmt
[] = {'"','%','s','"',0};
112 len
= size
/ sizeof(WCHAR
) - 1;
113 str
= escape_string(data
, len
, &line_len
);
114 *buf
= heap_xalloc((line_len
+ 3) * sizeof(WCHAR
));
115 swprintf(*buf
, line_len
+ 3, fmt
, str
);
119 static void export_dword_data(WCHAR
**buf
, DWORD
*data
)
121 static const WCHAR fmt
[] = {'d','w','o','r','d',':','%','0','8','x',0};
123 *buf
= heap_xalloc(15 * sizeof(WCHAR
));
124 swprintf(*buf
, 15, fmt
, *data
);
127 static size_t export_hex_data_type(HANDLE hFile
, DWORD type
)
129 static const WCHAR hex
[] = {'h','e','x',':',0};
130 static const WCHAR hexp_fmt
[] = {'h','e','x','(','%','x',')',':',0};
133 if (type
== REG_BINARY
)
135 line_len
= lstrlenW(hex
);
136 write_file(hFile
, hex
);
140 WCHAR
*buf
= heap_xalloc(15 * sizeof(WCHAR
));
141 line_len
= swprintf(buf
, 15, hexp_fmt
, type
);
142 write_file(hFile
, buf
);
149 #define MAX_HEX_CHARS 77
151 static void export_hex_data(HANDLE hFile
, WCHAR
**buf
, DWORD type
,
152 DWORD line_len
, void *data
, DWORD size
)
154 static const WCHAR fmt
[] = {'%','0','2','x',0};
155 static const WCHAR hex_concat
[] = {'\\','\r','\n',' ',' ',0};
156 size_t num_commas
, i
, pos
;
158 line_len
+= export_hex_data_type(hFile
, type
);
162 num_commas
= size
- 1;
163 *buf
= heap_xalloc(size
* 3 * sizeof(WCHAR
));
165 for (i
= 0, pos
= 0; i
< size
; i
++)
167 pos
+= swprintf(*buf
+ pos
, 3, fmt
, ((BYTE
*)data
)[i
]);
168 if (i
== num_commas
) break;
173 if (line_len
>= MAX_HEX_CHARS
)
175 write_file(hFile
, *buf
);
176 write_file(hFile
, hex_concat
);
183 static void export_newline(HANDLE hFile
)
185 static const WCHAR newline
[] = {'\r','\n',0};
187 write_file(hFile
, newline
);
190 static void export_data(HANDLE hFile
, WCHAR
*value_name
, DWORD value_len
,
191 DWORD type
, void *data
, size_t size
)
194 size_t line_len
= export_value_name(hFile
, value_name
, value_len
);
199 export_string_data(&buf
, data
, size
);
204 export_dword_data(&buf
, data
);
213 export_hex_data(hFile
, &buf
, type
, line_len
, data
, size
);
217 if (size
|| type
== REG_SZ
)
219 write_file(hFile
, buf
);
223 export_newline(hFile
);
226 static void export_key_name(HANDLE hFile
, WCHAR
*name
)
228 static const WCHAR fmt
[] = {'\r','\n','[','%','s',']','\r','\n',0};
231 buf
= heap_xalloc((lstrlenW(name
) + 7) * sizeof(WCHAR
));
232 swprintf(buf
, lstrlenW(name
) + 7, fmt
, name
);
233 write_file(hFile
, buf
);
237 static int export_registry_data(HANDLE hFile
, HKEY key
, WCHAR
*path
)
240 DWORD max_value_len
= 256, value_len
;
241 DWORD max_data_bytes
= 2048, data_size
;
243 DWORD i
, type
, path_len
;
244 WCHAR
*value_name
, *subkey_name
, *subkey_path
;
248 export_key_name(hFile
, path
);
250 value_name
= heap_xalloc(max_value_len
* sizeof(WCHAR
));
251 data
= heap_xalloc(max_data_bytes
);
256 value_len
= max_value_len
;
257 data_size
= max_data_bytes
;
258 rc
= RegEnumValueW(key
, i
, value_name
, &value_len
, NULL
, &type
, data
, &data_size
);
260 if (rc
== ERROR_SUCCESS
)
262 export_data(hFile
, value_name
, value_len
, type
, data
, data_size
);
265 else if (rc
== ERROR_MORE_DATA
)
267 if (data_size
> max_data_bytes
)
269 max_data_bytes
= data_size
;
270 data
= heap_xrealloc(data
, max_data_bytes
);
275 value_name
= heap_xrealloc(value_name
, max_value_len
* sizeof(WCHAR
));
282 heap_free(value_name
);
284 subkey_name
= heap_xalloc(MAX_SUBKEY_LEN
* sizeof(WCHAR
));
286 path_len
= lstrlenW(path
);
291 subkey_len
= MAX_SUBKEY_LEN
;
292 rc
= RegEnumKeyExW(key
, i
, subkey_name
, &subkey_len
, NULL
, NULL
, NULL
, NULL
);
293 if (rc
== ERROR_SUCCESS
)
295 subkey_path
= build_subkey_path(path
, path_len
, subkey_name
, subkey_len
);
296 if (!RegOpenKeyExW(key
, subkey_name
, 0, KEY_READ
, &subkey
))
298 export_registry_data(hFile
, subkey
, subkey_path
);
301 heap_free(subkey_path
);
307 heap_free(subkey_name
);
311 static void export_file_header(HANDLE hFile
)
313 static const WCHAR header
[] = { 0xfeff,'W','i','n','d','o','w','s',' ',
314 'R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ',
315 'V','e','r','s','i','o','n',' ','5','.','0','0','\r','\n',0};
317 write_file(hFile
, header
);
320 static HANDLE
create_file(const WCHAR
*filename
, DWORD action
)
322 return CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, action
, FILE_ATTRIBUTE_NORMAL
, NULL
);
325 static HANDLE
get_file_handle(WCHAR
*filename
, BOOL overwrite_file
)
327 HANDLE hFile
= create_file(filename
, overwrite_file
? CREATE_ALWAYS
: CREATE_NEW
);
329 if (hFile
== INVALID_HANDLE_VALUE
)
331 DWORD error
= GetLastError();
333 if (error
== ERROR_FILE_EXISTS
)
335 if (!ask_confirm(STRING_OVERWRITE_FILE
, filename
))
337 output_message(STRING_CANCELLED
);
341 hFile
= create_file(filename
, CREATE_ALWAYS
);
347 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
348 FORMAT_MESSAGE_IGNORE_INSERTS
, NULL
, error
, 0, (WCHAR
*)&str
, 0, NULL
);
349 output_writeconsole(str
, lstrlenW(str
));
358 static BOOL
is_overwrite_switch(const WCHAR
*s
)
360 return is_switch(s
, 'y');
363 int reg_export(int argc
, WCHAR
*argv
[])
366 WCHAR
*path
, *long_key
;
367 BOOL overwrite_file
= FALSE
;
371 if (argc
== 3 || argc
> 5)
374 if (!parse_registry_key(argv
[2], &root
, &path
, &long_key
))
377 if (argc
== 5 && !(overwrite_file
= is_overwrite_switch(argv
[4])))
380 if (RegOpenKeyExW(root
, path
, 0, KEY_READ
, &hkey
))
382 output_message(STRING_INVALID_KEY
);
386 hFile
= get_file_handle(argv
[3], overwrite_file
);
387 export_file_header(hFile
);
388 ret
= export_registry_data(hFile
, hkey
, long_key
);
389 export_newline(hFile
);
397 output_message(STRING_INVALID_SYNTAX
);
398 output_message(STRING_FUNC_HELP
, wcsupr(argv
[1]));