[PATCH 3/4] regedit: Re-implement processRegLinesA()

Hugh McMaster hugh.mcmaster at outlook.com
Thu Mar 16 07:05:23 CDT 2017


Signed-off-by: Hugh McMaster <hugh.mcmaster at outlook.com>
---
 programs/regedit/regproc.c       | 205 ++++++++++++++++-----------------------
 programs/regedit/tests/regedit.c |  14 +--
 2 files changed, 90 insertions(+), 129 deletions(-)

diff --git a/programs/regedit/regproc.c b/programs/regedit/regproc.c
index ac64e27..c04643e 100644
--- a/programs/regedit/regproc.c
+++ b/programs/regedit/regproc.c
@@ -675,145 +675,106 @@ static enum reg_versions parse_file_header(WCHAR *s)
     return REG_VERSION_INVALID;
 }
 
-/******************************************************************************
- * Processes a registry file.
- * Correctly processes comments (in # and ; form), line continuation.
- *
- * Parameters:
- *   in - input stream to read from
- *   first_chars - beginning of stream, read due to Unicode check
- */
-static void processRegLinesA(FILE *in, char* first_chars)
+static char *get_lineA(FILE *fp, char **buf)
 {
-    char *buf = NULL;  /* the line read from the input stream */
-    unsigned long line_size = REG_VAL_BUF_SIZE;
-    size_t chars_in_buf = -1;
-    char *s; /* A pointer to buf for fread */
-    char *line; /* The start of the current line */
-    WCHAR *lineW;
-    unsigned long version = 0;
-    BOOL first_line = TRUE;
-
-    buf = HeapAlloc(GetProcessHeap(), 0, line_size);
-    CHECK_ENOUGH_MEMORY(buf);
-    s = buf;
-    line = buf;
-
-    memcpy(line, first_chars, 2);
-
-    if (first_chars)
-        s += 2;
+    static size_t size;
+    static char *next;
+    char *line;
 
-    while (!feof(in)) {
-        size_t size_remaining;
-        int size_to_get;
-        char *s_eol = NULL; /* various local uses */
+    if (!size)
+    {
+        size = REG_VAL_BUF_SIZE;
+        *buf = HeapAlloc(GetProcessHeap(), 0, size);
+        CHECK_ENOUGH_MEMORY(*buf);
+        **buf = 0;
+        next = *buf;
+    }
+    line = next;
 
-        /* Do we need to expand the buffer? */
-        assert(s >= buf && s <= buf + line_size);
-        size_remaining = line_size - (s - buf);
-        if (size_remaining < 3) /* we need at least 3 bytes of room for \r\n\0 */
+    while (next)
+    {
+        char *p = strpbrk(line, "\r\n");
+        if (!p)
         {
-            char *new_buffer;
-            size_t new_size = line_size + REG_VAL_BUF_SIZE;
-            if (new_size > line_size) /* no arithmetic overflow */
-                new_buffer = HeapReAlloc(GetProcessHeap(), 0, buf, new_size);
-            else
-                new_buffer = NULL;
-            CHECK_ENOUGH_MEMORY(new_buffer);
-            buf = new_buffer;
-            line = buf;
-            s = buf + line_size - size_remaining;
-            line_size = new_size;
-            size_remaining = line_size - (s - buf);
-        }
-
-        /* Get as much as possible into the buffer, terminating on EOF,
-         * error or once we have read the maximum amount. Abort on error.
-         */
-        size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
-
-        chars_in_buf = fread(s, 1, size_to_get - 1, in);
-        s[chars_in_buf] = 0;
-
-        if (chars_in_buf == 0) {
-            if (ferror(in)) {
-                perror("While reading input");
-                exit(IO_ERROR);
-            } else {
-                assert(feof(in));
-                *s = '\0';
+            size_t len, count;
+            len = strlen(next);
+            MoveMemory(*buf, next, len + 1);
+            if (size - len < 3)
+            {
+                char *new_buf = HeapReAlloc(GetProcessHeap(), 0, *buf, size * 2);
+                CHECK_ENOUGH_MEMORY(new_buf);
+                *buf = new_buf;
+                size *= 2;
             }
+            if (!(count = fread(*buf + len, 1, size - len - 1, fp)))
+            {
+                next = NULL;
+                return *buf;
+            }
+            (*buf)[len + count] = 0;
+            next = *buf;
+            line = *buf;
+            continue;
         }
-
-        /* If we didn't read the end-of-line sequence or EOF, go around again */
-        while (1)
+        next = p + 1;
+        if (*p == '\r' && *(p + 1) == '\n') next++;
+        *p = 0;
+        if (*(p - 1) == '\\')
         {
-            s_eol = strpbrk(line, "\r\n");
-            if (!s_eol) {
-                /* Move the stub of the line to the start of the buffer so
-                 * we get the maximum space to read into, and so we don't
-                 * have to recalculate 'line' if the buffer expands */
-                MoveMemory(buf, line, strlen(line) + 1);
-                line = buf;
-                s = strchr(line, '\0');
-                break;
-            }
-
-            /* If we find a comment line, discard it and go around again */
-            if (line [0] == '#' || line [0] == ';') {
-                if (*s_eol == '\r' && *(s_eol + 1) == '\n')
-                    line = s_eol + 2;
-                else
-                    line = s_eol + 1;
-                continue;
-            }
-
-            /* If there is a concatenating '\\', go around again */
-            if (*(s_eol - 1) == '\\') {
-                char *next_line = s_eol + 1;
+            *(--p) = 0;
+            while (*next && (*next == ' ' || *next == '\t')) next++;
+            MoveMemory(p, next, strlen(next) + 1);
+            next = line;
+            continue;
+        }
+        if (*line == ';' || *line == '#')
+        {
+            line = next;
+            continue;
+        }
+        return line;
+    }
+    size = 0;
+    return NULL;
+}
 
-                if (*s_eol == '\r' && *(s_eol + 1) == '\n')
-                    next_line++;
+static void processRegLinesA(FILE *fp, char *two_chars)
+{
+    char *buf = NULL, *line, *header;
+    WCHAR *lineW;
+    int reg_version;
 
-                while (*(next_line + 1) == ' ' || *(next_line + 1) == '\t')
-                    next_line++;
+    line = get_lineA(fp, &buf);
 
-                MoveMemory(s_eol - 1, next_line, chars_in_buf - (next_line - s) + 1);
-                chars_in_buf -= next_line - s_eol + 1;
-                continue;
-            }
+    header = HeapAlloc(GetProcessHeap(), 0, strlen(line) + 3);
+    CHECK_ENOUGH_MEMORY(header);
+    strcpy(header, two_chars);
+    strcpy(header + 2, line);
 
-            /* Remove any line feed. Leave s_eol on the last \0 */
-            if (*s_eol == '\r' && *(s_eol + 1) == '\n')
-                *s_eol++ = '\0';
-            *s_eol = '\0';
+    lineW = GetWideString(header);
+    HeapFree(GetProcessHeap(), 0, header);
+    reg_version = parse_file_header(lineW);
+    HeapFree(GetProcessHeap(), 0, lineW);
 
-            lineW = GetWideString(line);
+    if (reg_version == REG_VERSION_INVALID)
+    {
+        HeapFree(GetProcessHeap(), 0, buf);
+        return;
+    }
 
-            if (first_line)
-            {
-                version = parse_file_header(lineW);
-                if (version == REG_VERSION_INVALID)
-                {
-                    HeapFree(GetProcessHeap(), 0, lineW);
-                    HeapFree(GetProcessHeap(), 0, buf);
-                    return;
-                }
-                first_line = FALSE;
-            }
+    while ((line = get_lineA(fp, &buf)))
+    {
+        lineW = GetWideString(line);
 
-            if (version == REG_VERSION_31)
-                processRegEntry31(lineW);
-            else
-                processRegEntry(lineW, FALSE);
+        if (reg_version == REG_VERSION_31)
+            processRegEntry31(lineW);
+        else
+            processRegEntry(lineW, FALSE);
 
-            HeapFree(GetProcessHeap(), 0, lineW);
-            line = s_eol + 1;
-        }
+        HeapFree(GetProcessHeap(), 0, lineW);
     }
-    closeKey();
 
+    closeKey();
     HeapFree(GetProcessHeap(), 0, buf);
 }
 
diff --git a/programs/regedit/tests/regedit.c b/programs/regedit/tests/regedit.c
index eacb583..72f0602 100644
--- a/programs/regedit/tests/regedit.c
+++ b/programs/regedit/tests/regedit.c
@@ -268,7 +268,7 @@ static void test_basic_import(void)
     exec_import_str("REGEDIT4\n\n"
                     "[HKEY_CURRENT_USER\\" KEY_BASE "]\n"
                     "\"Wine5\"=\"No newline\"");
-    todo_wine verify_reg(hkey, "Wine5", REG_SZ, "No newline", 11, 0);
+    verify_reg(hkey, "Wine5", REG_SZ, "No newline", 11, 0);
 
     exec_import_str("REGEDIT4\n\n"
                     "[HKEY_CURRENT_USER\\" KEY_BASE "]\n"
@@ -276,7 +276,7 @@ static void test_basic_import(void)
                     "\"Wine7\"=\"No newline\"");
     dword = 0x50;
     verify_reg(hkey, "Wine6", REG_DWORD, &dword, sizeof(dword), 0);
-    todo_wine verify_reg(hkey, "Wine7", REG_SZ, "No newline", 11, 0);
+    verify_reg(hkey, "Wine7", REG_SZ, "No newline", 11, 0);
 
     exec_import_str("REGEDIT4\n\n"
                     "[HKEY_CURRENT_USER\\" KEY_BASE "]\n"
@@ -361,7 +361,7 @@ static void test_basic_import_31(void)
 
     exec_import_str("REGEDIT\r\n"
                     "HKEY_CLASSES_ROOT\\" KEY_BASE " = No newline");
-    verify_reg(hkey, "", REG_SZ, "No newline", 11, TODO_REG_SIZE | TODO_REG_DATA);
+    verify_reg(hkey, "", REG_SZ, "No newline", 11, 0);
 
     RegCloseKey(hkey);
 
@@ -482,7 +482,7 @@ static void test_invalid_import(void)
                     "[HKEY_CURRENT_USER\\" KEY_BASE "]\n"
                     "\"Multi-Line2\"=hex(7):4c,69,6e,65,20\\\n"
                     "  ,63,6f,6e,63,61,74,65,6e,61,74,69,6f,6e,00,00\n\n");
-    verify_reg_nonexist(hkey, "Multi-Line2");
+    todo_wine verify_reg_nonexist(hkey, "Multi-Line2");
 
     exec_import_str("Windows Registry Editor Version 5.00\n\n"
                     "[HKEY_CURRENT_USER\\" KEY_BASE "]\n"
@@ -494,7 +494,7 @@ static void test_invalid_import(void)
                     "[HKEY_CURRENT_USER\\" KEY_BASE "]\n"
                     "\"Multi-Line4\"=hex(7):4c,69,6e,65,20\\\n"
                     "  ,63,6f,6e,63,61,74,65,6e,61,74,69,6f,6e,00,00\n\n");
-    verify_reg_nonexist(hkey, "Multi-Line4");
+    todo_wine verify_reg_nonexist(hkey, "Multi-Line4");
 
     RegCloseKey(hkey);
 
@@ -518,8 +518,8 @@ static void test_comments(void)
                     ";comment\\\n"
                     "\"Wine2\"=\"Line 2\"\n\n");
     lr = RegOpenKeyExA(HKEY_CURRENT_USER, KEY_BASE, 0, KEY_READ, &hkey);
-    verify_reg(hkey, "Wine1", REG_SZ, "Line 1", 7, 0);
-    verify_reg(hkey, "Wine2", REG_SZ, "Line 2", 7, 0);
+    todo_wine verify_reg(hkey, "Wine1", REG_SZ, "Line 1", 7, 0);
+    todo_wine verify_reg(hkey, "Wine2", REG_SZ, "Line 2", 7, 0);
 
     exec_import_str("REGEDIT4\n\n"
                     "[HKEY_CURRENT_USER\\" KEY_BASE "]\n"
-- 
2.7.4




More information about the wine-patches mailing list