Signed-off-by: Hugh McMaster hugh.mcmaster@outlook.com --- programs/reg/export.c | 124 +++++++++++++++++++++++++++++++++++++++++++++-- programs/reg/tests/reg.c | 20 ++++---- 2 files changed, 131 insertions(+), 13 deletions(-)
diff --git a/programs/reg/export.c b/programs/reg/export.c index f98ca1f89b..b94d79f27a 100644 --- a/programs/reg/export.c +++ b/programs/reg/export.c @@ -33,6 +33,87 @@ static void write_file(HANDLE hFile, const WCHAR *str) WriteFile(hFile, str, lstrlenW(str) * sizeof(WCHAR), &written, NULL); }
+static WCHAR *escape_string(WCHAR *str, size_t str_len, size_t *line_len) +{ + size_t i, escape_count, pos; + WCHAR *buf; + + for (i = 0, escape_count = 0; i < str_len; i++) + { + WCHAR c = str[i]; + if (c == '\r' || c == '\n' || c == '\' || c == '"' || c == '\0') + escape_count++; + } + + buf = heap_xalloc((str_len + escape_count + 1) * sizeof(WCHAR)); + + for (i = 0, pos = 0; i < str_len; i++, pos++) + { + WCHAR c = str[i]; + + switch (c) + { + case '\r': + buf[pos++] = '\'; + buf[pos] = 'r'; + break; + case '\n': + buf[pos++] = '\'; + buf[pos] = 'n'; + break; + case '\': + buf[pos++] = '\'; + buf[pos] = '\'; + break; + case '"': + buf[pos++] = '\'; + buf[pos] = '"'; + break; + case '\0': + buf[pos++] = '\'; + buf[pos] = '0'; + break; + default: + buf[pos] = c; + } + } + + buf[pos] = 0; + *line_len = pos; + return buf; +} + +static size_t export_value_name(HANDLE hFile, WCHAR *name, size_t len) +{ + static const WCHAR quoted_fmt[] = {'"','%','s','"','=',0}; + static const WCHAR default_name[] = {'@','=',0}; + size_t line_len; + + if (name && *name) + { + WCHAR *str = escape_string(name, len, &line_len); + WCHAR *buf = heap_xalloc((line_len + 4) * sizeof(WCHAR)); + line_len = sprintfW(buf, quoted_fmt, str); + write_file(hFile, buf); + heap_free(buf); + heap_free(str); + } + else + { + line_len = lstrlenW(default_name); + write_file(hFile, default_name); + } + + return line_len; +} + +static void export_newline(HANDLE hFile) +{ + static const WCHAR newline[] = {'\r','\n',0}; + + write_file(hFile, newline); +} + static void export_key_name(HANDLE hFile, WCHAR *name) { static const WCHAR fmt[] = {'\r','\n','[','%','s',']','\r','\n',0}; @@ -44,6 +125,42 @@ static void export_key_name(HANDLE hFile, WCHAR *name) heap_free(buf); }
+static int export_registry_data(HANDLE hFile, HKEY key, WCHAR *path) +{ + LONG rc; + DWORD max_value_len = 256, value_len; + DWORD i; + WCHAR *value_name; + + export_key_name(hFile, path); + + value_name = heap_xalloc(max_value_len * sizeof(WCHAR)); + + i = 0; + for (;;) + { + value_len = max_value_len; + rc = RegEnumValueW(key, i, value_name, &value_len, NULL, NULL, NULL, NULL); + + if (rc == ERROR_SUCCESS) + { + export_value_name(hFile, value_name, value_len); + FIXME(": export of data types not yet implemented\n"); + export_newline(hFile); + i++; + } + else if (rc == ERROR_MORE_DATA) + { + max_value_len *= 2; + value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR)); + } + else break; + } + + heap_free(value_name); + return 0; +} + static void export_file_header(HANDLE hFile) { static const WCHAR header[] = { 0xfeff,'W','i','n','d','o','w','s',' ', @@ -108,6 +225,7 @@ int reg_export(int argc, WCHAR *argv[]) WCHAR *path, *long_key; BOOL overwrite_file = FALSE; HANDLE hFile; + int ret;
if (argc == 3 || argc > 5) goto error; @@ -126,13 +244,13 @@ int reg_export(int argc, WCHAR *argv[])
hFile = get_file_handle(argv[3], overwrite_file); export_file_header(hFile); - export_key_name(hFile, long_key); - FIXME(": operation not yet implemented\n"); + ret = export_registry_data(hFile, hkey, long_key); + export_newline(hFile); CloseHandle(hFile);
RegCloseKey(hkey);
- return 1; + return ret;
error: output_message(STRING_INVALID_SYNTAX); diff --git a/programs/reg/tests/reg.c b/programs/reg/tests/reg.c index 62299aa268..f1fa8e6ea5 100644 --- a/programs/reg/tests/reg.c +++ b/programs/reg/tests/reg.c @@ -4422,7 +4422,7 @@ static void test_export(void) add_key(HKEY_CURRENT_USER, KEY_BASE, &hkey);
run_reg_exe("reg export HKEY_CURRENT_USER\" KEY_BASE " file.reg", &r); - todo_wine ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); + ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
os_version = GetVersion(); major_version = LOBYTE(LOWORD(os_version)); @@ -4437,12 +4437,12 @@ static void test_export(void) ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
run_reg_exe("reg export HKEY_CURRENT_USER\" KEY_BASE " file.reg /y", &r); - todo_wine ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); + ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); } else /* Windows XP (32-bit) and older */ win_skip("File overwrite flag [/y] not supported; skipping position tests\n");
- ok(compare_export("file.reg", empty_key_test, TODO_REG_COMPARE), "compare_export() failed\n"); + ok(compare_export("file.reg", empty_key_test, 0), "compare_export() failed\n");
/* Test registry export with a simple data structure */ dword = 0x100; @@ -4450,7 +4450,7 @@ static void test_export(void) add_value(hkey, "String", REG_SZ, "Your text here...", 18);
run_reg_exe("reg export HKEY_CURRENT_USER\" KEY_BASE " file.reg", &r); - todo_wine ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); + ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); ok(compare_export("file.reg", simple_test, TODO_REG_COMPARE), "compare_export() failed\n");
/* Test registry export with a complex data structure */ @@ -4488,7 +4488,7 @@ static void test_export(void) RegCloseKey(hkey);
run_reg_exe("reg export HKEY_CURRENT_USER\" KEY_BASE " file.reg", &r); - todo_wine ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); + ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); ok(compare_export("file.reg", complex_test, TODO_REG_COMPARE), "compare_export() failed\n");
err = delete_tree(HKEY_CURRENT_USER, KEY_BASE); @@ -4502,7 +4502,7 @@ static void test_export(void) RegCloseKey(subkey);
run_reg_exe("reg export HKEY_CURRENT_USER\" KEY_BASE " file.reg", &r); - todo_wine ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); + ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); ok(compare_export("file.reg", key_order_test, TODO_REG_COMPARE), "compare_export() failed\n");
delete_key(hkey, "Subkey1"); @@ -4517,7 +4517,7 @@ static void test_export(void) RegCloseKey(hkey);
run_reg_exe("reg export HKEY_CURRENT_USER\" KEY_BASE " file.reg", &r); - todo_wine ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); + ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); ok(compare_export("file.reg", value_order_test, TODO_REG_COMPARE), "compare_export() failed\n");
delete_key(HKEY_CURRENT_USER, KEY_BASE); @@ -4535,7 +4535,7 @@ static void test_export(void) RegCloseKey(hkey);
run_reg_exe("reg export HKEY_CURRENT_USER\" KEY_BASE " file.reg", &r); - todo_wine ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); + ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); ok(compare_export("file.reg", empty_hex_test, TODO_REG_COMPARE), "compare_export() failed\n");
delete_key(HKEY_CURRENT_USER, KEY_BASE); @@ -4553,7 +4553,7 @@ static void test_export(void) RegCloseKey(hkey);
run_reg_exe("reg export HKEY_CURRENT_USER\" KEY_BASE " file.reg", &r); - todo_wine ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); + ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); ok(compare_export("file.reg", empty_hex_test2, TODO_REG_COMPARE), "compare_export() failed\n");
delete_key(HKEY_CURRENT_USER, KEY_BASE); @@ -4572,7 +4572,7 @@ static void test_export(void) RegCloseKey(hkey);
run_reg_exe("reg export HKEY_CURRENT_USER\" KEY_BASE " file.reg", &r); - todo_wine ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); + ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); ok(compare_export("file.reg", hex_types_test, TODO_REG_COMPARE), "compare_export() failed\n");
delete_key(HKEY_CURRENT_USER, KEY_BASE);