diff --git a/base/applications/cmdutils/reg/CMakeLists.txt b/base/applications/cmdutils/reg/CMakeLists.txt index 56abc0f0ea9..53d1fa4c2fb 100644 --- a/base/applications/cmdutils/reg/CMakeLists.txt +++ b/base/applications/cmdutils/reg/CMakeLists.txt @@ -2,7 +2,7 @@ remove_definitions(-D_WIN32_WINNT=0x502) add_definitions(-D_WIN32_WINNT=0x600) -add_executable(reg import.c reg.c reg.rc) +add_executable(reg export.c import.c reg.c reg.rc) set_module_type(reg win32cui UNICODE) target_link_libraries(reg wine) add_importlibs(reg advapi32 advapi32_vista user32 msvcrt kernel32 ntdll) diff --git a/base/applications/cmdutils/reg/export.c b/base/applications/cmdutils/reg/export.c new file mode 100644 index 00000000000..24b9dc83748 --- /dev/null +++ b/base/applications/cmdutils/reg/export.c @@ -0,0 +1,410 @@ +/* + * Copyright 2017 Hugh McMaster + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include + +#include "reg.h" + +static void write_file(HANDLE hFile, const WCHAR *str) +{ + DWORD written; + + 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_string_data(WCHAR **buf, WCHAR *data, size_t size) +{ + size_t len = 0, line_len; + WCHAR *str; + static const WCHAR fmt[] = {'"','%','s','"',0}; + + if (size) + len = size / sizeof(WCHAR) - 1; + str = escape_string(data, len, &line_len); + *buf = heap_xalloc((line_len + 3) * sizeof(WCHAR)); + sprintfW(*buf, fmt, str); + heap_free(str); +} + +static void export_dword_data(WCHAR **buf, DWORD *data) +{ + static const WCHAR fmt[] = {'d','w','o','r','d',':','%','0','8','x',0}; + + *buf = heap_xalloc(15 * sizeof(WCHAR)); + sprintfW(*buf, fmt, *data); +} + +static size_t export_hex_data_type(HANDLE hFile, DWORD type) +{ + static const WCHAR hex[] = {'h','e','x',':',0}; + static const WCHAR hexp_fmt[] = {'h','e','x','(','%','x',')',':',0}; + size_t line_len; + + if (type == REG_BINARY) + { + line_len = lstrlenW(hex); + write_file(hFile, hex); + } + else + { + WCHAR *buf = heap_xalloc(15 * sizeof(WCHAR)); + line_len = sprintfW(buf, hexp_fmt, type); + write_file(hFile, buf); + heap_free(buf); + } + + return line_len; +} + +#define MAX_HEX_CHARS 77 + +static void export_hex_data(HANDLE hFile, WCHAR **buf, DWORD type, + DWORD line_len, void *data, DWORD size) +{ + static const WCHAR fmt[] = {'%','0','2','x',0}; + static const WCHAR hex_concat[] = {'\\','\r','\n',' ',' ',0}; + size_t num_commas, i, pos; + + line_len += export_hex_data_type(hFile, type); + + if (!size) return; + + num_commas = size - 1; + *buf = heap_xalloc(size * 3 * sizeof(WCHAR)); + + for (i = 0, pos = 0; i < size; i++) + { + pos += sprintfW(*buf + pos, fmt, ((BYTE *)data)[i]); + if (i == num_commas) break; + (*buf)[pos++] = ','; + (*buf)[pos] = 0; + line_len += 3; + + if (line_len >= MAX_HEX_CHARS) + { + write_file(hFile, *buf); + write_file(hFile, hex_concat); + line_len = 2; + pos = 0; + } + } +} + +static void export_newline(HANDLE hFile) +{ + static const WCHAR newline[] = {'\r','\n',0}; + + write_file(hFile, newline); +} + +static void export_data(HANDLE hFile, WCHAR *value_name, DWORD value_len, + DWORD type, void *data, size_t size) +{ + WCHAR *buf = NULL; + size_t line_len = export_value_name(hFile, value_name, value_len); + + switch (type) + { + case REG_SZ: + export_string_data(&buf, data, size); + break; + case REG_DWORD: + if (size) + { + export_dword_data(&buf, data); + break; + } + /* fall through */ + case REG_NONE: + case REG_EXPAND_SZ: + case REG_BINARY: + case REG_MULTI_SZ: + default: + export_hex_data(hFile, &buf, type, line_len, data, size); + break; + } + + if (size || type == REG_SZ) + { + write_file(hFile, buf); + heap_free(buf); + } + + export_newline(hFile); +} + +static void export_key_name(HANDLE hFile, WCHAR *name) +{ + static const WCHAR fmt[] = {'\r','\n','[','%','s',']','\r','\n',0}; + WCHAR *buf; + + buf = heap_xalloc((lstrlenW(name) + 7) * sizeof(WCHAR)); + sprintfW(buf, fmt, name); + write_file(hFile, buf); + heap_free(buf); +} + +static int export_registry_data(HANDLE hFile, HKEY key, WCHAR *path) +{ + LONG rc; + DWORD max_value_len = 256, value_len; + DWORD max_data_bytes = 2048, data_size; + DWORD subkey_len; + DWORD i, type, path_len; + WCHAR *value_name, *subkey_name, *subkey_path; + BYTE *data; + HKEY subkey; + + export_key_name(hFile, path); + + value_name = heap_xalloc(max_value_len * sizeof(WCHAR)); + data = heap_xalloc(max_data_bytes); + + i = 0; + for (;;) + { + value_len = max_value_len; + data_size = max_data_bytes; + rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size); + + if (rc == ERROR_SUCCESS) + { + export_data(hFile, value_name, value_len, type, data, data_size); + i++; + } + else if (rc == ERROR_MORE_DATA) + { + if (data_size > max_data_bytes) + { + max_data_bytes = data_size; + data = heap_xrealloc(data, max_data_bytes); + } + else + { + max_value_len *= 2; + value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR)); + } + } + else break; + } + + heap_free(data); + heap_free(value_name); + + subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); + + path_len = lstrlenW(path); + + i = 0; + for (;;) + { + subkey_len = MAX_SUBKEY_LEN; + rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); + if (rc == ERROR_SUCCESS) + { + subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len); + if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey)) + { + export_registry_data(hFile, subkey, subkey_path); + RegCloseKey(subkey); + } + heap_free(subkey_path); + i++; + } + else break; + } + + heap_free(subkey_name); + return 0; +} + +static void export_file_header(HANDLE hFile) +{ + static const WCHAR header[] = { 0xfeff,'W','i','n','d','o','w','s',' ', + 'R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ', + 'V','e','r','s','i','o','n',' ','5','.','0','0','\r','\n'}; + + write_file(hFile, header); +} + +static HANDLE create_file(const WCHAR *filename, DWORD action) +{ + return CreateFileW(filename, GENERIC_WRITE, 0, NULL, action, FILE_ATTRIBUTE_NORMAL, NULL); +} + +static HANDLE get_file_handle(WCHAR *filename, BOOL overwrite_file) +{ + HANDLE hFile = create_file(filename, overwrite_file ? CREATE_ALWAYS : CREATE_NEW); + + if (hFile == INVALID_HANDLE_VALUE) + { + DWORD error = GetLastError(); + + if (error == ERROR_FILE_EXISTS) + { + if (!ask_confirm(STRING_OVERWRITE_FILE, filename)) + { + output_message(STRING_CANCELLED); + exit(0); + } + + hFile = create_file(filename, CREATE_ALWAYS); + } + else + { + WCHAR *str; + + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (WCHAR *)&str, 0, NULL); + output_writeconsole(str, lstrlenW(str)); + LocalFree(str); + exit(1); + } + } + + return hFile; +} + +static BOOL is_overwrite_switch(const WCHAR *s) +{ + if (strlenW(s) > 2) + return FALSE; + + if ((s[0] == '/' || s[0] == '-') && (s[1] == 'y' || s[1] == 'Y')) + return TRUE; + + return FALSE; +} + +int reg_export(int argc, WCHAR *argv[]) +{ + HKEY root, hkey; + WCHAR *path, *long_key; + BOOL overwrite_file = FALSE; + HANDLE hFile; + int ret; + + if (argc == 3 || argc > 5) + goto error; + + if (!parse_registry_key(argv[2], &root, &path, &long_key)) + return 1; + + if (argc == 5 && !(overwrite_file = is_overwrite_switch(argv[4]))) + goto error; + + if (RegOpenKeyExW(root, path, 0, KEY_READ, &hkey)) + { + output_message(STRING_INVALID_KEY); + return 1; + } + + hFile = get_file_handle(argv[3], overwrite_file); + export_file_header(hFile); + ret = export_registry_data(hFile, hkey, long_key); + export_newline(hFile); + CloseHandle(hFile); + + RegCloseKey(hkey); + + return ret; + +error: + output_message(STRING_INVALID_SYNTAX); + output_message(STRING_FUNC_HELP, struprW(argv[1])); + return 1; +} diff --git a/base/applications/cmdutils/reg/import.c b/base/applications/cmdutils/reg/import.c index 8825765c6d2..c4c988d7d1d 100644 --- a/base/applications/cmdutils/reg/import.c +++ b/base/applications/cmdutils/reg/import.c @@ -785,6 +785,9 @@ static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos) { WCHAR *line = pos; + if (!*line) + goto set_value; + if (!convert_hex_csv_to_hex(parser, &line)) goto invalid; @@ -796,6 +799,7 @@ static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos) prepare_hex_string_data(parser); +set_value: set_state(parser, SET_VALUE); return line; diff --git a/base/applications/cmdutils/reg/lang/bg-BG.rc b/base/applications/cmdutils/reg/lang/bg-BG.rc index 884d55ee374..23fbfb02552 100644 --- a/base/applications/cmdutils/reg/lang/bg-BG.rc +++ b/base/applications/cmdutils/reg/lang/bg-BG.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/cs-CZ.rc b/base/applications/cmdutils/reg/lang/cs-CZ.rc index f75f8fb36a7..ab9bfde01ef 100644 --- a/base/applications/cmdutils/reg/lang/cs-CZ.rc +++ b/base/applications/cmdutils/reg/lang/cs-CZ.rc @@ -42,4 +42,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/da-DK.rc b/base/applications/cmdutils/reg/lang/da-DK.rc index a1519024211..6c8338ca0f2 100644 --- a/base/applications/cmdutils/reg/lang/da-DK.rc +++ b/base/applications/cmdutils/reg/lang/da-DK.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/de-DE.rc b/base/applications/cmdutils/reg/lang/de-DE.rc index 083b7e73c1b..ec0cd460ed2 100644 --- a/base/applications/cmdutils/reg/lang/de-DE.rc +++ b/base/applications/cmdutils/reg/lang/de-DE.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/en-US.rc b/base/applications/cmdutils/reg/lang/en-US.rc index 3aae61e02c5..9c9bef54ed2 100644 --- a/base/applications/cmdutils/reg/lang/en-US.rc +++ b/base/applications/cmdutils/reg/lang/en-US.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/es-ES.rc b/base/applications/cmdutils/reg/lang/es-ES.rc index ea9cb3bd273..60bb78af8e4 100644 --- a/base/applications/cmdutils/reg/lang/es-ES.rc +++ b/base/applications/cmdutils/reg/lang/es-ES.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/fr-FR.rc b/base/applications/cmdutils/reg/lang/fr-FR.rc index 3e891d3186e..89aceb90799 100644 --- a/base/applications/cmdutils/reg/lang/fr-FR.rc +++ b/base/applications/cmdutils/reg/lang/fr-FR.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/it-IT.rc b/base/applications/cmdutils/reg/lang/it-IT.rc index 63cbc5c803d..c2ad7f34e53 100644 --- a/base/applications/cmdutils/reg/lang/it-IT.rc +++ b/base/applications/cmdutils/reg/lang/it-IT.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/ja-JP.rc b/base/applications/cmdutils/reg/lang/ja-JP.rc index 7b1c018fbfe..07e7fd73bf6 100644 --- a/base/applications/cmdutils/reg/lang/ja-JP.rc +++ b/base/applications/cmdutils/reg/lang/ja-JP.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/ko-KR.rc b/base/applications/cmdutils/reg/lang/ko-KR.rc index 2bbe277d1a5..ba9af4b55a5 100644 --- a/base/applications/cmdutils/reg/lang/ko-KR.rc +++ b/base/applications/cmdutils/reg/lang/ko-KR.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/lt-LT.rc b/base/applications/cmdutils/reg/lang/lt-LT.rc index 75bbcc21d84..c8feef0d973 100644 --- a/base/applications/cmdutils/reg/lang/lt-LT.rc +++ b/base/applications/cmdutils/reg/lang/lt-LT.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/nl-NL.rc b/base/applications/cmdutils/reg/lang/nl-NL.rc index b2fb857f896..a62f1780fa1 100644 --- a/base/applications/cmdutils/reg/lang/nl-NL.rc +++ b/base/applications/cmdutils/reg/lang/nl-NL.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/no-NO.rc b/base/applications/cmdutils/reg/lang/no-NO.rc index 5d6b79e0b9b..b9c269e1c30 100644 --- a/base/applications/cmdutils/reg/lang/no-NO.rc +++ b/base/applications/cmdutils/reg/lang/no-NO.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/pl-PL.rc b/base/applications/cmdutils/reg/lang/pl-PL.rc index e3d2116fb61..92f98dccae6 100644 --- a/base/applications/cmdutils/reg/lang/pl-PL.rc +++ b/base/applications/cmdutils/reg/lang/pl-PL.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/pt-PT.rc b/base/applications/cmdutils/reg/lang/pt-PT.rc index f6ee64dd826..dd39615452e 100644 --- a/base/applications/cmdutils/reg/lang/pt-PT.rc +++ b/base/applications/cmdutils/reg/lang/pt-PT.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/ro-RO.rc b/base/applications/cmdutils/reg/lang/ro-RO.rc index ebcbe182c03..5c613624d9b 100644 --- a/base/applications/cmdutils/reg/lang/ro-RO.rc +++ b/base/applications/cmdutils/reg/lang/ro-RO.rc @@ -43,4 +43,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/ru-RU.rc b/base/applications/cmdutils/reg/lang/ru-RU.rc index 04ad38c66e6..f8d3d8afbec 100644 --- a/base/applications/cmdutils/reg/lang/ru-RU.rc +++ b/base/applications/cmdutils/reg/lang/ru-RU.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/sl-SI.rc b/base/applications/cmdutils/reg/lang/sl-SI.rc index e7d631e80b8..cd22ffe74c5 100644 --- a/base/applications/cmdutils/reg/lang/sl-SI.rc +++ b/base/applications/cmdutils/reg/lang/sl-SI.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/sq-AL.rc b/base/applications/cmdutils/reg/lang/sq-AL.rc index 3b0dba526f8..2c4d2f5f4c8 100644 --- a/base/applications/cmdutils/reg/lang/sq-AL.rc +++ b/base/applications/cmdutils/reg/lang/sq-AL.rc @@ -41,4 +41,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/sv-SE.rc b/base/applications/cmdutils/reg/lang/sv-SE.rc index 774bf958144..978e704c6ad 100644 --- a/base/applications/cmdutils/reg/lang/sv-SE.rc +++ b/base/applications/cmdutils/reg/lang/sv-SE.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/tr-TR.rc b/base/applications/cmdutils/reg/lang/tr-TR.rc index 9061740de68..e46733002c3 100644 --- a/base/applications/cmdutils/reg/lang/tr-TR.rc +++ b/base/applications/cmdutils/reg/lang/tr-TR.rc @@ -39,4 +39,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/uk-UA.rc b/base/applications/cmdutils/reg/lang/uk-UA.rc index b5a8b68e6d1..7ca1cff6a5c 100644 --- a/base/applications/cmdutils/reg/lang/uk-UA.rc +++ b/base/applications/cmdutils/reg/lang/uk-UA.rc @@ -37,4 +37,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/zh-CN.rc b/base/applications/cmdutils/reg/lang/zh-CN.rc index c952714bd1b..6dbe3759634 100644 --- a/base/applications/cmdutils/reg/lang/zh-CN.rc +++ b/base/applications/cmdutils/reg/lang/zh-CN.rc @@ -39,4 +39,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/lang/zh-TW.rc b/base/applications/cmdutils/reg/lang/zh-TW.rc index e6c5a6e8ee6..b9cff9a2838 100644 --- a/base/applications/cmdutils/reg/lang/zh-TW.rc +++ b/base/applications/cmdutils/reg/lang/zh-TW.rc @@ -39,4 +39,7 @@ STRINGTABLE STRING_FILE_NOT_FOUND, "reg: The file '%1' was not found.\n" STRING_OPEN_KEY_FAILED, "reg: Unable to open the registry key '%1'.\n" STRING_ESCAPE_SEQUENCE, "reg: Unrecognized escape sequence [\\%1!c!]\n" + STRING_EXPORT_USAGE, "REG EXPORT key_name file.reg [/y]\n" + STRING_INVALID_SYSTEM_KEY, "reg: Invalid system key [%1]\n" + STRING_OVERWRITE_FILE, "The file '%1' already exists. Do you want to overwrite it?" } diff --git a/base/applications/cmdutils/reg/reg.c b/base/applications/cmdutils/reg/reg.c index 5a857dea952..b9db08e787d 100644 --- a/base/applications/cmdutils/reg/reg.c +++ b/base/applications/cmdutils/reg/reg.c @@ -81,6 +81,8 @@ type_rels[] = {REG_MULTI_SZ, type_multi_sz}, }; +static const WCHAR newlineW[] = {'\n',0}; + void *heap_xalloc(size_t size) { void *buf = HeapAlloc(GetProcessHeap(), 0, size); @@ -115,7 +117,7 @@ BOOL heap_free(void *buf) return HeapFree(GetProcessHeap(), 0, buf); } -static void output_writeconsole(const WCHAR *str, DWORD wlen) +void output_writeconsole(const WCHAR *str, DWORD wlen) { DWORD count, ret; @@ -155,7 +157,7 @@ static void output_formatstring(const WCHAR *fmt, __ms_va_list va_args) LocalFree(str); } -void __cdecl output_message(unsigned int id, ...) +void WINAPIV output_message(unsigned int id, ...) { WCHAR fmt[1024]; __ms_va_list va_args; @@ -170,7 +172,7 @@ void __cdecl output_message(unsigned int id, ...) __ms_va_end(va_args); } -static void __cdecl output_string(const WCHAR *fmt, ...) +static void WINAPIV output_string(const WCHAR *fmt, ...) { __ms_va_list va_args; @@ -180,7 +182,7 @@ static void __cdecl output_string(const WCHAR *fmt, ...) } /* ask_confirm() adapted from programs/cmd/builtins.c */ -static BOOL ask_confirm(unsigned int msgid, WCHAR *reg_info) +BOOL ask_confirm(unsigned int msgid, WCHAR *reg_info) { HMODULE hmod; WCHAR Ybuffer[4]; @@ -614,7 +616,6 @@ static const WCHAR *reg_type_to_wchar(DWORD type) static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size) { static const WCHAR fmt[] = {' ',' ',' ',' ','%','1',0}; - static const WCHAR newlineW[] = {'\n',0}; WCHAR defval[32]; WCHAR *reg_data; @@ -641,7 +642,7 @@ static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD output_string(newlineW); } -static WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len) +WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len) { WCHAR *subkey_path; static const WCHAR fmt[] = {'%','s','\\','%','s',0}; @@ -654,8 +655,6 @@ static WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, static unsigned int num_values_found = 0; -#define MAX_SUBKEY_LEN 257 - static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse) { LONG rc; @@ -664,7 +663,6 @@ static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse) DWORD type, path_len, i; BYTE *data; WCHAR fmt[] = {'%','1','\n',0}; - WCHAR newlineW[] = {'\n',0}; WCHAR *subkey_name, *subkey_path; HKEY subkey; @@ -744,7 +742,6 @@ static int query_all(HKEY key, WCHAR *path, BOOL recurse) WCHAR fmt[] = {'%','1','\n',0}; WCHAR fmt_path[] = {'%','1','\\','%','2','\n',0}; WCHAR *value_name, *subkey_name, *subkey_path; - WCHAR newlineW[] = {'\n',0}; BYTE *data; HKEY subkey; @@ -825,7 +822,6 @@ static int reg_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name, BOOL value_empty, BOOL recurse) { HKEY key; - WCHAR newlineW[] = {'\n',0}; int ret; if (RegOpenKeyExW(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS) @@ -877,32 +873,41 @@ static WCHAR *get_long_key(HKEY root, WCHAR *path) return long_key; } -static BOOL parse_registry_key(const WCHAR *key, HKEY *root, WCHAR **path, WCHAR **long_key) +BOOL parse_registry_key(const WCHAR *key, HKEY *root, WCHAR **path, WCHAR **long_key) { if (!sane_path(key)) return FALSE; + *path = strchrW(key, '\\'); + if (*path) (*path)++; + *root = path_get_rootkey(key); if (!*root) { - output_message(STRING_INVALID_KEY); + if (*path) *(*path - 1) = 0; + output_message(STRING_INVALID_SYSTEM_KEY, key); return FALSE; } - *path = strchrW(key, '\\'); - if (*path) (*path)++; - *long_key = get_long_key(*root, *path); return TRUE; } -static BOOL is_help_switch(const WCHAR *s) +static BOOL is_switch(const WCHAR *s, const WCHAR c) { if (strlenW(s) > 2) return FALSE; - if ((s[0] == '/' || s[0] == '-') && (s[1] == 'h' || s[1] == '?')) + if ((s[0] == '/' || s[0] == '-') && (s[1] == c || s[1] == toupperW(c))) + return TRUE; + + return FALSE; +} + +static BOOL is_help_switch(const WCHAR *s) +{ + if (is_switch(s, '?') || is_switch(s, 'h')) return TRUE; return FALSE; @@ -912,6 +917,7 @@ enum operations { REG_ADD, REG_DELETE, REG_IMPORT, + REG_EXPORT, REG_QUERY, REG_INVALID }; @@ -923,6 +929,7 @@ static enum operations get_operation(const WCHAR *str, int *op_help) static const WCHAR add[] = {'a','d','d',0}; static const WCHAR delete[] = {'d','e','l','e','t','e',0}; static const WCHAR import[] = {'i','m','p','o','r','t',0}; + static const WCHAR export[] = {'e','x','p','o','r','t',0}; static const WCHAR query[] = {'q','u','e','r','y',0}; static const struct op_info op_array[] = @@ -930,6 +937,7 @@ static enum operations get_operation(const WCHAR *str, int *op_help) { add, REG_ADD, STRING_ADD_USAGE }, { delete, REG_DELETE, STRING_DELETE_USAGE }, { import, REG_IMPORT, STRING_IMPORT_USAGE }, + { export, REG_EXPORT, STRING_EXPORT_USAGE }, { query, REG_QUERY, STRING_QUERY_USAGE }, { NULL, -1, 0 } }; @@ -998,6 +1006,9 @@ int wmain(int argc, WCHAR *argvW[]) if (op == REG_IMPORT) return reg_import(argvW[2]); + if (op == REG_EXPORT) + return reg_export(argc, argvW); + if (!parse_registry_key(argvW[2], &root, &path, &key_name)) return 1; diff --git a/base/applications/cmdutils/reg/reg.h b/base/applications/cmdutils/reg/reg.h index 14c05b13d49..eb792bbf886 100644 --- a/base/applications/cmdutils/reg/reg.h +++ b/base/applications/cmdutils/reg/reg.h @@ -22,15 +22,23 @@ #include "resource.h" #define ARRAY_SIZE(A) (sizeof(A)/sizeof(*A)) +#define MAX_SUBKEY_LEN 257 /* reg.c */ void *heap_xalloc(size_t size); void *heap_xrealloc(void *buf, size_t size); BOOL heap_free(void *buf); -void __cdecl output_message(unsigned int id, ...); +void output_writeconsole(const WCHAR *str, DWORD wlen); +void WINAPIV output_message(unsigned int id, ...); +BOOL ask_confirm(unsigned int msgid, WCHAR *reg_info); HKEY path_get_rootkey(const WCHAR *path); +WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len); +BOOL parse_registry_key(const WCHAR *key, HKEY *root, WCHAR **path, WCHAR **long_key); /* import.c */ int reg_import(const WCHAR *filename); +/* export.c */ +int reg_export(int argc, WCHAR *argv[]); + #endif /* __REG_H__ */ diff --git a/base/applications/cmdutils/reg/resource.h b/base/applications/cmdutils/reg/resource.h index 0f57663183d..84cbe906b9b 100644 --- a/base/applications/cmdutils/reg/resource.h +++ b/base/applications/cmdutils/reg/resource.h @@ -23,38 +23,41 @@ //#include /* Translation IDs. */ -#define STRING_USAGE 101 -#define STRING_ADD_USAGE 102 -#define STRING_DELETE_USAGE 103 -#define STRING_QUERY_USAGE 104 -#define STRING_SUCCESS 105 -#define STRING_INVALID_KEY 106 -#define STRING_INVALID_CMDLINE 107 -#define STRING_NO_REMOTE 108 -#define STRING_CANNOT_FIND 109 -#define STRING_UNSUPPORTED_TYPE 110 -#define STRING_MISSING_INTEGER 111 -#define STRING_MISSING_HEXDATA 112 -#define STRING_UNHANDLED_TYPE 113 -#define STRING_OVERWRITE_VALUE 114 -#define STRING_YESNO 115 -#define STRING_YES 116 -#define STRING_NO 117 -#define STRING_CANCELLED 118 -#define STRING_DEFAULT_VALUE 119 -#define STRING_DELETE_VALUE 120 -#define STRING_DELETE_VALUEALL 121 -#define STRING_DELETE_SUBKEY 122 -#define STRING_INVALID_STRING 123 -#define STRING_VALUEALL_FAILED 124 -#define STRING_GENERAL_FAILURE 125 -#define STRING_MATCHES_FOUND 126 -#define STRING_INVALID_SYNTAX 127 -#define STRING_INVALID_OPTION 128 -#define STRING_REG_HELP 129 -#define STRING_FUNC_HELP 130 -#define STRING_VALUE_NOT_SET 131 -#define STRING_IMPORT_USAGE 132 -#define STRING_FILE_NOT_FOUND 133 -#define STRING_OPEN_KEY_FAILED 134 -#define STRING_ESCAPE_SEQUENCE 135 +#define STRING_USAGE 101 +#define STRING_ADD_USAGE 102 +#define STRING_DELETE_USAGE 103 +#define STRING_QUERY_USAGE 104 +#define STRING_SUCCESS 105 +#define STRING_INVALID_KEY 106 +#define STRING_INVALID_CMDLINE 107 +#define STRING_NO_REMOTE 108 +#define STRING_CANNOT_FIND 109 +#define STRING_UNSUPPORTED_TYPE 110 +#define STRING_MISSING_INTEGER 111 +#define STRING_MISSING_HEXDATA 112 +#define STRING_UNHANDLED_TYPE 113 +#define STRING_OVERWRITE_VALUE 114 +#define STRING_YESNO 115 +#define STRING_YES 116 +#define STRING_NO 117 +#define STRING_CANCELLED 118 +#define STRING_DEFAULT_VALUE 119 +#define STRING_DELETE_VALUE 120 +#define STRING_DELETE_VALUEALL 121 +#define STRING_DELETE_SUBKEY 122 +#define STRING_INVALID_STRING 123 +#define STRING_VALUEALL_FAILED 124 +#define STRING_GENERAL_FAILURE 125 +#define STRING_MATCHES_FOUND 126 +#define STRING_INVALID_SYNTAX 127 +#define STRING_INVALID_OPTION 128 +#define STRING_REG_HELP 129 +#define STRING_FUNC_HELP 130 +#define STRING_VALUE_NOT_SET 131 +#define STRING_IMPORT_USAGE 132 +#define STRING_FILE_NOT_FOUND 133 +#define STRING_OPEN_KEY_FAILED 134 +#define STRING_ESCAPE_SEQUENCE 135 +#define STRING_EXPORT_USAGE 136 +#define STRING_INVALID_SYSTEM_KEY 137 +#define STRING_OVERWRITE_FILE 138 diff --git a/media/doc/README.WINE b/media/doc/README.WINE index 69bf99b9c66..5e66b918b0b 100644 --- a/media/doc/README.WINE +++ b/media/doc/README.WINE @@ -227,7 +227,7 @@ reactos/win32ss/printing/monitors/localmon/ui/ # Synced to WineStaging-2.9 (kno ReactOS shares the following programs with Winehq. reactos/base/applications/cmdutils/cscript # Synced to WineStaging-2.9 -reactos/base/applications/cmdutils/reg # Synced to WineStaging-2.16 +reactos/base/applications/cmdutils/reg # Synced to Wine-3.0 reactos/base/applications/cmdutils/schtasks # Synced to WineStaging-2.9 reactos/base/applications/cmdutils/taskkill # Synced to WineStaging-2.9 reactos/base/applications/cmdutils/wmic # Synced to WineStaging-2.9