Author: akhaldi
Date: Sun Sep 24 11:33:04 2017
New Revision: 75958

URL: http://svn.reactos.org/svn/reactos?rev=75958&view=rev
Log:
[REG] Sync with Wine Staging 2.16. CORE-13762

39e0e81 reg: Null-terminate incomplete REG_EXPAND_SZ and REG_MULTI_SZ Unicode 
data.
82fc4c8 reg: Close any open registry keys before starting the key deletion 
process.
5de883c reg: Use the correct return codes during the import operation.
56e58e4 reg: Delete registry keys via the state machine.
d90f2a5 reg: Delete registry values via the state machine.
db98cc4 reg: Handle unknown registry data types in the state machine.
32d5368 reg: Import hex data via the state machine.
f1874c1 reg: Import REG_DWORD data via the state machine.
038f1c6 reg: Parse data types and import REG_SZ data via the state machine.
0565934 reg: Parse key names and value names in the state machine.
3e87a70 reg: Introduce a partial state machine for importing Windows 3.1 
registry data.
aa386af reg: Add initial support for the import operation.
f2fbbec reg: Rename reg.h to resource.h.
c6c95a0 reg: Compile with msvcrt.
8c253c4 reg: Make some variables 'static const'.
337e0f4 reg: Avoid an uninitialized variable warning.
8abec73 reg: Dynamically allocate memory for the value name buffer when 
deleting all registry values in a specified key.
e7ea838 reg: Use a helper function to resize a memory buffer.
a1bc33a reg: Use a helper function to free allocated memory.
a6e28cc reg: Use a helper function to allocate memory and die on failure.
90da210 reg: Account for sizeof(WCHAR) when resizing the value name buffer 
during the query operation.
fb22f6c reg: Avoid using RegQueryInfoKey() to enumerate subkeys and values in 
the query operation.

Added:
    trunk/reactos/base/applications/cmdutils/reg/import.c   (with props)
    trunk/reactos/base/applications/cmdutils/reg/resource.h   (with props)
Modified:
    trunk/reactos/base/applications/cmdutils/reg/CMakeLists.txt
    trunk/reactos/base/applications/cmdutils/reg/lang/bg-BG.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/cs-CZ.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/da-DK.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/de-DE.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/en-US.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/es-ES.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/fr-FR.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/it-IT.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/ja-JP.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/ko-KR.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/lt-LT.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/nl-NL.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/no-NO.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/pl-PL.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/pt-PT.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/ro-RO.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/ru-RU.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/sl-SI.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/sq-AL.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/sv-SE.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/tr-TR.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/uk-UA.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/zh-CN.rc
    trunk/reactos/base/applications/cmdutils/reg/lang/zh-TW.rc
    trunk/reactos/base/applications/cmdutils/reg/reg.c
    trunk/reactos/base/applications/cmdutils/reg/reg.h
    trunk/reactos/media/doc/README.WINE

Modified: trunk/reactos/base/applications/cmdutils/reg/CMakeLists.txt
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/CMakeLists.txt?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/CMakeLists.txt [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/CMakeLists.txt [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -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)

Added: trunk/reactos/base/applications/cmdutils/reg/import.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/import.c?rev=75958
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/import.c       (added)
+++ trunk/reactos/base/applications/cmdutils/reg/import.c       [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -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 <windef.h>
+#include <winbase.h>
+#include <winreg.h>
+#include <stdio.h>
+
+#include <wine/unicode.h>
+#include <wine/debug.h>
+
+#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;
+}

Propchange: trunk/reactos/base/applications/cmdutils/reg/import.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/bg-BG.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/bg-BG.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/bg-BG.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/bg-BG.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/cs-CZ.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/cs-CZ.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/cs-CZ.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/cs-CZ.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -38,4 +38,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/da-DK.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/da-DK.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/da-DK.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/da-DK.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/de-DE.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/de-DE.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/de-DE.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/de-DE.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/en-US.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/en-US.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/en-US.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/en-US.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/es-ES.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/es-ES.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/es-ES.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/es-ES.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/fr-FR.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/fr-FR.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/fr-FR.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/fr-FR.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/it-IT.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/it-IT.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/it-IT.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/it-IT.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/ja-JP.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/ja-JP.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/ja-JP.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/ja-JP.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/ko-KR.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/ko-KR.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/ko-KR.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/ko-KR.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/lt-LT.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/lt-LT.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/lt-LT.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/lt-LT.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/nl-NL.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/nl-NL.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/nl-NL.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/nl-NL.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/no-NO.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/no-NO.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/no-NO.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/no-NO.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/pl-PL.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/pl-PL.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/pl-PL.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/pl-PL.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/pt-PT.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/pt-PT.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/pt-PT.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/pt-PT.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/ro-RO.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/ro-RO.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/ro-RO.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/ro-RO.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -39,4 +39,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/ru-RU.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/ru-RU.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/ru-RU.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/ru-RU.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/sl-SI.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/sl-SI.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/sl-SI.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/sl-SI.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/sq-AL.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/sq-AL.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/sq-AL.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/sq-AL.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -37,4 +37,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/sv-SE.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/sv-SE.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/sv-SE.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/sv-SE.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/tr-TR.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/tr-TR.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/tr-TR.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/tr-TR.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -35,4 +35,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/uk-UA.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/uk-UA.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/uk-UA.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/uk-UA.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -33,4 +33,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/zh-CN.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/zh-CN.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/zh-CN.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/zh-CN.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -35,4 +35,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/lang/zh-TW.rc
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/lang/zh-TW.rc?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/lang/zh-TW.rc  [iso-8859-1] 
(original)
+++ trunk/reactos/base/applications/cmdutils/reg/lang/zh-TW.rc  [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -35,4 +35,8 @@
     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"
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/reg.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/reg.c?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/reg.c  [iso-8859-1] (original)
+++ trunk/reactos/base/applications/cmdutils/reg/reg.c  [iso-8859-1] Sun Sep 24 
11:33:04 2017
@@ -25,10 +25,7 @@
 #include <shlwapi.h>
 #include <wine/unicode.h>
 #include <wine/debug.h>
-#include <errno.h>
 #include "reg.h"
-
-#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*A))
 
 WINE_DEFAULT_DEBUG_CHANNEL(reg);
 
@@ -84,6 +81,40 @@
     {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 @@
          * 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 @@
     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 @@
             (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 @@
         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 @@
         {
             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 @@
             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 @@
             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 @@
         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 @@
 
                 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 @@
         }
 
         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 @@
 
     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 @@
     {
         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};
-
-            buffer = HeapAlloc(GetProcessHeap(), 0, (size_bytes * 2 + 1) * 
sizeof(WCHAR));
+            static const WCHAR fmt[] = {'%','0','2','X',0};
+
+            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 @@
         case REG_DWORD_BIG_ENDIAN:
         {
             const int zero_x_dword = 10;
-            WCHAR fmt[] = {'0','x','%','x',0};
-
-            buffer = HeapAlloc(GetProcessHeap(), 0, (zero_x_dword + 1) * 
sizeof(WCHAR));
+            static const WCHAR fmt[] = {'0','x','%','x',0};
+
+            buffer = heap_xalloc((zero_x_dword + 1) * sizeof(WCHAR));
             sprintfW(buffer, fmt, *(DWORD *)src);
             break;
         }
@@ -548,13 +573,13 @@
 
             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 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 @@
     {
         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 WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR 
*subkey_name, DWORD subkey_len)
 {
     WCHAR *subkey_path;
-    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;
-    }
+    static const WCHAR fmt[] = {'%','s','\\','%','s',0};
+
+    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 @@
     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)
-    {
-        ERR("RegQueryInfoKey failed: %d\n", rc);
-        return 1;
-    }
-
-    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);
+    data = heap_xalloc(max_data_bytes);
+
+    for (;;)
+    {
+        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;
+    }
+
     if (rc == ERROR_SUCCESS)
     {
         output_string(fmt, path);
@@ -670,7 +690,7 @@
         num_values_found++;
     }
 
-    HeapFree(GetProcessHeap(), 0, data);
+    heap_free(data);
 
     if (!recurse)
     {
@@ -687,19 +707,14 @@
         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++)
-    {
-        subkey_len = max_subkey_len;
+    i = 0;
+    for (;;)
+    {
+        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 @@
                 query_value(subkey, value_name, subkey_path, recurse);
                 RegCloseKey(subkey);
             }
-            HeapFree(GetProcessHeap(), 0, subkey_path);
-        }
-    }
-
-    HeapFree(GetProcessHeap(), 0, subkey_name);
+            heap_free(subkey_path);
+            i++;
+        }
+        else break;
+    }
+
+    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 @@
     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;
-    }
-
-    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++)
+    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)
+        {
             output_value(value_name, type, data, data_size);
-    }
-
-    HeapFree(GetProcessHeap(), 0, data);
-    HeapFree(GetProcessHeap(), 0, value_name);
-
-    if (num_values || recurse)
+            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);
+
+    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++)
-    {
-        subkey_len = max_subkey_len;
+    i = 0;
+    for (;;)
+    {
+        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 @@
                     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);
-        }
-    }
-
-    HeapFree(GetProcessHeap(), 0, subkey_name);
-
-    if (num_subkeys && !recurse)
+            i++;
+        }
+        else break;
+    }
+
+    heap_free(subkey_name);
+
+    if (i && !recurse)
         output_string(newlineW);
 
     return 0;
@@ -855,13 +866,13 @@
 
     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 @@
 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;
-    }
-
-    if (!lstrcmpiW(str, deleteW))
-    {
-        *op_help = STRING_DELETE_USAGE;
-        return REG_DELETE;
-    }
-
-    if (!lstrcmpiW(str, queryW))
-    {
-        *op_help = STRING_QUERY_USAGE;
-        return REG_QUERY;
+    struct op_info { const WCHAR *op; int id; int help_id; };
+
+    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};
+
+    static const struct op_info op_array[] =
+    {
+        { 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 @@
     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]));
@@ -977,6 +994,9 @@
         output_message(op_help);
         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 @@
         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;
 }

Modified: trunk/reactos/base/applications/cmdutils/reg/reg.h
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/reg.h?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/reg.h  [iso-8859-1] (original)
+++ trunk/reactos/base/applications/cmdutils/reg/reg.h  [iso-8859-1] Sun Sep 24 
11:33:04 2017
@@ -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 <windef.h>
+#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__ */

Added: trunk/reactos/base/applications/cmdutils/reg/resource.h
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/reg/resource.h?rev=75958
==============================================================================
--- trunk/reactos/base/applications/cmdutils/reg/resource.h     (added)
+++ trunk/reactos/base/applications/cmdutils/reg/resource.h     [iso-8859-1] 
Sun Sep 24 11:33:04 2017
@@ -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 <windef.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 STRING_IMPORT_USAGE     132
+#define STRING_FILE_NOT_FOUND   133
+#define STRING_OPEN_KEY_FAILED  134
+#define STRING_ESCAPE_SEQUENCE  135

Propchange: trunk/reactos/base/applications/cmdutils/reg/resource.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: trunk/reactos/media/doc/README.WINE
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/media/doc/README.WINE?rev=75958&r1=75957&r2=75958&view=diff
==============================================================================
--- trunk/reactos/media/doc/README.WINE [iso-8859-1] (original)
+++ trunk/reactos/media/doc/README.WINE [iso-8859-1] Sun Sep 24 11:33:04 2017
@@ -227,7 +227,7 @@
 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


Reply via email to