d3d10core/tests: Add tests for GenerateMips().
[wine.git] / programs / reg / export.c
blob622e7ca8d9465fba0fd4bcff61463ad293c1c9a2
1 /*
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
19 #include <windows.h>
20 #include <stdlib.h>
22 #include <wine/unicode.h>
23 #include <wine/heap.h>
25 #include "reg.h"
27 static void write_file(HANDLE hFile, const WCHAR *str)
29 DWORD written;
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;
37 WCHAR *buf;
39 for (i = 0, escape_count = 0; i < str_len; i++)
41 WCHAR c = str[i];
42 if (c == '\r' || c == '\n' || c == '\\' || c == '"' || c == '\0')
43 escape_count++;
46 buf = heap_xalloc((str_len + escape_count + 1) * sizeof(WCHAR));
48 for (i = 0, pos = 0; i < str_len; i++, pos++)
50 WCHAR c = str[i];
52 switch (c)
54 case '\r':
55 buf[pos++] = '\\';
56 buf[pos] = 'r';
57 break;
58 case '\n':
59 buf[pos++] = '\\';
60 buf[pos] = 'n';
61 break;
62 case '\\':
63 buf[pos++] = '\\';
64 buf[pos] = '\\';
65 break;
66 case '"':
67 buf[pos++] = '\\';
68 buf[pos] = '"';
69 break;
70 case '\0':
71 buf[pos++] = '\\';
72 buf[pos] = '0';
73 break;
74 default:
75 buf[pos] = c;
79 buf[pos] = 0;
80 *line_len = pos;
81 return buf;
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};
88 size_t line_len;
90 if (name && *name)
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);
96 heap_free(buf);
97 heap_free(str);
99 else
101 line_len = lstrlenW(default_name);
102 write_file(hFile, default_name);
105 return line_len;
108 static void export_string_data(WCHAR **buf, WCHAR *data, size_t size)
110 size_t len = 0, line_len;
111 WCHAR *str;
112 static const WCHAR fmt[] = {'"','%','s','"',0};
114 if (size)
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);
119 heap_free(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};
134 size_t line_len;
136 if (type == REG_BINARY)
138 line_len = lstrlenW(hex);
139 write_file(hFile, hex);
141 else
143 WCHAR *buf = heap_xalloc(15 * sizeof(WCHAR));
144 line_len = sprintfW(buf, hexp_fmt, type);
145 write_file(hFile, buf);
146 heap_free(buf);
149 return line_len;
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);
163 if (!size) return;
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;
172 (*buf)[pos++] = ',';
173 (*buf)[pos] = 0;
174 line_len += 3;
176 if (line_len >= MAX_HEX_CHARS)
178 write_file(hFile, *buf);
179 write_file(hFile, hex_concat);
180 line_len = 2;
181 pos = 0;
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)
196 WCHAR *buf = NULL;
197 size_t line_len = export_value_name(hFile, value_name, value_len);
199 switch (type)
201 case REG_SZ:
202 export_string_data(&buf, data, size);
203 break;
204 case REG_DWORD:
205 if (size)
207 export_dword_data(&buf, data);
208 break;
210 /* fall through */
211 case REG_NONE:
212 case REG_EXPAND_SZ:
213 case REG_BINARY:
214 case REG_MULTI_SZ:
215 default:
216 export_hex_data(hFile, &buf, type, line_len, data, size);
217 break;
220 if (size || type == REG_SZ)
222 write_file(hFile, buf);
223 heap_free(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};
232 WCHAR *buf;
234 buf = heap_xalloc((lstrlenW(name) + 7) * sizeof(WCHAR));
235 sprintfW(buf, fmt, name);
236 write_file(hFile, buf);
237 heap_free(buf);
240 static int export_registry_data(HANDLE hFile, HKEY key, WCHAR *path)
242 LONG rc;
243 DWORD max_value_len = 256, value_len;
244 DWORD max_data_bytes = 2048, data_size;
245 DWORD subkey_len;
246 DWORD i, type, path_len;
247 WCHAR *value_name, *subkey_name, *subkey_path;
248 BYTE *data;
249 HKEY subkey;
251 export_key_name(hFile, path);
253 value_name = heap_xalloc(max_value_len * sizeof(WCHAR));
254 data = heap_xalloc(max_data_bytes);
256 i = 0;
257 for (;;)
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);
266 i++;
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);
275 else
277 max_value_len *= 2;
278 value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR));
281 else break;
284 heap_free(data);
285 heap_free(value_name);
287 subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
289 path_len = lstrlenW(path);
291 i = 0;
292 for (;;)
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);
302 RegCloseKey(subkey);
304 heap_free(subkey_path);
305 i++;
307 else break;
310 heap_free(subkey_name);
311 return 0;
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);
341 exit(0);
344 hFile = create_file(filename, CREATE_ALWAYS);
346 else
348 WCHAR *str;
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));
353 LocalFree(str);
354 exit(1);
358 return hFile;
361 static BOOL is_overwrite_switch(const WCHAR *s)
363 if (strlenW(s) > 2)
364 return FALSE;
366 if ((s[0] == '/' || s[0] == '-') && (s[1] == 'y' || s[1] == 'Y'))
367 return TRUE;
369 return FALSE;
372 int reg_export(int argc, WCHAR *argv[])
374 HKEY root, hkey;
375 WCHAR *path, *long_key;
376 BOOL overwrite_file = FALSE;
377 HANDLE hFile;
378 int ret;
380 if (argc == 3 || argc > 5)
381 goto error;
383 if (!parse_registry_key(argv[2], &root, &path, &long_key))
384 return 1;
386 if (argc == 5 && !(overwrite_file = is_overwrite_switch(argv[4])))
387 goto error;
389 if (RegOpenKeyExW(root, path, 0, KEY_READ, &hkey))
391 output_message(STRING_INVALID_KEY);
392 return 1;
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);
399 CloseHandle(hFile);
401 RegCloseKey(hkey);
403 return ret;
405 error:
406 output_message(STRING_INVALID_SYNTAX);
407 output_message(STRING_FUNC_HELP, struprW(argv[1]));
408 return 1;