[PATCH v4 5/8] reg.exe: Add wchar/raw data conversion functions

Jonathan Vollebregt jnvsor at gmail.com
Thu Oct 9 03:55:11 CDT 2014


---
 programs/reg/reg.c       | 222 ++++++++++++++++++++++++++++++++++++++++++-----
 programs/reg/reg.h       |   3 +
 programs/reg/reg.rc      |   3 +
 programs/reg/tests/reg.c |  13 ++-
 4 files changed, 210 insertions(+), 31 deletions(-)

diff --git a/programs/reg/reg.c b/programs/reg/reg.c
index 1caa3dc..15bf570 100644
--- a/programs/reg/reg.c
+++ b/programs/reg/reg.c
@@ -178,43 +178,209 @@ static DWORD wchar_get_type(const WCHAR *type)
     return -1;
 }
 
-static LPBYTE get_regdata(LPWSTR data, DWORD reg_type, WCHAR separator, DWORD *reg_count)
+static inline DWORD switch_endian(const DWORD i)
 {
-    LPBYTE out_data = NULL;
-    *reg_count = 0;
+    return (i>>24) | ((i>>8)&0xFF00) | ((i&0xFF00)<<8) | (i<<24);
+}
+
+static WCHAR *data_get_wchar(const BYTE *data, const DWORD size, const DWORD type)
+{
+    static const WCHAR print_dwordW[] = {'0','x','%','0','8','x',0};
+    static const WCHAR print_byteW[] = {'%','0','2','x',0};
+    DWORD i = 0;
+    WCHAR *output = NULL;
 
-    switch (reg_type)
+    switch(type)
     {
         case REG_SZ:
+        case REG_EXPAND_SZ:
         {
-            *reg_count = (lstrlenW(data) + 1) * sizeof(WCHAR);
-            out_data = HeapAlloc(GetProcessHeap(),0,*reg_count);
-            lstrcpyW((LPWSTR)out_data,data);
-            break;
+            output = HeapAlloc(GetProcessHeap(), 0, size);
+            lstrcpyW(output, (WCHAR *) data);
+            return output;
         }
         case REG_DWORD:
+        case REG_DWORD_BIG_ENDIAN:
         {
-            LPWSTR rest;
-            DWORD val;
-            val = strtolW(data, &rest, 0);
-            if (rest == data) {
-                static const WCHAR nonnumber[] = {'E','r','r','o','r',':',' ','/','d',' ','r','e','q','u','i','r','e','s',' ','n','u','m','b','e','r','.','\n',0};
-                reg_printfW(nonnumber);
-                break;
-            }
-            *reg_count = sizeof(DWORD);
-            out_data = HeapAlloc(GetProcessHeap(),0,*reg_count);
-            ((LPDWORD)out_data)[0] = val;
-            break;
+            output = HeapAlloc(GetProcessHeap(), 0, 11 * sizeof(WCHAR));
+
+            i = * (DWORD *) data;
+            if (type == REG_DWORD_BIG_ENDIAN)
+                i = switch_endian(i);
+
+            sprintfW(output, print_dwordW, i);
+            return output;
+        }
+        case REG_MULTI_SZ:
+        {
+            WCHAR *input = (WCHAR *) data;
+
+            output = HeapAlloc(GetProcessHeap(), 0, size);
+
+            do
+            {
+                lstrcpyW(output+i, &input[i]);
+
+                i += strlenW(&input[i]) + 1;
+
+                if (input[i] != 0)
+                    output[i - 1] = ',';
+            } while (input[i]);
+
+            return output;
         }
         default:
         {
-            static const WCHAR unhandled[] = {'U','n','h','a','n','d','l','e','d',' ','T','y','p','e',' ','0','x','%','x',' ',' ','d','a','t','a',' ','%','s','\n',0};
-            reg_printfW(unhandled, reg_type,data);
+            output = HeapAlloc(GetProcessHeap(), 0, (size * 2 + 1) * sizeof(WCHAR) );
+
+            for (i = 0; i < size; i++)
+                sprintfW(output + i * 2, print_byteW, data[i]);
+
+            return output;
         }
     }
+}
+
+static BYTE *data_default(const DWORD type, DWORD *size_out)
+{
+    static const WCHAR unhandled[] = {'\t','%','s','\n',0};
+    BYTE *output;
+
+    switch (type){
+        case REG_SZ:
+        case REG_EXPAND_SZ:
+        case REG_MULTI_SZ:
+        {
+            output = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR));
+            * (WCHAR *) output = 0;
+            *size_out = sizeof(WCHAR);
+            return output;
+        }
+        case REG_DWORD:
+        case REG_DWORD_BIG_ENDIAN:
+        {
+            reg_message(STRING_NAN);
+            return NULL;
+        }
+        case REG_BINARY:
+        {
+            output = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
+            * (DWORD *) output = 0;
+            *size_out = sizeof(DWORD);
+            return output;
+        }
+        default:
+        {
+            reg_message(STRING_UNHANDLED_TYPE);
+            reg_printfW(unhandled, type_get_wchar(type));
+            return NULL;
+        }
+    }
+}
+
+static BYTE *wchar_get_data(const WCHAR *input,     const DWORD type,
+                            const WCHAR seperator,  DWORD *size_out)
+{
+    static const WCHAR unhandled[] = {'\t','%','s','\n',0};
+    BYTE *output = NULL;
+    DWORD i;
+
+    if (!input)
+        return data_default(type, size_out);
 
-    return out_data;
+    switch (type){
+        case REG_SZ:
+        case REG_EXPAND_SZ:
+        {
+            i = (strlenW(input) + 1) * sizeof(WCHAR);
+            output = HeapAlloc(GetProcessHeap(), 0, i);
+            lstrcpyW((WCHAR *) output, input);
+            *size_out = i;
+            return output;
+        }
+        case REG_DWORD:
+        case REG_DWORD_BIG_ENDIAN:
+        {
+            WCHAR *temp;
+
+            if (input[0] == '0' && (input[1] == 'x' || input[1] == 'X'))
+                i = strtoulW(input, &temp, 16);
+            else
+                i = strtoulW(input, &temp, 10);
+
+            if (temp == input || temp[0]) {
+                reg_message(STRING_NAN);
+                return NULL;
+            }
+
+            if (type == REG_DWORD_BIG_ENDIAN)
+                i = switch_endian(i);
+
+            output = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
+            * (DWORD *) output = i;
+            *size_out = sizeof(DWORD);
+            return output;
+        }
+        case REG_MULTI_SZ:
+        {
+            WCHAR *temp = HeapAlloc(GetProcessHeap(), 0, (strlenW(input) + 1) * sizeof(WCHAR));
+            DWORD p;
+
+            for (i = 0, p = 0; i <= strlenW(input); i++, p++)
+            {
+                if (input[i] == seperator)
+                    temp[p] = 0;
+                else if (seperator == 0 && input[i] == '\\' && input[i + 1] == '0')
+                {
+                    temp[p] = 0;
+                    i++;
+                }
+                else
+                    temp[p] = input[i];
+            }
+            temp[p++] = 0;
+
+            *size_out = p * sizeof(WCHAR);
+            return HeapReAlloc(GetProcessHeap(), 0, temp, p * sizeof(WCHAR));
+        }
+        case REG_BINARY:
+        {
+            BYTE * temp = HeapAlloc(GetProcessHeap(), 0, strlenW(input));
+            DWORD p;
+
+            for (i = 0, p = 0; i < strlenW(input); i++, p++)
+            {
+                if (input[i] >= '0' && input[i] <= '9')
+                    temp[p] = input[i] - '0';
+                else if (input[i] >= 'a' && input[i] <= 'f')
+                    temp[p] = input[i] - 'a' + 10;
+                else if (input[i] >= 'A' && input[i] <= 'F')
+                    temp[p] = input[i] - 'A' + 10;
+                else
+                    break;
+            }
+
+            if (p % 2)
+            {
+                reg_message(STRING_BINARY_INCMPLT);
+                return NULL;
+            }
+
+            p /= 2;
+
+            for (i = 0; i < p; i++)
+                temp[i] = (temp[i * 2] << 4) | temp[i * 2 + 1];
+
+            *size_out = p;
+            return HeapReAlloc(GetProcessHeap(), 0, temp, p);
+        }
+        default:
+        {
+            reg_message(STRING_UNHANDLED_TYPE);
+            reg_printfW(unhandled, type_get_wchar(type));
+            return NULL;
+        }
+    }
 }
 
 static int reg_add(WCHAR *key_name, WCHAR *value_name, BOOL value_empty,
@@ -272,7 +438,15 @@ static int reg_add(WCHAR *key_name, WCHAR *value_name, BOOL value_empty,
         }
 
         if (data)
-            reg_data = get_regdata(data,reg_type,separator,&reg_count);
+        {
+            reg_data = wchar_get_data(data, reg_type, separator, &reg_count);
+            if (!reg_data)
+            {
+                RegCloseKey(subkey);
+                reg_message(STRING_ERROR);
+                return 1;
+            }
+        }
 
         RegSetValueExW(subkey,value_name,0,reg_type,reg_data,reg_count);
         HeapFree(GetProcessHeap(),0,reg_data);
diff --git a/programs/reg/reg.h b/programs/reg/reg.h
index 1c2ae83..e593695 100644
--- a/programs/reg/reg.h
+++ b/programs/reg/reg.h
@@ -31,3 +31,6 @@
 #define STRING_NO_REMOTE        108
 #define STRING_CANNOT_FIND      109
 #define STRING_ERROR            110
+#define STRING_UNHANDLED_TYPE   111
+#define STRING_NAN              112
+#define STRING_BINARY_INCMPLT   113
diff --git a/programs/reg/reg.rc b/programs/reg/reg.rc
index 5d259c7..3180fd5 100644
--- a/programs/reg/reg.rc
+++ b/programs/reg/reg.rc
@@ -36,4 +36,7 @@ STRINGTABLE
     STRING_NO_REMOTE, "Error: Unable to access remote machine\n"
     STRING_CANNOT_FIND, "Error: The system was unable to find the specified registry key or value\n"
     STRING_ERROR, "Error: An internal error occurred\n"
+    STRING_UNHANDLED_TYPE, "Error: Unhandled Type"
+    STRING_NAN, "Error: This type requires /d to be a number\n"
+    STRING_BINARY_INCMPLT, "Error: REG_BINARY input must have even number of nibbles\n"
 }
diff --git a/programs/reg/tests/reg.c b/programs/reg/tests/reg.c
index 5b79aed..75ff631 100644
--- a/programs/reg/tests/reg.c
+++ b/programs/reg/tests/reg.c
@@ -150,11 +150,11 @@ static void test_add(void)
     todo_wine ok(r == REG_EXIT_FAILURE || broken(r == REG_EXIT_SUCCESS /* WinXP */),
        "got exit code %d, expected 0\n", r);
     run_reg_exe("reg add HKCU\\" KEY_BASE " /v dword2 /t REG_DWORD /d zzz /f", &r);
-    todo_wine ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
+    ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
     run_reg_exe("reg add HKCU\\" KEY_BASE " /v dword3 /t REG_DWORD /d deadbeef /f", &r);
-    todo_wine ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
+    ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
     run_reg_exe("reg add HKCU\\" KEY_BASE " /v dword4 /t REG_DWORD /d 123xyz /f", &r);
-    todo_wine ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
+    ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
 
     run_reg_exe("reg add HKCU\\" KEY_BASE " /v dword5 /t reg_dword /d 12345678 /f", &r);
     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
@@ -168,17 +168,16 @@ static void test_add(void)
     ok(err == ERROR_SUCCESS, "RegQueryValueEx failed: got %d\n", err);
     ok(type == REG_DWORD, "got wrong type %d, expected %d\n", type, REG_DWORD);
     ok(size == sizeof(DWORD), "got wrong size %d, expected %d\n", size, (int)sizeof(DWORD));
-    todo_wine ok(dword == 123 || broken(dword == 0123 /* WinXP */),
+    ok(dword == 123 || broken(dword == 0123 /* WinXP */),
                  "got wrong data %d, expected %d\n", dword, 123);
 
     run_reg_exe("reg add HKCU\\" KEY_BASE " /v dword7 /t reg_dword /d 0xabcdefg /f", &r);
-    todo_wine ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
+    ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r);
 
     run_reg_exe("reg add HKCU\\" KEY_BASE " /v dword8 /t REG_dword /d 0xdeadbeef /f", &r);
     ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r);
     dword = 0xdeadbeef;
-    verify_reg(hkey, "dword8", REG_DWORD, &dword, sizeof(dword),
-               (sizeof(long) > sizeof(DWORD)) ? 0 : TODO_REG_DATA);
+    verify_reg(hkey, "dword8", REG_DWORD, &dword, sizeof(dword), 0);
 
     /* REG_DWORD_LITTLE_ENDIAN */
     run_reg_exe("reg add HKCU\\" KEY_BASE " /v DWORD_LE /t REG_DWORD_LITTLE_ENDIAN /d 456 /f", &r);
-- 
2.1.1




More information about the wine-patches mailing list