diff --git a/reactos/base/applications/cmdutils/reg/CMakeLists.txt b/reactos/base/applications/cmdutils/reg/CMakeLists.txt index a851b325495..56abc0f0ea9 100644 --- a/reactos/base/applications/cmdutils/reg/CMakeLists.txt +++ b/reactos/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 reg.c reg.rc) +add_executable(reg 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/reactos/base/applications/cmdutils/reg/import.c b/reactos/base/applications/cmdutils/reg/import.c new file mode 100644 index 00000000000..8825765c6d2 --- /dev/null +++ b/reactos/base/applications/cmdutils/reg/import.c @@ -0,0 +1,1042 @@ +/* + * 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 + +#include "reg.h" + +WINE_DEFAULT_DEBUG_CHANNEL(reg); + +static WCHAR *GetWideString(const char *strA) +{ + if (strA) + { + WCHAR *strW; + int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0); + + strW = heap_xalloc(len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len); + return strW; + } + return NULL; +} + +static WCHAR *GetWideStringN(const char *strA, int size, DWORD *len) +{ + if (strA) + { + WCHAR *strW; + *len = MultiByteToWideChar(CP_ACP, 0, strA, size, NULL, 0); + + strW = heap_xalloc(*len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, strA, size, strW, *len); + return strW; + } + *len = 0; + return NULL; +} + +static WCHAR *(*get_line)(FILE *); + +/* parser definitions */ +enum parser_state +{ + HEADER, /* parsing the registry file version header */ + PARSE_WIN31_LINE, /* parsing a Windows 3.1 registry line */ + LINE_START, /* at the beginning of a registry line */ + KEY_NAME, /* parsing a key name */ + DELETE_KEY, /* deleting a registry key */ + DEFAULT_VALUE_NAME, /* parsing a default value name */ + QUOTED_VALUE_NAME, /* parsing a double-quoted value name */ + DATA_START, /* preparing for data parsing operations */ + DELETE_VALUE, /* deleting a registry value */ + DATA_TYPE, /* parsing the registry data type */ + STRING_DATA, /* parsing REG_SZ data */ + DWORD_DATA, /* parsing DWORD data */ + HEX_DATA, /* parsing REG_BINARY, REG_NONE, REG_EXPAND_SZ or REG_MULTI_SZ data */ + EOL_BACKSLASH, /* preparing to parse multiple lines of hex data */ + HEX_MULTILINE, /* parsing multiple lines of hex data */ + UNKNOWN_DATA, /* parsing an unhandled or invalid data type */ + SET_VALUE, /* adding a value to the registry */ + NB_PARSER_STATES +}; + +struct parser +{ + FILE *file; /* pointer to a registry file */ + WCHAR two_wchars[2]; /* first two characters from the encoding check */ + BOOL is_unicode; /* parsing Unicode or ASCII data */ + short int reg_version; /* registry file version */ + HKEY hkey; /* current registry key */ + WCHAR *key_name; /* current key name */ + WCHAR *value_name; /* value name */ + DWORD parse_type; /* generic data type for parsing */ + DWORD data_type; /* data type */ + void *data; /* value data */ + DWORD data_size; /* size of the data (in bytes) */ + BOOL backslash; /* TRUE if the current line contains a backslash */ + enum parser_state state; /* current parser state */ +}; + +typedef WCHAR *(*parser_state_func)(struct parser *parser, WCHAR *pos); + +/* parser state machine functions */ +static WCHAR *header_state(struct parser *parser, WCHAR *pos); +static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos); +static WCHAR *line_start_state(struct parser *parser, WCHAR *pos); +static WCHAR *key_name_state(struct parser *parser, WCHAR *pos); +static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos); +static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos); +static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos); +static WCHAR *data_start_state(struct parser *parser, WCHAR *pos); +static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos); +static WCHAR *data_type_state(struct parser *parser, WCHAR *pos); +static WCHAR *string_data_state(struct parser *parser, WCHAR *pos); +static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos); +static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos); +static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos); +static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos); +static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos); +static WCHAR *set_value_state(struct parser *parser, WCHAR *pos); + +static const parser_state_func parser_funcs[NB_PARSER_STATES] = +{ + header_state, /* HEADER */ + parse_win31_line_state, /* PARSE_WIN31_LINE */ + line_start_state, /* LINE_START */ + key_name_state, /* KEY_NAME */ + delete_key_state, /* DELETE_KEY */ + default_value_name_state, /* DEFAULT_VALUE_NAME */ + quoted_value_name_state, /* QUOTED_VALUE_NAME */ + data_start_state, /* DATA_START */ + delete_value_state, /* DELETE_VALUE */ + data_type_state, /* DATA_TYPE */ + string_data_state, /* STRING_DATA */ + dword_data_state, /* DWORD_DATA */ + hex_data_state, /* HEX_DATA */ + eol_backslash_state, /* EOL_BACKSLASH */ + hex_multiline_state, /* HEX_MULTILINE */ + unknown_data_state, /* UNKNOWN_DATA */ + set_value_state, /* SET_VALUE */ +}; + +/* set the new parser state and return the previous one */ +static inline enum parser_state set_state(struct parser *parser, enum parser_state state) +{ + enum parser_state ret = parser->state; + parser->state = state; + return ret; +} + +/****************************************************************************** + * Converts a hex representation of a DWORD into a DWORD. + */ +static BOOL convert_hex_to_dword(WCHAR *str, DWORD *dw) +{ + WCHAR *p, *end; + int count = 0; + + while (*str == ' ' || *str == '\t') str++; + if (!*str) goto error; + + p = str; + while (isxdigitW(*p)) + { + count++; + p++; + } + if (count > 8) goto error; + + end = p; + while (*p == ' ' || *p == '\t') p++; + if (*p && *p != ';') goto error; + + *end = 0; + *dw = strtoulW(str, &end, 16); + return TRUE; + +error: + return FALSE; +} + +/****************************************************************************** + * Converts comma-separated hex data into a binary string and modifies + * the input parameter to skip the concatenating backslash, if found. + * + * Returns TRUE or FALSE to indicate whether parsing was successful. + */ +static BOOL convert_hex_csv_to_hex(struct parser *parser, WCHAR **str) +{ + size_t size; + BYTE *d; + WCHAR *s; + + parser->backslash = FALSE; + + /* The worst case is 1 digit + 1 comma per byte */ + size = ((lstrlenW(*str) + 1) / 2) + parser->data_size; + parser->data = heap_xrealloc(parser->data, size); + + s = *str; + d = (BYTE *)parser->data + parser->data_size; + + while (*s) + { + WCHAR *end; + unsigned long wc; + + wc = strtoulW(s, &end, 16); + if (wc > 0xff) return FALSE; + + if (s == end && wc == 0) + { + while (*end == ' ' || *end == '\t') end++; + if (*end == '\\') + { + parser->backslash = TRUE; + *str = end + 1; + return TRUE; + } + else if (*end == ';') + return TRUE; + return FALSE; + } + + *d++ = wc; + parser->data_size++; + + if (*end && *end != ',') + { + while (*end == ' ' || *end == '\t') end++; + if (*end && *end != ';') return FALSE; + return TRUE; + } + + if (*end) end++; + s = end; + } + + return TRUE; +} + +/****************************************************************************** + * Parses the data type of the registry value being imported and modifies + * the input parameter to skip the string representation of the data type. + * + * Returns TRUE or FALSE to indicate whether a data type was found. + */ +static BOOL parse_data_type(struct parser *parser, WCHAR **line) +{ + struct data_type { const WCHAR *tag; int len; int type; int parse_type; }; + + static const WCHAR quote[] = {'"'}; + static const WCHAR hex[] = {'h','e','x',':'}; + static const WCHAR dword[] = {'d','w','o','r','d',':'}; + static const WCHAR hexp[] = {'h','e','x','('}; + + static const struct data_type data_types[] = { + /* tag len type parse type */ + { quote, 1, REG_SZ, REG_SZ }, + { hex, 4, REG_BINARY, REG_BINARY }, + { dword, 6, REG_DWORD, REG_DWORD }, + { hexp, 4, -1, REG_BINARY }, /* REG_NONE, REG_EXPAND_SZ, REG_MULTI_SZ */ + { NULL, 0, 0, 0 } + }; + + const struct data_type *ptr; + + for (ptr = data_types; ptr->tag; ptr++) + { + if (strncmpW(ptr->tag, *line, ptr->len)) + continue; + + parser->parse_type = ptr->parse_type; + parser->data_type = ptr->parse_type; + *line += ptr->len; + + if (ptr->type == -1) + { + WCHAR *end; + DWORD val; + + if (!**line || tolowerW((*line)[1]) == 'x') + return FALSE; + + /* "hex(xx):" is special */ + val = wcstoul(*line, &end, 16); + if (*end != ')' || *(end + 1) != ':' || (val == ~0u && errno == ERANGE)) + return FALSE; + + parser->data_type = val; + *line = end + 2; + } + return TRUE; + } + return FALSE; +} + +/****************************************************************************** + * Replaces escape sequences with their character equivalents and + * null-terminates the string on the first non-escaped double quote. + * + * Assigns a pointer to the remaining unparsed data in the line. + * Returns TRUE or FALSE to indicate whether a closing double quote was found. + */ +static BOOL unescape_string(WCHAR *str, WCHAR **unparsed) +{ + int str_idx = 0; /* current character under analysis */ + int val_idx = 0; /* the last character of the unescaped string */ + int len = lstrlenW(str); + BOOL ret; + + for (str_idx = 0; str_idx < len; str_idx++, val_idx++) + { + if (str[str_idx] == '\\') + { + str_idx++; + switch (str[str_idx]) + { + case 'n': + str[val_idx] = '\n'; + break; + case 'r': + str[val_idx] = '\r'; + break; + case '0': + str[val_idx] = '\0'; + break; + case '\\': + case '"': + str[val_idx] = str[str_idx]; + break; + default: + if (!str[str_idx]) return FALSE; + output_message(STRING_ESCAPE_SEQUENCE, str[str_idx]); + str[val_idx] = str[str_idx]; + break; + } + } + else if (str[str_idx] == '"') + break; + else + str[val_idx] = str[str_idx]; + } + + ret = (str[str_idx] == '"'); + *unparsed = str + str_idx + 1; + str[val_idx] = '\0'; + return ret; +} + +static HKEY parse_key_name(WCHAR *key_name, WCHAR **key_path) +{ + if (!key_name) return 0; + + *key_path = strchrW(key_name, '\\'); + if (*key_path) (*key_path)++; + + return path_get_rootkey(key_name); +} + +static void close_key(struct parser *parser) +{ + if (parser->hkey) + { + heap_free(parser->key_name); + parser->key_name = NULL; + + RegCloseKey(parser->hkey); + parser->hkey = NULL; + } +} + +static LONG open_key(struct parser *parser, WCHAR *path) +{ + HKEY key_class; + WCHAR *key_path; + LONG res; + + close_key(parser); + + /* Get the registry class */ + if (!path || !(key_class = parse_key_name(path, &key_path))) + return ERROR_INVALID_PARAMETER; + + res = RegCreateKeyExW(key_class, key_path, 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, NULL, &parser->hkey, NULL); + + if (res == ERROR_SUCCESS) + { + parser->key_name = heap_xalloc((lstrlenW(path) + 1) * sizeof(WCHAR)); + lstrcpyW(parser->key_name, path); + } + else + parser->hkey = NULL; + + return res; +} + +static void free_parser_data(struct parser *parser) +{ + if (parser->parse_type == REG_DWORD || parser->parse_type == REG_BINARY) + heap_free(parser->data); + + parser->data = NULL; + parser->data_size = 0; +} + +static void prepare_hex_string_data(struct parser *parser) +{ + if (parser->data_type == REG_EXPAND_SZ || parser->data_type == REG_MULTI_SZ) + { + if (parser->is_unicode) + { + WCHAR *data = parser->data; + DWORD len = parser->data_size / sizeof(WCHAR); + + if (data[len - 1] != 0) + { + data[len] = 0; + parser->data_size += sizeof(WCHAR); + } + } + else + { + BYTE *data = parser->data; + + if (data[parser->data_size - 1] != 0) + { + data[parser->data_size] = 0; + parser->data_size++; + } + + parser->data = GetWideStringN(parser->data, parser->data_size, &parser->data_size); + parser->data_size *= sizeof(WCHAR); + heap_free(data); + } + } +} + +enum reg_versions { + REG_VERSION_31, + REG_VERSION_40, + REG_VERSION_50, + REG_VERSION_FUZZY, + REG_VERSION_INVALID +}; + +static enum reg_versions parse_file_header(const WCHAR *s) +{ + static const WCHAR header_31[] = {'R','E','G','E','D','I','T',0}; + static const WCHAR header_40[] = {'R','E','G','E','D','I','T','4',0}; + static const WCHAR header_50[] = {'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',0}; + + while (*s == ' ' || *s == '\t') s++; + + if (!strcmpW(s, header_31)) + return REG_VERSION_31; + + if (!strcmpW(s, header_40)) + return REG_VERSION_40; + + if (!strcmpW(s, header_50)) + return REG_VERSION_50; + + /* The Windows version accepts registry file headers beginning with "REGEDIT" and ending + * with other characters, as long as "REGEDIT" appears at the start of the line. For example, + * "REGEDIT 4", "REGEDIT9" and "REGEDIT4FOO" are all treated as valid file headers. + * In all such cases, however, the contents of the registry file are not imported. + */ + if (!strncmpW(s, header_31, 7)) /* "REGEDIT" without NUL */ + return REG_VERSION_FUZZY; + + return REG_VERSION_INVALID; +} + +/* handler for parser HEADER state */ +static WCHAR *header_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *line, *header; + + if (!(line = get_line(parser->file))) + return NULL; + + if (!parser->is_unicode) + { + header = heap_xalloc((lstrlenW(line) + 3) * sizeof(WCHAR)); + header[0] = parser->two_wchars[0]; + header[1] = parser->two_wchars[1]; + lstrcpyW(header + 2, line); + parser->reg_version = parse_file_header(header); + heap_free(header); + } + else parser->reg_version = parse_file_header(line); + + switch (parser->reg_version) + { + case REG_VERSION_31: + set_state(parser, PARSE_WIN31_LINE); + break; + case REG_VERSION_40: + case REG_VERSION_50: + set_state(parser, LINE_START); + break; + default: + get_line(NULL); /* Reset static variables */ + return NULL; + } + + return line; +} + +/* handler for parser PARSE_WIN31_LINE state */ +static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *line, *value; + static WCHAR hkcr[] = {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T'}; + unsigned int key_end = 0; + + if (!(line = get_line(parser->file))) + return NULL; + + if (strncmpW(line, hkcr, ARRAY_SIZE(hkcr))) + return line; + + /* get key name */ + while (line[key_end] && !isspaceW(line[key_end])) key_end++; + + value = line + key_end; + while (*value == ' ' || *value == '\t') value++; + + if (*value == '=') value++; + if (*value == ' ') value++; /* at most one space is skipped */ + + line[key_end] = 0; + + if (open_key(parser, line) != ERROR_SUCCESS) + { + output_message(STRING_OPEN_KEY_FAILED, line); + return line; + } + + parser->value_name = NULL; + parser->data_type = REG_SZ; + parser->data = value; + parser->data_size = (lstrlenW(value) + 1) * sizeof(WCHAR); + + set_state(parser, SET_VALUE); + return value; +} + +/* handler for parser LINE_START state */ +static WCHAR *line_start_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *line, *p; + + if (!(line = get_line(parser->file))) + return NULL; + + for (p = line; *p; p++) + { + switch (*p) + { + case '[': + set_state(parser, KEY_NAME); + return p + 1; + case '@': + set_state(parser, DEFAULT_VALUE_NAME); + return p; + case '"': + set_state(parser, QUOTED_VALUE_NAME); + return p + 1; + case ' ': + case '\t': + break; + default: + return p; + } + } + + return p; +} + +/* handler for parser KEY_NAME state */ +static WCHAR *key_name_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *p = pos, *key_end; + + if (*p == ' ' || *p == '\t' || !(key_end = strrchrW(p, ']'))) + goto done; + + *key_end = 0; + + if (*p == '-') + { + set_state(parser, DELETE_KEY); + return p + 1; + } + else if (open_key(parser, p) != ERROR_SUCCESS) + output_message(STRING_OPEN_KEY_FAILED, p); + +done: + set_state(parser, LINE_START); + return p; +} + +/* handler for parser DELETE_KEY state */ +static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *p = pos; + + close_key(parser); + + if (*p == 'H' || *p == 'h') + { + HKEY root; + WCHAR *path; + + root = parse_key_name(p, &path); + + if (root && path && *path) + RegDeleteTreeW(root, path); + } + + set_state(parser, LINE_START); + return p; +} + +/* handler for parser DEFAULT_VALUE_NAME state */ +static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos) +{ + heap_free(parser->value_name); + parser->value_name = NULL; + + set_state(parser, DATA_START); + return pos + 1; +} + +/* handler for parser QUOTED_VALUE_NAME state */ +static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *val_name = pos, *p; + + if (parser->value_name) + { + heap_free(parser->value_name); + parser->value_name = NULL; + } + + if (!unescape_string(val_name, &p)) + goto invalid; + + /* copy the value name in case we need to parse multiple lines and the buffer is overwritten */ + parser->value_name = heap_xalloc((lstrlenW(val_name) + 1) * sizeof(WCHAR)); + lstrcpyW(parser->value_name, val_name); + + set_state(parser, DATA_START); + return p; + +invalid: + set_state(parser, LINE_START); + return val_name; +} + +/* handler for parser DATA_START state */ +static WCHAR *data_start_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *p = pos; + unsigned int len; + + while (*p == ' ' || *p == '\t') p++; + if (*p != '=') goto invalid; + p++; + while (*p == ' ' || *p == '\t') p++; + + /* trim trailing whitespace */ + len = strlenW(p); + while (len > 0 && (p[len - 1] == ' ' || p[len - 1] == '\t')) len--; + p[len] = 0; + + if (*p == '-') + set_state(parser, DELETE_VALUE); + else + set_state(parser, DATA_TYPE); + return p; + +invalid: + set_state(parser, LINE_START); + return p; +} + +/* handler for parser DELETE_VALUE state */ +static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *p = pos + 1; + + while (*p == ' ' || *p == '\t') p++; + if (*p && *p != ';') goto done; + + RegDeleteValueW(parser->hkey, parser->value_name); + +done: + set_state(parser, LINE_START); + return p; +} + +/* handler for parser DATA_TYPE state */ +static WCHAR *data_type_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *line = pos; + + if (!parse_data_type(parser, &line)) + { + set_state(parser, LINE_START); + return line; + } + + switch (parser->parse_type) + { + case REG_SZ: + set_state(parser, STRING_DATA); + break; + case REG_DWORD: + set_state(parser, DWORD_DATA); + break; + case REG_BINARY: /* all hex data types, including undefined */ + set_state(parser, HEX_DATA); + break; + default: + set_state(parser, UNKNOWN_DATA); + } + + return line; +} + +/* handler for parser STRING_DATA state */ +static WCHAR *string_data_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *line; + + parser->data = pos; + + if (!unescape_string(parser->data, &line)) + goto invalid; + + while (*line == ' ' || *line == '\t') line++; + if (*line && *line != ';') goto invalid; + + parser->data_size = (lstrlenW(parser->data) + 1) * sizeof(WCHAR); + + set_state(parser, SET_VALUE); + return line; + +invalid: + free_parser_data(parser); + set_state(parser, LINE_START); + return line; +} + +/* handler for parser DWORD_DATA state */ +static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *line = pos; + + parser->data = heap_xalloc(sizeof(DWORD)); + + if (!convert_hex_to_dword(line, parser->data)) + goto invalid; + + parser->data_size = sizeof(DWORD); + + set_state(parser, SET_VALUE); + return line; + +invalid: + free_parser_data(parser); + set_state(parser, LINE_START); + return line; +} + +/* handler for parser HEX_DATA state */ +static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *line = pos; + + if (!convert_hex_csv_to_hex(parser, &line)) + goto invalid; + + if (parser->backslash) + { + set_state(parser, EOL_BACKSLASH); + return line; + } + + prepare_hex_string_data(parser); + + set_state(parser, SET_VALUE); + return line; + +invalid: + free_parser_data(parser); + set_state(parser, LINE_START); + return line; +} + +/* handler for parser EOL_BACKSLASH state */ +static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *p = pos; + + while (*p == ' ' || *p == '\t') p++; + if (*p && *p != ';') goto invalid; + + set_state(parser, HEX_MULTILINE); + return pos; + +invalid: + free_parser_data(parser); + set_state(parser, LINE_START); + return p; +} + +/* handler for parser HEX_MULTILINE state */ +static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos) +{ + WCHAR *line; + + if (!(line = get_line(parser->file))) + { + prepare_hex_string_data(parser); + set_state(parser, SET_VALUE); + return pos; + } + + while (*line == ' ' || *line == '\t') line++; + if (!*line || *line == ';') return line; + + if (!isxdigitW(*line)) goto invalid; + + set_state(parser, HEX_DATA); + return line; + +invalid: + free_parser_data(parser); + set_state(parser, LINE_START); + return line; +} + +/* handler for parser UNKNOWN_DATA state */ +static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos) +{ + FIXME("Unknown registry data type [0x%x]\n", parser->data_type); + + set_state(parser, LINE_START); + return pos; +} + +/* handler for parser SET_VALUE state */ +static WCHAR *set_value_state(struct parser *parser, WCHAR *pos) +{ + RegSetValueExW(parser->hkey, parser->value_name, 0, parser->data_type, + parser->data, parser->data_size); + + free_parser_data(parser); + + if (parser->reg_version == REG_VERSION_31) + set_state(parser, PARSE_WIN31_LINE); + else + set_state(parser, LINE_START); + + return pos; +} + +#define REG_VAL_BUF_SIZE 4096 + +static WCHAR *get_lineA(FILE *fp) +{ + static WCHAR *lineW; + static size_t size; + static char *buf, *next; + char *line; + + heap_free(lineW); + + if (!fp) goto cleanup; + + if (!size) + { + size = REG_VAL_BUF_SIZE; + buf = heap_xalloc(size); + *buf = 0; + next = buf; + } + line = next; + + while (next) + { + char *p = strpbrk(line, "\r\n"); + if (!p) + { + size_t len, count; + len = strlen(next); + memmove(buf, next, len + 1); + if (size - len < 3) + { + size *= 2; + buf = heap_xrealloc(buf, size); + } + if (!(count = fread(buf + len, 1, size - len - 1, fp))) + { + next = NULL; + lineW = GetWideString(buf); + return lineW; + } + buf[len + count] = 0; + next = buf; + line = buf; + continue; + } + next = p + 1; + if (*p == '\r' && *(p + 1) == '\n') next++; + *p = 0; + lineW = GetWideString(line); + return lineW; + } + +cleanup: + lineW = NULL; + if (size) heap_free(buf); + size = 0; + return NULL; +} + +static WCHAR *get_lineW(FILE *fp) +{ + static size_t size; + static WCHAR *buf, *next; + WCHAR *line; + + if (!fp) goto cleanup; + + if (!size) + { + size = REG_VAL_BUF_SIZE; + buf = heap_xalloc(size * sizeof(WCHAR)); + *buf = 0; + next = buf; + } + line = next; + + while (next) + { + static const WCHAR line_endings[] = {'\r','\n',0}; + WCHAR *p = strpbrkW(line, line_endings); + if (!p) + { + size_t len, count; + len = strlenW(next); + memmove(buf, next, (len + 1) * sizeof(WCHAR)); + if (size - len < 3) + { + size *= 2; + buf = heap_xrealloc(buf, size * sizeof(WCHAR)); + } + if (!(count = fread(buf + len, sizeof(WCHAR), size - len - 1, fp))) + { + next = NULL; + return buf; + } + buf[len + count] = 0; + next = buf; + line = buf; + continue; + } + next = p + 1; + if (*p == '\r' && *(p + 1) == '\n') next++; + *p = 0; + return line; + } + +cleanup: + if (size) heap_free(buf); + size = 0; + return NULL; +} + +int reg_import(const WCHAR *filename) +{ + FILE *fp; + static const WCHAR rb_mode[] = {'r','b',0}; + BYTE s[2]; + struct parser parser; + WCHAR *pos; + + fp = _wfopen(filename, rb_mode); + if (!fp) + { + output_message(STRING_FILE_NOT_FOUND, filename); + return 1; + } + + if (fread(s, sizeof(WCHAR), 1, fp) != 1) + goto error; + + parser.is_unicode = (s[0] == 0xff && s[1] == 0xfe); + get_line = parser.is_unicode ? get_lineW : get_lineA; + + parser.file = fp; + parser.two_wchars[0] = s[0]; + parser.two_wchars[1] = s[1]; + parser.reg_version = -1; + parser.hkey = NULL; + parser.key_name = NULL; + parser.value_name = NULL; + parser.parse_type = 0; + parser.data_type = 0; + parser.data = NULL; + parser.data_size = 0; + parser.backslash = FALSE; + parser.state = HEADER; + + pos = parser.two_wchars; + + /* parser main loop */ + while (pos) + pos = (parser_funcs[parser.state])(&parser, pos); + + if (parser.reg_version == REG_VERSION_INVALID) + goto error; + + heap_free(parser.value_name); + close_key(&parser); + + fclose(fp); + return 0; + +error: + fclose(fp); + return 1; +} diff --git a/reactos/base/applications/cmdutils/reg/lang/bg-BG.rc b/reactos/base/applications/cmdutils/reg/lang/bg-BG.rc index 7c6c3393aee..884d55ee374 100644 --- a/reactos/base/applications/cmdutils/reg/lang/bg-BG.rc +++ b/reactos/base/applications/cmdutils/reg/lang/bg-BG.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/cs-CZ.rc b/reactos/base/applications/cmdutils/reg/lang/cs-CZ.rc index 275d923533d..f75f8fb36a7 100644 --- a/reactos/base/applications/cmdutils/reg/lang/cs-CZ.rc +++ b/reactos/base/applications/cmdutils/reg/lang/cs-CZ.rc @@ -38,4 +38,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/da-DK.rc b/reactos/base/applications/cmdutils/reg/lang/da-DK.rc index 1e34bb4e1de..a1519024211 100644 --- a/reactos/base/applications/cmdutils/reg/lang/da-DK.rc +++ b/reactos/base/applications/cmdutils/reg/lang/da-DK.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/de-DE.rc b/reactos/base/applications/cmdutils/reg/lang/de-DE.rc index cb29bfa3080..083b7e73c1b 100644 --- a/reactos/base/applications/cmdutils/reg/lang/de-DE.rc +++ b/reactos/base/applications/cmdutils/reg/lang/de-DE.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/en-US.rc b/reactos/base/applications/cmdutils/reg/lang/en-US.rc index 865ee7413e5..3aae61e02c5 100644 --- a/reactos/base/applications/cmdutils/reg/lang/en-US.rc +++ b/reactos/base/applications/cmdutils/reg/lang/en-US.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/es-ES.rc b/reactos/base/applications/cmdutils/reg/lang/es-ES.rc index fbb8b5a505a..ea9cb3bd273 100644 --- a/reactos/base/applications/cmdutils/reg/lang/es-ES.rc +++ b/reactos/base/applications/cmdutils/reg/lang/es-ES.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/fr-FR.rc b/reactos/base/applications/cmdutils/reg/lang/fr-FR.rc index 0fbcdadf09e..3e891d3186e 100644 --- a/reactos/base/applications/cmdutils/reg/lang/fr-FR.rc +++ b/reactos/base/applications/cmdutils/reg/lang/fr-FR.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/it-IT.rc b/reactos/base/applications/cmdutils/reg/lang/it-IT.rc index b558875a01e..63cbc5c803d 100644 --- a/reactos/base/applications/cmdutils/reg/lang/it-IT.rc +++ b/reactos/base/applications/cmdutils/reg/lang/it-IT.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/ja-JP.rc b/reactos/base/applications/cmdutils/reg/lang/ja-JP.rc index d818ede0a41..7b1c018fbfe 100644 --- a/reactos/base/applications/cmdutils/reg/lang/ja-JP.rc +++ b/reactos/base/applications/cmdutils/reg/lang/ja-JP.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/ko-KR.rc b/reactos/base/applications/cmdutils/reg/lang/ko-KR.rc index 6d37ab70973..2bbe277d1a5 100644 --- a/reactos/base/applications/cmdutils/reg/lang/ko-KR.rc +++ b/reactos/base/applications/cmdutils/reg/lang/ko-KR.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/lt-LT.rc b/reactos/base/applications/cmdutils/reg/lang/lt-LT.rc index fbe54fdeea3..75bbcc21d84 100644 --- a/reactos/base/applications/cmdutils/reg/lang/lt-LT.rc +++ b/reactos/base/applications/cmdutils/reg/lang/lt-LT.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/nl-NL.rc b/reactos/base/applications/cmdutils/reg/lang/nl-NL.rc index 930fbbda2c7..b2fb857f896 100644 --- a/reactos/base/applications/cmdutils/reg/lang/nl-NL.rc +++ b/reactos/base/applications/cmdutils/reg/lang/nl-NL.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/no-NO.rc b/reactos/base/applications/cmdutils/reg/lang/no-NO.rc index 38ee867f9c1..5d6b79e0b9b 100644 --- a/reactos/base/applications/cmdutils/reg/lang/no-NO.rc +++ b/reactos/base/applications/cmdutils/reg/lang/no-NO.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/pl-PL.rc b/reactos/base/applications/cmdutils/reg/lang/pl-PL.rc index 130f3795f70..e3d2116fb61 100644 --- a/reactos/base/applications/cmdutils/reg/lang/pl-PL.rc +++ b/reactos/base/applications/cmdutils/reg/lang/pl-PL.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/pt-PT.rc b/reactos/base/applications/cmdutils/reg/lang/pt-PT.rc index d3cc5c36e0d..f6ee64dd826 100644 --- a/reactos/base/applications/cmdutils/reg/lang/pt-PT.rc +++ b/reactos/base/applications/cmdutils/reg/lang/pt-PT.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/ro-RO.rc b/reactos/base/applications/cmdutils/reg/lang/ro-RO.rc index c8984290681..ebcbe182c03 100644 --- a/reactos/base/applications/cmdutils/reg/lang/ro-RO.rc +++ b/reactos/base/applications/cmdutils/reg/lang/ro-RO.rc @@ -39,4 +39,8 @@ STRINGTABLE STRING_REG_HELP, "Tastați «REG /?» pentru mai multe informații.\n" STRING_FUNC_HELP, "Tastați «REG %1 /?» pentru mai multe informații.\n" STRING_VALUE_NOT_SET, "(valoare nealocată)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/ru-RU.rc b/reactos/base/applications/cmdutils/reg/lang/ru-RU.rc index a3e7453174a..04ad38c66e6 100644 --- a/reactos/base/applications/cmdutils/reg/lang/ru-RU.rc +++ b/reactos/base/applications/cmdutils/reg/lang/ru-RU.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Введите ""REG /?"" для получения справки по использованию..\n" STRING_FUNC_HELP, "Введите ""REG %1 /?"" для получения справки по использованию..\n" STRING_VALUE_NOT_SET, "(значение не указано)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/sl-SI.rc b/reactos/base/applications/cmdutils/reg/lang/sl-SI.rc index 7647a598e3a..e7d631e80b8 100644 --- a/reactos/base/applications/cmdutils/reg/lang/sl-SI.rc +++ b/reactos/base/applications/cmdutils/reg/lang/sl-SI.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/sq-AL.rc b/reactos/base/applications/cmdutils/reg/lang/sq-AL.rc index baf5aa07e2d..3b0dba526f8 100644 --- a/reactos/base/applications/cmdutils/reg/lang/sq-AL.rc +++ b/reactos/base/applications/cmdutils/reg/lang/sq-AL.rc @@ -37,4 +37,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/sv-SE.rc b/reactos/base/applications/cmdutils/reg/lang/sv-SE.rc index 2e290bb6e4d..24443ae2990 100644 --- a/reactos/base/applications/cmdutils/reg/lang/sv-SE.rc +++ b/reactos/base/applications/cmdutils/reg/lang/sv-SE.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/tr-TR.rc b/reactos/base/applications/cmdutils/reg/lang/tr-TR.rc index 577ef6f409e..bb0b757b908 100644 --- a/reactos/base/applications/cmdutils/reg/lang/tr-TR.rc +++ b/reactos/base/applications/cmdutils/reg/lang/tr-TR.rc @@ -35,4 +35,8 @@ STRINGTABLE STRING_REG_HELP, "Yardım için ""REG /?"" yazınız.\n" STRING_FUNC_HELP, "Yardım için ""REG %1 /?"" yazınız.\n" STRING_VALUE_NOT_SET, "(Değer belirlenmemiş.)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/uk-UA.rc b/reactos/base/applications/cmdutils/reg/lang/uk-UA.rc index 0933918f81d..b5a8b68e6d1 100644 --- a/reactos/base/applications/cmdutils/reg/lang/uk-UA.rc +++ b/reactos/base/applications/cmdutils/reg/lang/uk-UA.rc @@ -33,4 +33,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/zh-CN.rc b/reactos/base/applications/cmdutils/reg/lang/zh-CN.rc index 0647d667c28..c952714bd1b 100644 --- a/reactos/base/applications/cmdutils/reg/lang/zh-CN.rc +++ b/reactos/base/applications/cmdutils/reg/lang/zh-CN.rc @@ -35,4 +35,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/lang/zh-TW.rc b/reactos/base/applications/cmdutils/reg/lang/zh-TW.rc index cf4248ec5a2..e6c5a6e8ee6 100644 --- a/reactos/base/applications/cmdutils/reg/lang/zh-TW.rc +++ b/reactos/base/applications/cmdutils/reg/lang/zh-TW.rc @@ -35,4 +35,8 @@ STRINGTABLE STRING_REG_HELP, "Type ""REG /?"" for help.\n" STRING_FUNC_HELP, "Type ""REG %1 /?"" for help.\n" STRING_VALUE_NOT_SET, "(value not set)" + STRING_IMPORT_USAGE, "REG IMPORT file.reg\n" + 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" } diff --git a/reactos/base/applications/cmdutils/reg/reg.c b/reactos/base/applications/cmdutils/reg/reg.c index 094a2f46637..5a857dea952 100644 --- a/reactos/base/applications/cmdutils/reg/reg.c +++ b/reactos/base/applications/cmdutils/reg/reg.c @@ -25,11 +25,8 @@ #include #include #include -#include #include "reg.h" -#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*A)) - WINE_DEFAULT_DEBUG_CHANNEL(reg); static const WCHAR short_hklm[] = {'H','K','L','M',0}; @@ -84,6 +81,40 @@ type_rels[] = {REG_MULTI_SZ, type_multi_sz}, }; +void *heap_xalloc(size_t size) +{ + void *buf = HeapAlloc(GetProcessHeap(), 0, size); + if (!buf) + { + ERR("Out of memory!\n"); + exit(1); + } + return buf; +} + +void *heap_xrealloc(void *buf, size_t size) +{ + void *new_buf; + + if (buf) + new_buf = HeapReAlloc(GetProcessHeap(), 0, buf, size); + else + new_buf = HeapAlloc(GetProcessHeap(), 0, size); + + if (!new_buf) + { + ERR("Out of memory!\n"); + exit(1); + } + + return new_buf; +} + +BOOL heap_free(void *buf) +{ + return HeapFree(GetProcessHeap(), 0, buf); +} + static void output_writeconsole(const WCHAR *str, DWORD wlen) { DWORD count, ret; @@ -99,12 +130,11 @@ static void output_writeconsole(const WCHAR *str, DWORD wlen) * one in that case. */ len = WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, NULL, 0, NULL, NULL); - msgA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char)); - if (!msgA) return; + msgA = heap_xalloc(len); WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, msgA, len, NULL, NULL); WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE); - HeapFree(GetProcessHeap(), 0, msgA); + heap_free(msgA); } } @@ -125,7 +155,7 @@ static void output_formatstring(const WCHAR *fmt, __ms_va_list va_args) LocalFree(str); } -static void __cdecl output_message(unsigned int id, ...) +void __cdecl output_message(unsigned int id, ...) { WCHAR fmt[1024]; __ms_va_list va_args; @@ -188,7 +218,7 @@ static inline BOOL path_rootname_cmp(const WCHAR *input_path, const WCHAR *rootk (input_path[length] == 0 || input_path[length] == '\\')); } -static HKEY path_get_rootkey(const WCHAR *path) +HKEY path_get_rootkey(const WCHAR *path) { DWORD i; @@ -246,7 +276,7 @@ static LPBYTE get_regdata(const WCHAR *data, DWORD reg_type, WCHAR separator, DW case REG_EXPAND_SZ: { *reg_count = (lstrlenW(data) + 1) * sizeof(WCHAR); - out_data = HeapAlloc(GetProcessHeap(),0,*reg_count); + out_data = heap_xalloc(*reg_count); lstrcpyW((LPWSTR)out_data,data); break; } @@ -256,13 +286,13 @@ static LPBYTE get_regdata(const WCHAR *data, DWORD reg_type, WCHAR separator, DW { LPWSTR rest; unsigned long val; - val = strtoulW(data, &rest, (tolowerW(data[1]) == 'x') ? 16 : 10); - if (*rest || data[0] == '-' || (val == ~0u && errno == ERANGE) || val > ~0u) { + val = wcstoul(data, &rest, (tolowerW(data[1]) == 'x') ? 16 : 10); + if (*rest || data[0] == '-' || (val == ~0u && errno == ERANGE)) { output_message(STRING_MISSING_INTEGER); break; } *reg_count = sizeof(DWORD); - out_data = HeapAlloc(GetProcessHeap(),0,*reg_count); + out_data = heap_xalloc(*reg_count); ((LPDWORD)out_data)[0] = val; break; } @@ -271,7 +301,7 @@ static LPBYTE get_regdata(const WCHAR *data, DWORD reg_type, WCHAR separator, DW BYTE hex0, hex1; int i = 0, destByteIndex = 0, datalen = lstrlenW(data); *reg_count = ((datalen + datalen % 2) / 2) * sizeof(BYTE); - out_data = HeapAlloc(GetProcessHeap(), 0, *reg_count); + out_data = heap_xalloc(*reg_count); if(datalen % 2) { hex1 = hexchar_to_byte(data[i++]); @@ -290,7 +320,7 @@ static LPBYTE get_regdata(const WCHAR *data, DWORD reg_type, WCHAR separator, DW break; no_hex_data: /* cleanup, print error */ - HeapFree(GetProcessHeap(), 0, out_data); + heap_free(out_data); output_message(STRING_MISSING_HEXDATA); out_data = NULL; break; @@ -298,7 +328,7 @@ static LPBYTE get_regdata(const WCHAR *data, DWORD reg_type, WCHAR separator, DW case REG_MULTI_SZ: { int i, destindex, len = strlenW(data); - WCHAR *buffer = HeapAlloc(GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR)); + WCHAR *buffer = heap_xalloc((len + 2) * sizeof(WCHAR)); for (i = 0, destindex = 0; i < len; i++, destindex++) { @@ -314,7 +344,7 @@ static LPBYTE get_regdata(const WCHAR *data, DWORD reg_type, WCHAR separator, DW if (destindex && !buffer[destindex - 1] && (!buffer[destindex] || destindex == 1)) { - HeapFree(GetProcessHeap(), 0, buffer); + heap_free(buffer); output_message(STRING_INVALID_STRING); return NULL; } @@ -402,7 +432,7 @@ static int reg_add(HKEY root, WCHAR *path, WCHAR *value_name, BOOL value_empty, } RegSetValueExW(key, value_name, 0, reg_type, reg_data, reg_count); - HeapFree(GetProcessHeap(),0,reg_data); + heap_free(reg_data); } RegCloseKey(key); @@ -454,40 +484,35 @@ static int reg_delete(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name if (value_all) { - LPWSTR szValue; - DWORD maxValue; - DWORD count; + DWORD max_value_len = 256, value_len; + WCHAR *value_name; LONG rc; - rc = RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, &maxValue, NULL, NULL, NULL); - if (rc != ERROR_SUCCESS) - { - RegCloseKey(key); - output_message(STRING_GENERAL_FAILURE); - return 1; - } - maxValue++; - szValue = HeapAlloc(GetProcessHeap(),0,maxValue*sizeof(WCHAR)); + value_name = heap_xalloc(max_value_len * sizeof(WCHAR)); while (1) { - count = maxValue; - rc = RegEnumValueW(key, 0, szValue, &count, NULL, NULL, NULL, NULL); + value_len = max_value_len; + rc = RegEnumValueW(key, 0, value_name, &value_len, NULL, NULL, NULL, NULL); if (rc == ERROR_SUCCESS) { - rc = RegDeleteValueW(key, szValue); + rc = RegDeleteValueW(key, value_name); if (rc != ERROR_SUCCESS) { - HeapFree(GetProcessHeap(), 0, szValue); + heap_free(value_name); RegCloseKey(key); output_message(STRING_VALUEALL_FAILED, key_name); return 1; } } + else if (rc == ERROR_MORE_DATA) + { + max_value_len *= 2; + value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR)); + } else break; } - HeapFree(GetProcessHeap(), 0, szValue); + heap_free(value_name); } else if (value_name || value_empty) { @@ -513,16 +538,16 @@ static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes) { case REG_SZ: case REG_EXPAND_SZ: - buffer = HeapAlloc(GetProcessHeap(), 0, size_bytes); + buffer = heap_xalloc(size_bytes); strcpyW(buffer, (WCHAR *)src); break; case REG_NONE: case REG_BINARY: { WCHAR *ptr; - WCHAR fmt[] = {'%','0','2','X',0}; + static const WCHAR fmt[] = {'%','0','2','X',0}; - buffer = HeapAlloc(GetProcessHeap(), 0, (size_bytes * 2 + 1) * sizeof(WCHAR)); + buffer = heap_xalloc((size_bytes * 2 + 1) * sizeof(WCHAR)); ptr = buffer; for (i = 0; i < size_bytes; i++) ptr += sprintfW(ptr, fmt, src[i]); @@ -533,9 +558,9 @@ static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes) case REG_DWORD_BIG_ENDIAN: { const int zero_x_dword = 10; - WCHAR fmt[] = {'0','x','%','x',0}; + static const WCHAR fmt[] = {'0','x','%','x',0}; - buffer = HeapAlloc(GetProcessHeap(), 0, (zero_x_dword + 1) * sizeof(WCHAR)); + buffer = heap_xalloc((zero_x_dword + 1) * sizeof(WCHAR)); sprintfW(buffer, fmt, *(DWORD *)src); break; } @@ -548,13 +573,13 @@ static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes) if (size_bytes <= two_wchars) { - buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)); + buffer = heap_xalloc(sizeof(WCHAR)); *buffer = 0; return buffer; } tmp_size = size_bytes - two_wchars; /* exclude both null terminators */ - buffer = HeapAlloc(GetProcessHeap(), 0, tmp_size * 2 + sizeof(WCHAR)); + buffer = heap_xalloc(tmp_size * 2 + sizeof(WCHAR)); len = tmp_size / sizeof(WCHAR); for (i = 0, destindex = 0; i < len; i++, destindex++) @@ -588,10 +613,10 @@ static const WCHAR *reg_type_to_wchar(DWORD type) static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size) { - WCHAR fmt[] = {' ',' ',' ',' ','%','1',0}; + static const WCHAR fmt[] = {' ',' ',' ',' ','%','1',0}; + static const WCHAR newlineW[] = {'\n',0}; WCHAR defval[32]; WCHAR *reg_data; - WCHAR newlineW[] = {'\n',0}; if (value_name && value_name[0]) output_string(fmt, value_name); @@ -606,7 +631,7 @@ static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD { reg_data = reg_data_to_wchar(type, data, data_size); output_string(fmt, reg_data); - HeapFree(GetProcessHeap(), 0, reg_data); + heap_free(reg_data); } else { @@ -619,25 +644,23 @@ static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD static WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len) { WCHAR *subkey_path; - WCHAR fmt[] = {'%','s','\\','%','s',0}; + static const WCHAR fmt[] = {'%','s','\\','%','s',0}; - subkey_path = HeapAlloc(GetProcessHeap(), 0, (path_len + subkey_len + 2) * sizeof(WCHAR)); - if (!subkey_path) - { - ERR("Failed to allocate memory for subkey_path\n"); - return NULL; - } + subkey_path = heap_xalloc((path_len + subkey_len + 2) * sizeof(WCHAR)); sprintfW(subkey_path, fmt, path, subkey_name); + return subkey_path; } 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; - DWORD num_subkeys, max_subkey_len, subkey_len; - DWORD max_data_bytes, data_size; + DWORD max_data_bytes = 2048, data_size; + DWORD subkey_len; DWORD type, path_len, i; BYTE *data; WCHAR fmt[] = {'%','1','\n',0}; @@ -645,23 +668,20 @@ static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse) WCHAR *subkey_name, *subkey_path; HKEY subkey; - rc = RegQueryInfoKeyW(key, NULL, NULL, NULL, &num_subkeys, &max_subkey_len, - NULL, NULL, NULL, &max_data_bytes, NULL, NULL); - if (rc) + data = heap_xalloc(max_data_bytes); + + for (;;) { - ERR("RegQueryInfoKey failed: %d\n", rc); - return 1; + data_size = max_data_bytes; + rc = RegQueryValueExW(key, value_name, NULL, &type, data, &data_size); + if (rc == ERROR_MORE_DATA) + { + max_data_bytes = data_size; + data = heap_xrealloc(data, max_data_bytes); + } + else break; } - data = HeapAlloc(GetProcessHeap(), 0, max_data_bytes); - if (!data) - { - ERR("Failed to allocate memory for data\n"); - return 1; - } - - data_size = max_data_bytes; - rc = RegQueryValueExW(key, value_name, NULL, &type, data, &data_size); if (rc == ERROR_SUCCESS) { output_string(fmt, path); @@ -670,7 +690,7 @@ static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse) num_values_found++; } - HeapFree(GetProcessHeap(), 0, data); + heap_free(data); if (!recurse) { @@ -687,19 +707,14 @@ static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse) return 0; } - max_subkey_len++; - subkey_name = HeapAlloc(GetProcessHeap(), 0, max_subkey_len * sizeof(WCHAR)); - if (!subkey_name) - { - ERR("Failed to allocate memory for subkey_name\n"); - return 1; - } + subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); path_len = strlenW(path); - for (i = 0; i < num_subkeys; i++) + i = 0; + for (;;) { - subkey_len = max_subkey_len; + subkey_len = MAX_SUBKEY_LEN; rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); if (rc == ERROR_SUCCESS) { @@ -709,20 +724,22 @@ static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse) query_value(subkey, value_name, subkey_path, recurse); RegCloseKey(subkey); } - HeapFree(GetProcessHeap(), 0, subkey_path); + heap_free(subkey_path); + i++; } + else break; } - HeapFree(GetProcessHeap(), 0, subkey_name); + heap_free(subkey_name); return 0; } static int query_all(HKEY key, WCHAR *path, BOOL recurse) { LONG rc; - DWORD num_subkeys, max_subkey_len, subkey_len; - DWORD num_values, max_value_len, value_len; - DWORD max_data_bytes, data_size; + DWORD max_value_len = 256, value_len; + DWORD max_data_bytes = 2048, data_size; + DWORD subkey_len; DWORD i, type, path_len; WCHAR fmt[] = {'%','1','\n',0}; WCHAR fmt_path[] = {'%','1','\\','%','2','\n',0}; @@ -731,60 +748,52 @@ static int query_all(HKEY key, WCHAR *path, BOOL recurse) BYTE *data; HKEY subkey; - rc = RegQueryInfoKeyW(key, NULL, NULL, NULL, &num_subkeys, &max_subkey_len, NULL, - &num_values, &max_value_len, &max_data_bytes, NULL, NULL); - if (rc) - { - ERR("RegQueryInfoKey failed: %d\n", rc); - return 1; - } - output_string(fmt, path); - max_value_len++; - value_name = HeapAlloc(GetProcessHeap(), 0, max_value_len * sizeof(WCHAR)); - if (!value_name) - { - ERR("Failed to allocate memory for value_name\n"); - return 1; - } + value_name = heap_xalloc(max_value_len * sizeof(WCHAR)); + data = heap_xalloc(max_data_bytes); - data = HeapAlloc(GetProcessHeap(), 0, max_data_bytes); - if (!data) - { - HeapFree(GetProcessHeap(), 0, value_name); - ERR("Failed to allocate memory for data\n"); - return 1; - } - - for (i = 0; i < num_values; i++) + 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) + { output_value(value_name, 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; } - HeapFree(GetProcessHeap(), 0, data); - HeapFree(GetProcessHeap(), 0, value_name); + heap_free(data); + heap_free(value_name); - if (num_values || recurse) + if (i || recurse) output_string(newlineW); - max_subkey_len++; - subkey_name = HeapAlloc(GetProcessHeap(), 0, max_subkey_len * sizeof(WCHAR)); - if (!subkey_name) - { - ERR("Failed to allocate memory for subkey_name\n"); - return 1; - } + subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); path_len = strlenW(path); - for (i = 0; i < num_subkeys; i++) + i = 0; + for (;;) { - subkey_len = max_subkey_len; + subkey_len = MAX_SUBKEY_LEN; rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); if (rc == ERROR_SUCCESS) { @@ -796,15 +805,17 @@ static int query_all(HKEY key, WCHAR *path, BOOL recurse) query_all(subkey, subkey_path, recurse); RegCloseKey(subkey); } - HeapFree(GetProcessHeap(), 0, subkey_path); + heap_free(subkey_path); } else output_string(fmt_path, path, subkey_name); + i++; } + else break; } - HeapFree(GetProcessHeap(), 0, subkey_name); + heap_free(subkey_name); - if (num_subkeys && !recurse) + if (i && !recurse) output_string(newlineW); return 0; @@ -855,13 +866,13 @@ static WCHAR *get_long_key(HKEY root, WCHAR *path) if (!path) { - long_key = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + long_key = heap_xalloc((len + 1) * sizeof(WCHAR)); strcpyW(long_key, root_rels[i].long_name); return long_key; } len += strlenW(path) + 1; /* add one for the backslash */ - long_key = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + long_key = heap_xalloc((len + 1) * sizeof(WCHAR)); sprintfW(long_key, fmt, root_rels[i].long_name, path); return long_key; } @@ -900,32 +911,38 @@ static BOOL is_help_switch(const WCHAR *s) enum operations { REG_ADD, REG_DELETE, + REG_IMPORT, REG_QUERY, REG_INVALID }; -static const WCHAR addW[] = {'a','d','d',0}; -static const WCHAR deleteW[] = {'d','e','l','e','t','e',0}; -static const WCHAR queryW[] = {'q','u','e','r','y',0}; - static enum operations get_operation(const WCHAR *str, int *op_help) { - if (!lstrcmpiW(str, addW)) - { - *op_help = STRING_ADD_USAGE; - return REG_ADD; - } + struct op_info { const WCHAR *op; int id; int help_id; }; - if (!lstrcmpiW(str, deleteW)) - { - *op_help = STRING_DELETE_USAGE; - return REG_DELETE; - } + 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 query[] = {'q','u','e','r','y',0}; - if (!lstrcmpiW(str, queryW)) + static const struct op_info op_array[] = { - *op_help = STRING_QUERY_USAGE; - return REG_QUERY; + { add, REG_ADD, STRING_ADD_USAGE }, + { delete, REG_DELETE, STRING_DELETE_USAGE }, + { import, REG_IMPORT, STRING_IMPORT_USAGE }, + { query, REG_QUERY, STRING_QUERY_USAGE }, + { NULL, -1, 0 } + }; + + const struct op_info *ptr; + + for (ptr = op_array; ptr->op; ptr++) + { + if (!lstrcmpiW(str, ptr->op)) + { + *op_help = ptr->help_id; + return ptr->id; + } } return REG_INVALID; @@ -966,7 +983,7 @@ int wmain(int argc, WCHAR *argvW[]) if (argc > 2) show_op_help = is_help_switch(argvW[2]); - if (argc == 2 || (show_op_help && argc > 3)) + if (argc == 2 || ((show_op_help || op == REG_IMPORT) && argc > 3)) { output_message(STRING_INVALID_SYNTAX); output_message(STRING_FUNC_HELP, struprW(argvW[1])); @@ -978,6 +995,9 @@ int wmain(int argc, WCHAR *argvW[]) return 0; } + if (op == REG_IMPORT) + return reg_import(argvW[2]); + if (!parse_registry_key(argvW[2], &root, &path, &key_name)) return 1; @@ -1061,7 +1081,7 @@ int wmain(int argc, WCHAR *argvW[]) ret = reg_add(root, path, value_name, value_empty, type, separator, data, force); else if (op == REG_DELETE) ret = reg_delete(root, path, key_name, value_name, value_empty, value_all, force); - else if (op == REG_QUERY) + else ret = reg_query(root, path, key_name, value_name, value_empty, recurse); return ret; } diff --git a/reactos/base/applications/cmdutils/reg/reg.h b/reactos/base/applications/cmdutils/reg/reg.h index 2dbe1213f81..14c05b13d49 100644 --- a/reactos/base/applications/cmdutils/reg/reg.h +++ b/reactos/base/applications/cmdutils/reg/reg.h @@ -1,7 +1,5 @@ /* - * REG.EXE - Wine-compatible reg program. - * - * Copyright 2008 Andrew Riedi + * 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 @@ -18,39 +16,21 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#pragma once +#ifndef __REG_H__ +#define __REG_H__ -//#include +#include "resource.h" -/* 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 ARRAY_SIZE(A) (sizeof(A)/sizeof(*A)) + +/* 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, ...); +HKEY path_get_rootkey(const WCHAR *path); + +/* import.c */ +int reg_import(const WCHAR *filename); + +#endif /* __REG_H__ */ diff --git a/reactos/base/applications/cmdutils/reg/resource.h b/reactos/base/applications/cmdutils/reg/resource.h new file mode 100644 index 00000000000..0f57663183d --- /dev/null +++ b/reactos/base/applications/cmdutils/reg/resource.h @@ -0,0 +1,60 @@ +/* + * REG.EXE - Wine-compatible reg program. + * + * Copyright 2008 Andrew Riedi + * + * 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 + */ + +#pragma once + +//#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 diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index dcfaa1f6383..f325d82232f 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/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.9 +reactos/base/applications/cmdutils/reg # Synced to WineStaging-2.16 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