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 static void write_file(HANDLE hFile
, const WCHAR
*str
)
26 WriteFile(hFile
, str
, lstrlenW(str
) * sizeof(WCHAR
), &written
, NULL
);
29 static WCHAR
*escape_string(WCHAR
*str
, size_t str_len
, size_t *line_len
)
31 size_t i
, escape_count
, pos
;
34 for (i
= 0, escape_count
= 0; i
< str_len
; i
++)
40 if (c
== '\r' || c
== '\n' || c
== '\\' || c
== '"')
44 buf
= malloc((str_len
+ escape_count
+ 1) * sizeof(WCHAR
));
46 for (i
= 0, pos
= 0; i
< str_len
; i
++, pos
++)
80 static size_t export_value_name(HANDLE hFile
, WCHAR
*name
, size_t len
)
82 static const WCHAR
*default_name
= L
"@=";
87 WCHAR
*str
= escape_string(name
, len
, &line_len
);
88 WCHAR
*buf
= malloc((line_len
+ 4) * sizeof(WCHAR
));
89 line_len
= swprintf(buf
, line_len
+ 4, L
"\"%s\"=", str
);
90 write_file(hFile
, buf
);
96 line_len
= lstrlenW(default_name
);
97 write_file(hFile
, default_name
);
103 static void export_string_data(WCHAR
**buf
, WCHAR
*data
, size_t size
)
105 size_t len
= 0, line_len
;
109 len
= size
/ sizeof(WCHAR
) - 1;
110 str
= escape_string(data
, len
, &line_len
);
111 *buf
= malloc((line_len
+ 3) * sizeof(WCHAR
));
112 swprintf(*buf
, line_len
+ 3, L
"\"%s\"", str
);
116 static void export_dword_data(WCHAR
**buf
, DWORD
*data
)
118 *buf
= malloc(15 * sizeof(WCHAR
));
119 swprintf(*buf
, 15, L
"dword:%08x", *data
);
122 static size_t export_hex_data_type(HANDLE hFile
, DWORD type
)
124 static const WCHAR
*hex
= L
"hex:";
127 if (type
== REG_BINARY
)
129 line_len
= lstrlenW(hex
);
130 write_file(hFile
, hex
);
134 WCHAR
*buf
= malloc(15 * sizeof(WCHAR
));
135 line_len
= swprintf(buf
, 15, L
"hex(%x):", type
);
136 write_file(hFile
, buf
);
143 #define MAX_HEX_CHARS 77
145 static void export_hex_data(HANDLE hFile
, WCHAR
**buf
, DWORD type
,
146 DWORD line_len
, void *data
, DWORD size
)
148 size_t num_commas
, i
, pos
;
150 line_len
+= export_hex_data_type(hFile
, type
);
154 num_commas
= size
- 1;
155 *buf
= malloc(size
* 3 * sizeof(WCHAR
));
157 for (i
= 0, pos
= 0; i
< size
; i
++)
159 pos
+= swprintf(*buf
+ pos
, 3, L
"%02x", ((BYTE
*)data
)[i
]);
160 if (i
== num_commas
) break;
165 if (line_len
>= MAX_HEX_CHARS
)
167 write_file(hFile
, *buf
);
168 write_file(hFile
, L
"\\\r\n ");
175 static void export_newline(HANDLE hFile
)
177 static const WCHAR
*newline
= L
"\r\n";
179 write_file(hFile
, newline
);
182 static void export_data(HANDLE hFile
, WCHAR
*value_name
, DWORD value_len
,
183 DWORD type
, void *data
, size_t size
)
186 size_t line_len
= export_value_name(hFile
, value_name
, value_len
);
191 export_string_data(&buf
, data
, size
);
196 export_dword_data(&buf
, data
);
205 export_hex_data(hFile
, &buf
, type
, line_len
, data
, size
);
209 if (size
|| type
== REG_SZ
)
211 write_file(hFile
, buf
);
215 export_newline(hFile
);
218 static void export_key_name(HANDLE hFile
, WCHAR
*name
)
222 buf
= malloc((lstrlenW(name
) + 7) * sizeof(WCHAR
));
223 swprintf(buf
, lstrlenW(name
) + 7, L
"\r\n[%s]\r\n", name
);
224 write_file(hFile
, buf
);
228 static int export_registry_data(HANDLE hFile
, HKEY hkey
, WCHAR
*path
, REGSAM sam
)
231 DWORD max_value_len
= 256, value_len
;
232 DWORD max_data_bytes
= 2048, data_size
;
234 DWORD i
, type
, path_len
;
235 WCHAR
*value_name
, *subkey_name
, *subkey_path
;
239 export_key_name(hFile
, path
);
241 value_name
= malloc(max_value_len
* sizeof(WCHAR
));
242 data
= malloc(max_data_bytes
);
247 value_len
= max_value_len
;
248 data_size
= max_data_bytes
;
249 rc
= RegEnumValueW(hkey
, i
, value_name
, &value_len
, NULL
, &type
, data
, &data_size
);
251 if (rc
== ERROR_SUCCESS
)
253 export_data(hFile
, value_name
, value_len
, type
, data
, data_size
);
256 else if (rc
== ERROR_MORE_DATA
)
258 if (data_size
> max_data_bytes
)
260 max_data_bytes
= data_size
;
261 data
= realloc(data
, max_data_bytes
);
266 value_name
= realloc(value_name
, max_value_len
* sizeof(WCHAR
));
275 subkey_name
= malloc(MAX_SUBKEY_LEN
* sizeof(WCHAR
));
277 path_len
= lstrlenW(path
);
282 subkey_len
= MAX_SUBKEY_LEN
;
283 rc
= RegEnumKeyExW(hkey
, i
, subkey_name
, &subkey_len
, NULL
, NULL
, NULL
, NULL
);
284 if (rc
== ERROR_SUCCESS
)
286 subkey_path
= build_subkey_path(path
, path_len
, subkey_name
, subkey_len
);
287 if (!RegOpenKeyExW(hkey
, subkey_name
, 0, KEY_READ
|sam
, &subkey
))
289 export_registry_data(hFile
, subkey
, subkey_path
, sam
);
302 static void export_file_header(HANDLE hFile
)
304 static const WCHAR header
[] = L
"\xFEFFWindows Registry Editor Version 5.00\r\n";
306 write_file(hFile
, header
);
309 static HANDLE
create_file(const WCHAR
*filename
, DWORD action
)
311 return CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, action
, FILE_ATTRIBUTE_NORMAL
, NULL
);
314 static HANDLE
get_file_handle(WCHAR
*filename
, BOOL overwrite_file
)
316 HANDLE hFile
= create_file(filename
, overwrite_file
? CREATE_ALWAYS
: CREATE_NEW
);
318 if (hFile
== INVALID_HANDLE_VALUE
)
320 DWORD error
= GetLastError();
322 if (error
== ERROR_FILE_EXISTS
)
324 if (!ask_confirm(STRING_OVERWRITE_FILE
, filename
))
326 output_message(STRING_CANCELLED
);
330 hFile
= create_file(filename
, CREATE_ALWAYS
);
336 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
337 FORMAT_MESSAGE_IGNORE_INSERTS
, NULL
, error
, 0, (WCHAR
*)&str
, 0, NULL
);
338 output_writeconsole(str
, lstrlenW(str
));
347 int reg_export(int argc
, WCHAR
*argvW
[])
350 WCHAR
*path
, *key_name
;
351 BOOL overwrite_file
= FALSE
;
356 if (argc
< 4) goto invalid
;
358 if (!parse_registry_key(argvW
[2], &root
, &path
))
361 for (i
= 4; i
< argc
; i
++)
365 if (argvW
[i
][0] != '/' && argvW
[i
][0] != '-')
370 if (is_char(*str
, 'y') && !str
[1])
371 overwrite_file
= TRUE
;
372 else if (!lstrcmpiW(str
, L
"reg:32"))
374 if (sam
& KEY_WOW64_32KEY
) goto invalid
;
375 sam
|= KEY_WOW64_32KEY
;
378 else if (!lstrcmpiW(str
, L
"reg:64"))
380 if (sam
& KEY_WOW64_64KEY
) goto invalid
;
381 sam
|= KEY_WOW64_64KEY
;
388 if (sam
== (KEY_WOW64_32KEY
|KEY_WOW64_64KEY
))
391 if (RegOpenKeyExW(root
, path
, 0, KEY_READ
|sam
, &hkey
))
393 output_message(STRING_KEY_NONEXIST
);
397 key_name
= get_long_key(root
, path
);
399 hFile
= get_file_handle(argvW
[3], overwrite_file
);
400 export_file_header(hFile
);
401 ret
= export_registry_data(hFile
, hkey
, key_name
, sam
);
402 export_newline(hFile
);
410 output_message(STRING_INVALID_SYNTAX
);
411 output_message(STRING_FUNC_HELP
, wcsupr(argvW
[1]));