[REG] Sync with Wine Staging 1.7.37. CORE-9246
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 3 May 2015 11:30:49 +0000 (11:30 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 3 May 2015 11:30:49 +0000 (11:30 +0000)
svn path=/trunk/; revision=67529

25 files changed:
reactos/base/applications/cmdutils/reg/CMakeLists.txt
reactos/base/applications/cmdutils/reg/lang/bg-BG.rc
reactos/base/applications/cmdutils/reg/lang/cs-CZ.rc
reactos/base/applications/cmdutils/reg/lang/da-DK.rc
reactos/base/applications/cmdutils/reg/lang/de-DE.rc
reactos/base/applications/cmdutils/reg/lang/en-US.rc
reactos/base/applications/cmdutils/reg/lang/es-ES.rc
reactos/base/applications/cmdutils/reg/lang/fr-FR.rc
reactos/base/applications/cmdutils/reg/lang/it-IT.rc
reactos/base/applications/cmdutils/reg/lang/ja-JP.rc
reactos/base/applications/cmdutils/reg/lang/ko-KR.rc
reactos/base/applications/cmdutils/reg/lang/lt-LT.rc
reactos/base/applications/cmdutils/reg/lang/nl-NL.rc
reactos/base/applications/cmdutils/reg/lang/no-NO.rc
reactos/base/applications/cmdutils/reg/lang/pl-PL.rc
reactos/base/applications/cmdutils/reg/lang/pt-PT.rc
reactos/base/applications/cmdutils/reg/lang/ro-RO.rc
reactos/base/applications/cmdutils/reg/lang/ru-RU.rc
reactos/base/applications/cmdutils/reg/lang/sl-SI.rc
reactos/base/applications/cmdutils/reg/lang/sq-AL.rc
reactos/base/applications/cmdutils/reg/lang/sv-SE.rc
reactos/base/applications/cmdutils/reg/lang/uk-UA.rc
reactos/base/applications/cmdutils/reg/reg.c
reactos/base/applications/cmdutils/reg/reg.h
reactos/media/doc/README.WINE

index 4efbd6b..bc63dc2 100644 (file)
@@ -1,5 +1,6 @@
 
 add_executable(reg reg.c reg.rc)
 set_module_type(reg win32cui UNICODE)
-add_importlibs(reg advapi32 user32 shlwapi msvcrt kernel32)
+target_link_libraries(reg wine)
+add_importlibs(reg advapi32 user32 shlwapi msvcrt kernel32 ntdll)
 add_cd_file(TARGET reg DESTINATION reactos/system32 FOR all)
index e328604..51ed3b0 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Грешка: Неправилни параметри на командия ред\n"
     STRING_NO_REMOTE, "Грешка: Неуспешно добавяне на ключове в отдалечената машина\n"
     STRING_CANNOT_FIND, "Грешка: Уредбата не откри указания регистърен ключ или стойност\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index c2cc5f4..3d1886d 100644 (file)
@@ -16,4 +16,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Chyba: Neplatné parametry příkazové řádky\n"
     STRING_NO_REMOTE, "Chyba: Nelze přidat klíče na vzdálený stroj\n"
     STRING_CANNOT_FIND, "Chyba: Systém nenalezl zadaný klíč nebo hodnotu registru\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 8b76b61..a6afd6a 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Fejl: Ugyldige kommando linje parametre\n"
     STRING_NO_REMOTE, "Fejl: Kunne ikke tilføje nøgler til fjern maskinen\n"
     STRING_CANNOT_FIND, "Fejl: Systemet kunne ikke finde, den angivet registrerings nøgle eller værdi\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 3099afd..2170da7 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Fehler: Ungültige Befehlszeilenargumente\n"
     STRING_NO_REMOTE, "Fehler: Konnte Schlüssel nicht zum entfernten Rechner hinzufügen\n"
     STRING_CANNOT_FIND, "Fehler: Der angegebene Schlüssel oder Wert konnte nicht gefunden werden\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 4f322e7..813f70a 100644 (file)
@@ -9,6 +9,9 @@ STRINGTABLE
     STRING_SUCCESS, "The operation completed successfully\n"
     STRING_INVALID_KEY, "Error: Invalid key name\n"
     STRING_INVALID_CMDLINE, "Error: Invalid command line parameters\n"
-    STRING_NO_REMOTE, "Error: Unable to add keys to remote machine\n"
+    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, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index f499711..c88438c 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Error: parámetros de línea de comandos inválidos\n"
     STRING_NO_REMOTE, "Error: No se puede agregar claves al equipo remoto\n"
     STRING_CANNOT_FIND, "Error: El sistema no pudo encontrar la clave o el valor del Registro especificado\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 6f11dd7..c29b329 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Erreur : paramètre de ligne de commande non valable\n"
     STRING_NO_REMOTE, "Erreur : impossible d'ajouter des clés à une machine distante\n"
     STRING_CANNOT_FIND, "Erreur : le système n'a pas pu trouver la clé ou la valeur de registre spécifiée\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 5a9b6a6..6ed7789 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Errore: parametri della linea di comando non validi\n"
     STRING_NO_REMOTE, "Errore: impossibile aggiungere chiavi alla macchina remota\n"
     STRING_CANNOT_FIND, "Errore: il sistema non è riuscito a trovare la chiave di registro o il valore specificati\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 6295850..856e88e 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "エラー: コマンド ライン引数が無効です\n"
     STRING_NO_REMOTE, "エラー: リモート マシンにキーを追加できませんでした\n"
     STRING_CANNOT_FIND, "エラー: システムは指定されたキーまたは値を見つけられませんでした\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index e5ee0cd..139128b 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "에러:올바르지 않은 명령라인 매개변수\n"
     STRING_NO_REMOTE, "에러: 원격 머신에  키를 더하는 것은 가능하지 않습니다\n"
     STRING_CANNOT_FIND, "에러: 이 시스템에서 지정된 레지스트리 키나 값을 찾을수 없습니다\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index ec3af97..32861fc 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Klaida: Netinkami komandos eilutės parametrai\n"
     STRING_NO_REMOTE, "Klaida: Negalima pridėti raktų nuotoliniame kompiuteryje\n"
     STRING_CANNOT_FIND, "Klaida: Sistemai nepavyko rasti nurodyto registro rakto ar reikšmės\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 56e70b8..786d457 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Fout: Foutieve commandoregel-parameters\n"
     STRING_NO_REMOTE, "Fout: Sleutels konden niet toegevoegd worden aan de remote machine\n"
     STRING_CANNOT_FIND, "Fout: Het systeem kon de gespecificeerde registersleutel of waarde niet vinden\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 9297053..f31a061 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Feil: Ugyldige parametere på kommandolinjen\n"
     STRING_NO_REMOTE, "Feil: Kan ikke legge til nøkler på ekstern maskin\n"
     STRING_CANNOT_FIND, "Feil: Systemet klarte ikke finne den angitte registernøkkelen eller -verdien\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 34b10df..991e8d2 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Błąd: Niewłaściwe parametry wiersza poleceń\n"
     STRING_NO_REMOTE, "Błąd: Nie można dodać kluczy do zdalnej maszyny\n"
     STRING_CANNOT_FIND, "Błąd: System nie mógł znaleźć podanej wartości lub klucza rejestru\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index abc38f1..d93c8e5 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Erro: Parâmetros da linha de comandos inválidos\n"
     STRING_NO_REMOTE, "Erro: Incapaz de adicionar chaves à máquina remota\n"
     STRING_CANNOT_FIND, "Erro: O sistema foi incapaz de encontrar a chave de registo ou valor especificado\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 6301650..6845510 100644 (file)
@@ -17,4 +17,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Eroare: Parametri nevalizi pentru linia de comandă\n"
     STRING_NO_REMOTE, "Eroare: Nu se pot adăuga chei pe calculatorul de la distanță\n"
     STRING_CANNOT_FIND, "Eroare: Sistemul nu a putut găsi cheia sau valoarea de registru specificată\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 50f653f..5d3ed89 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Ошибка: Неправильные параметры командной строки\n"
     STRING_NO_REMOTE, "Ошибка: Невозможно добавить ключи на удаленной машине\n"
     STRING_CANNOT_FIND, "Ошибка: Не удалось найти указанный ключ реестра или значение\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 5576a7c..122e4b4 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Napaka: Napačen parameter v ukazni vrstici\n"
     STRING_NO_REMOTE, "Napaka: Na morem dodati ključa na oddaljen računalnik\n"
     STRING_CANNOT_FIND, "Napaka: Sistem ni našel zahtevanega ključa ali vrednosti\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 31d1862..1d3a69f 100644 (file)
@@ -15,4 +15,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Error: Parametrat e pavlefshme ne vijën komanduse\n"
     STRING_NO_REMOTE, "Error: Në pamundësi për të shtuar çelësat në makinë në distancë\n"
     STRING_CANNOT_FIND, "Error: Sistemi nuk ishte në gjendje për të gjetur çelësat të caktuar të regjistrit ose vlerës\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 817fa3f..d72d957 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Fel: ogiltiga kommandoradsparametrar\n"
     STRING_NO_REMOTE, "Fel: Kan inte lägga till nycklar till fjärrmaskin\n"
     STRING_CANNOT_FIND, "Fel: Systemet kunde inte hitta angiven nyckel eller värde i registret\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 9b98233..5afd90d 100644 (file)
@@ -11,4 +11,7 @@ STRINGTABLE
     STRING_INVALID_CMDLINE, "Помилка: неправильні параметри командного рядка\n"
     STRING_NO_REMOTE, "Помилка: неможливо додати ключі на віддаленій машині\n"
     STRING_CANNOT_FIND, "Помилка: не вдалось знайти вказаний ключ реєстру чи значення\n"
+    STRING_ERROR, "Unexpected error: "
+    STRING_UNSUPPORTED_TYPE, "Error: Unsupported type\n"
+    STRING_INVALID_DWORD, "Error: /d must be positive number\n"
 }
index 00c79ff..dcf4898 100644 (file)
 #include <wincon.h>
 #include <shlwapi.h>
 #include <wine/unicode.h>
-
+#include <wine/debug.h>
 #include "reg.h"
 
+#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*A))
+
+#define ERROR_NO_REMOTE         20000
+#define ERROR_INVALID_DWORD     20001
+
+WINE_DEFAULT_DEBUG_CHANNEL(reg);
+
+static const WCHAR empty_wstr[] = {0};
+
+static const WCHAR short_hklm[] = {'H','K','L','M',0};
+static const WCHAR short_hkcu[] = {'H','K','C','U',0};
+static const WCHAR short_hkcr[] = {'H','K','C','R',0};
+static const WCHAR short_hku[] = {'H','K','U',0};
+static const WCHAR short_hkcc[] = {'H','K','C','C',0};
+static const WCHAR long_hklm[] = {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0};
+static const WCHAR long_hkcu[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0};
+static const WCHAR long_hkcr[] = {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0};
+static const WCHAR long_hku[] = {'H','K','E','Y','_','U','S','E','R','S',0};
+static const WCHAR long_hkcc[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0};
+
+static const struct
+{
+    HKEY key;
+    const WCHAR *short_name;
+    const WCHAR *long_name;
+}
+root_rels[] =
+{
+    {HKEY_LOCAL_MACHINE, short_hklm, long_hklm},
+    {HKEY_CURRENT_USER, short_hkcu, long_hkcu},
+    {HKEY_CLASSES_ROOT, short_hkcr, long_hkcr},
+    {HKEY_USERS, short_hku, long_hku},
+    {HKEY_CURRENT_CONFIG, short_hkcc, long_hkcc},
+};
+
+static const WCHAR type_none[] = {'R','E','G','_','N','O','N','E',0};
+static const WCHAR type_sz[] = {'R','E','G','_','S','Z',0};
+static const WCHAR type_expand_sz[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0};
+static const WCHAR type_binary[] = {'R','E','G','_','B','I','N','A','R','Y',0};
+static const WCHAR type_dword[] = {'R','E','G','_','D','W','O','R','D',0};
+static const WCHAR type_dword_le[] = {'R','E','G','_','D','W','O','R','D','_','L','I','T','T','L','E','_','E','N','D','I','A','N',0};
+static const WCHAR type_dword_be[] = {'R','E','G','_','D','W','O','R','D','_','B','I','G','_','E','N','D','I','A','N',0};
+static const WCHAR type_multi_sz[] = {'R','E','G','_','M','U','L','T','I','_','S','Z',0};
+
+static const struct
+{
+    DWORD type;
+    const WCHAR *name;
+}
+type_rels[] =
+{
+    {REG_NONE, type_none},
+    {REG_SZ, type_sz},
+    {REG_EXPAND_SZ, type_expand_sz},
+    {REG_BINARY, type_binary},
+    {REG_DWORD, type_dword},
+    {REG_DWORD_LITTLE_ENDIAN, type_dword_le},
+    {REG_DWORD_BIG_ENDIAN, type_dword_be},
+    {REG_MULTI_SZ, type_multi_sz},
+};
+
 static int reg_printfW(const WCHAR *msg, ...)
 {
     va_list va_args;
@@ -74,293 +135,407 @@ static int reg_message(int msg)
     return reg_printfW(formatW, msg_buffer);
 }
 
-static HKEY get_rootkey(LPWSTR key)
+static void reg_print_error(LSTATUS error_code)
+{
+    switch (error_code)
+    {
+        case ERROR_SUCCESS:
+            return;
+        case ERROR_BAD_COMMAND:
+            reg_message(STRING_INVALID_CMDLINE);
+            return;
+        case ERROR_INVALID_HANDLE:
+            reg_message(STRING_INVALID_KEY);
+            return;
+        case ERROR_NO_REMOTE:
+            reg_message(STRING_NO_REMOTE);
+            return;
+        case ERROR_FILE_NOT_FOUND:
+            reg_message(STRING_CANNOT_FIND);
+            return;
+        case ERROR_UNSUPPORTED_TYPE:
+            reg_message(STRING_UNSUPPORTED_TYPE);
+            return;
+        case ERROR_INVALID_DWORD:
+            reg_message(STRING_INVALID_DWORD);
+            return;
+        default:
+        {
+            static const WCHAR error_string[] = {'%','0','5','d',':',' ','%','s',0};
+            WCHAR *message = NULL;
+            FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,
+                error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (WCHAR *)&message, 0, NULL);
+
+            reg_message(STRING_ERROR);
+            reg_printfW(error_string, error_code, message);
+            LocalFree(message);
+            return;
+        }
+    }
+}
+
+static inline BOOL path_rootname_cmp(const WCHAR *input_path, const WCHAR *rootkey_name)
+{
+    DWORD length = strlenW(rootkey_name);
+
+    return (!strncmpiW(input_path, rootkey_name, length) &&
+            (input_path[length] == 0 || input_path[length] == '\\'));
+}
+
+static HKEY path_get_rootkey(const WCHAR *path)
+{
+    DWORD i;
+
+    for (i = 0; i < ARRAY_SIZE(root_rels); i++)
+    {
+        if (path_rootname_cmp(path, root_rels[i].short_name) ||
+            path_rootname_cmp(path, root_rels[i].long_name))
+            return root_rels[i].key;
+    }
+
+    return NULL;
+}
+
+static LSTATUS path_open(const WCHAR *path, HKEY *out, BOOL create)
 {
-    static const WCHAR szHKLM[] = {'H','K','L','M',0};
-    static const WCHAR szHKEY_LOCAL_MACHINE[] = {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0};
-    static const WCHAR szHKCU[] = {'H','K','C','U',0};
-    static const WCHAR szHKEY_CURRENT_USER[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0};
-    static const WCHAR szHKCR[] = {'H','K','C','R',0};
-    static const WCHAR szHKEY_CLASSES_ROOT[] = {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0};
-    static const WCHAR szHKU[] = {'H','K','U',0};
-    static const WCHAR szHKEY_USERS[] = {'H','K','E','Y','_','U','S','E','R','S',0};
-    static const WCHAR szHKCC[] = {'H','K','C','C',0};
-    static const WCHAR szHKEY_CURRENT_CONFIG[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0};
-
-    if (CompareStringW(CP_ACP,NORM_IGNORECASE,key,4,szHKLM,4)==CSTR_EQUAL ||
-        CompareStringW(CP_ACP,NORM_IGNORECASE,key,18,szHKEY_LOCAL_MACHINE,18)==CSTR_EQUAL)
-        return HKEY_LOCAL_MACHINE;
-    else if (CompareStringW(CP_ACP,NORM_IGNORECASE,key,4,szHKCU,4)==CSTR_EQUAL ||
-             CompareStringW(CP_ACP,NORM_IGNORECASE,key,17,szHKEY_CURRENT_USER,17)==CSTR_EQUAL)
-        return HKEY_CURRENT_USER;
-    else if (CompareStringW(CP_ACP,NORM_IGNORECASE,key,4,szHKCR,4)==CSTR_EQUAL ||
-             CompareStringW(CP_ACP,NORM_IGNORECASE,key,17,szHKEY_CLASSES_ROOT,17)==CSTR_EQUAL)
-        return HKEY_CLASSES_ROOT;
-    else if (CompareStringW(CP_ACP,NORM_IGNORECASE,key,3,szHKU,3)==CSTR_EQUAL ||
-             CompareStringW(CP_ACP,NORM_IGNORECASE,key,10,szHKEY_USERS,10)==CSTR_EQUAL)
-        return HKEY_USERS;
-    else if (CompareStringW(CP_ACP,NORM_IGNORECASE,key,4,szHKCC,4)==CSTR_EQUAL ||
-             CompareStringW(CP_ACP,NORM_IGNORECASE,key,19,szHKEY_CURRENT_CONFIG,19)==CSTR_EQUAL)
-        return HKEY_CURRENT_CONFIG;
-    else return NULL;
+    *out = path_get_rootkey(path);
+
+    path = strchrW(path, '\\');
+    if (path)
+        path++;
+
+    if (create)
+        return RegCreateKeyW(*out, path, out);
+    else
+        return RegOpenKeyW(*out, path, out);
 }
 
-static DWORD get_regtype(LPWSTR type)
+static DWORD wchar_get_type(const WCHAR *type_name)
 {
-    static const WCHAR szREG_SZ[] = {'R','E','G','_','S','Z',0};
-    static const WCHAR szREG_MULTI_SZ[] = {'R','E','G','_','M','U','L','T','I','_','S','Z',0};
-    static const WCHAR szREG_DWORD_BIG_ENDIAN[] = {'R','E','G','_','D','W','O','R','D','_','B','I','G','_','E','N','D','I','A','N',0};
-    static const WCHAR szREG_DWORD[] = {'R','E','G','_','D','W','O','R','D',0};
-    static const WCHAR szREG_BINARY[] = {'R','E','G','_','B','I','N','A','R','Y',0};
-    static const WCHAR szREG_DWORD_LITTLE_ENDIAN[] = {'R','E','G','_','D','W','O','R','D','_','L','I','T','T','L','E','_','E','N','D','I','A','N',0};
-    static const WCHAR szREG_NONE[] = {'R','E','G','_','N','O','N','E',0};
-    static const WCHAR szREG_EXPAND_SZ[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0};
-
-    if (!type)
+    DWORD i;
+
+    if (!type_name)
         return REG_SZ;
 
-    if (lstrcmpiW(type,szREG_SZ)==0) return REG_SZ;
-    if (lstrcmpiW(type,szREG_DWORD)==0) return REG_DWORD;
-    if (lstrcmpiW(type,szREG_MULTI_SZ)==0) return REG_MULTI_SZ;
-    if (lstrcmpiW(type,szREG_EXPAND_SZ)==0) return REG_EXPAND_SZ;
-    if (lstrcmpiW(type,szREG_DWORD_BIG_ENDIAN)==0) return REG_DWORD_BIG_ENDIAN;
-    if (lstrcmpiW(type,szREG_DWORD_LITTLE_ENDIAN)==0) return REG_DWORD_LITTLE_ENDIAN;
-    if (lstrcmpiW(type,szREG_BINARY)==0) return REG_BINARY;
-    if (lstrcmpiW(type,szREG_NONE)==0) return REG_NONE;
+    for (i = 0; i < ARRAY_SIZE(type_rels); i++)
+    {
+        if (!strcmpiW(type_rels[i].name, type_name))
+            return type_rels[i].type;
+    }
 
-    return -1;
+    return ~0u;
 }
 
-static LPBYTE get_regdata(LPWSTR data, DWORD reg_type, WCHAR separator, DWORD *reg_count)
+static LSTATUS wchar_get_data(const WCHAR *input, const DWORD type, const WCHAR separator,
+    DWORD *size_out, BYTE **out)
 {
-    LPBYTE out_data = NULL;
-    *reg_count = 0;
+    DWORD i;
 
-    switch (reg_type)
+    if (!input)
+        input = empty_wstr;
+
+    switch (type)
     {
+        case REG_NONE:
         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;
+            i = (strlenW(input) + 1) * sizeof(WCHAR);
+            *out = HeapAlloc(GetProcessHeap(), 0, i);
+            memcpy(*out, input, i);
+            *size_out = i;
+            return ERROR_SUCCESS;
         }
         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;
+            WCHAR *temp;
+
+            if (input[0] == '0' && (input[1] == 'x' || input[1] == 'X'))
+                i = strtoulW(input, &temp, 16);
+            else
+                i = strtoulW(input, &temp, 10);
+
+            if (input[0] == '-' || temp[0] || temp == input)
+                return ERROR_INVALID_DWORD;
+
+            if (i == 0xffffffff)
+                WINE_FIXME("Check for integer overflow.\n");
+
+            *out = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
+            **(DWORD **) out = i;
+            *size_out = sizeof(DWORD);
+            return ERROR_SUCCESS;
+        }
+        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 this character is the separator, or no separator has been given and these
+                 * characters are "\\0", then add a 0 indicating the end of this string */
+                if ( (separator && input[i] == separator) ||
+                     (!separator && input[i] == '\\' && input[i + 1] == '0') )
+                {
+                    /* If it's the first character or the previous one was a separator */
+                    if (!p || temp[p - 1] == 0)
+                    {
+                        HeapFree(GetProcessHeap(), 0, temp);
+                        return ERROR_INVALID_DATA;
+                    }
+                    temp[p] = 0;
+
+                    if (!separator)
+                        i++;
+                }
+                else
+                    temp[p] = input[i];
             }
-            *reg_count = sizeof(DWORD);
-            out_data = HeapAlloc(GetProcessHeap(),0,*reg_count);
-            ((LPDWORD)out_data)[0] = val;
-            break;
+
+            /* Add a 0 to the end if the string wasn't "", and it wasn't
+             * double-0-terminated already (In the case of a trailing separator) */
+            if (p > 1 && temp[p - 2])
+                temp[p++] = 0;
+
+            *size_out = p * sizeof(WCHAR);
+            *out = (BYTE *) temp;
+            return ERROR_SUCCESS;
+        }
+        case REG_BINARY:
+        {
+            BYTE *temp = HeapAlloc(GetProcessHeap(), 0, strlenW(input));
+            DWORD p, odd;
+
+            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
+                {
+                    HeapFree(GetProcessHeap(), 0, temp);
+                    return ERROR_INVALID_DATA;
+                }
+            }
+
+            *out = temp;
+            odd = p & 1;
+            temp += odd;
+            p >>= 1;
+
+            for (i = 0; i < p; i++)
+                temp[i] = (temp[i * 2] << 4) | temp[i * 2 + 1];
+
+            *size_out = p + odd;
+            return ERROR_SUCCESS;
         }
         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);
+            WINE_FIXME("Add support for registry type: %u\n", type);
+            return ERROR_UNSUPPORTED_TYPE;
         }
     }
-
-    return out_data;
 }
 
-static int reg_add(WCHAR *key_name, WCHAR *value_name, BOOL value_empty,
-    WCHAR *type, WCHAR separator, WCHAR *data, BOOL force)
+static LSTATUS sane_path(const WCHAR *key)
 {
-    static const WCHAR stubW[] = {'A','D','D',' ','-',' ','%','s',
-        ' ','%','s',' ','%','d',' ','%','s',' ','%','s',' ','%','d','\n',0};
-    LPWSTR p;
-    HKEY root,subkey;
+    int i = strlenW(key);
 
-    reg_printfW(stubW, key_name, value_name, value_empty, type, data, force);
+    if (i < 3 || (key[i - 1] == '\\' && key[i - 2] == '\\'))
+        return ERROR_INVALID_HANDLE;
 
-    if (key_name[0]=='\\' && key_name[1]=='\\')
-    {
-        reg_message(STRING_NO_REMOTE);
-        return 1;
-    }
+    if (key[0] == '\\' && key[1] == '\\' && key[2] != '\\')
+        return ERROR_NO_REMOTE;
 
-    p = strchrW(key_name,'\\');
-    if (!p)
-    {
-        reg_message(STRING_INVALID_KEY);
-        return 1;
-    }
-    p++;
+    return ERROR_SUCCESS;
+}
 
-    root = get_rootkey(key_name);
-    if (!root)
-    {
-        reg_message(STRING_INVALID_KEY);
-        return 1;
-    }
+static int reg_add( const WCHAR *key_name,  const WCHAR *value_name,    const BOOL value_empty,
+                    const WCHAR *type,      const WCHAR separator,      const WCHAR *data,
+                    const BOOL force)
+{
+    HKEY key = NULL;
+    LONG err = sane_path(key_name);
+    if (err != ERROR_SUCCESS)
+        goto error;
 
-    if(RegCreateKeyW(root,p,&subkey)!=ERROR_SUCCESS)
+    if (value_name && value_empty)
     {
-        reg_message(STRING_INVALID_KEY);
-        return 1;
+        err = ERROR_BAD_COMMAND;
+        goto error;
     }
 
+    err = path_open(key_name, &key, TRUE);
+    if (err != ERROR_SUCCESS)
+        goto error;
+
     if (value_name || data)
     {
-        DWORD reg_type;
-        DWORD reg_count = 0;
-        BYTE* reg_data = NULL;
+        DWORD size, reg_type;
+        BYTE *data_out;
+
+        if (value_name && !value_name[0])
+            value_name = NULL;
 
-        if (!force)
+        if (type && !type[0])
         {
-            if (RegQueryValueW(subkey,value_name,NULL,NULL)==ERROR_SUCCESS)
-            {
-                /* FIXME:  Prompt for overwrite */
-            }
+            data = NULL;
+            type = NULL;
         }
 
-        reg_type = get_regtype(type);
-        if (reg_type == -1)
+        if (!force && RegQueryValueExW(key, value_name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
         {
-            RegCloseKey(subkey);
-            reg_message(STRING_INVALID_CMDLINE);
-            return 1;
+            WINE_FIXME("Prompt for overwrite\n");
         }
 
-        if (data)
-            reg_data = get_regdata(data,reg_type,separator,&reg_count);
+        reg_type = wchar_get_type(type);
+        if (reg_type == ~0u)
+        {
+            err = ERROR_INVALID_DATATYPE;
+            goto error;
+        }
 
-        RegSetValueExW(subkey,value_name,0,reg_type,reg_data,reg_count);
-        HeapFree(GetProcessHeap(),0,reg_data);
+        err = wchar_get_data(data, reg_type, separator, &size, &data_out);
+        if (err != ERROR_SUCCESS)
+            goto error;
+
+        err = RegSetValueExW(key, value_name, 0, reg_type, data_out, size);
+        HeapFree(GetProcessHeap(), 0, data_out);
+        if (err != ERROR_SUCCESS)
+            goto error;
     }
 
-    RegCloseKey(subkey);
+    RegCloseKey(key);
     reg_message(STRING_SUCCESS);
-
     return 0;
+
+error:
+    RegCloseKey(key);
+    reg_print_error(err);
+    return 1;
 }
 
-static int reg_delete(WCHAR *key_name, WCHAR *value_name, BOOL value_empty,
-    BOOL value_all, BOOL force)
+static int reg_delete(const WCHAR *key_name,    const WCHAR *value_name,  const BOOL value_empty,
+                      const BOOL value_all,     const BOOL force)
 {
-    LPWSTR p;
-    HKEY root,subkey;
-
-    static const WCHAR stubW[] = {'D','E','L','E','T','E',
-        ' ','-',' ','%','s',' ','%','s',' ','%','d',' ','%','d',' ','%','d','\n'
-        ,0};
-    reg_printfW(stubW, key_name, value_name, value_empty, value_all, force);
-
-    if (key_name[0]=='\\' && key_name[1]=='\\')
-    {
-        reg_message(STRING_NO_REMOTE);
-        return 1;
-    }
-
-    p = strchrW(key_name,'\\');
-    if (!p)
+    HKEY key = NULL;
+    LONG err = sane_path(key_name);
+    if (err != ERROR_SUCCESS)
     {
-        reg_message(STRING_INVALID_KEY);
+        reg_print_error(err);
         return 1;
     }
-    p++;
 
-    root = get_rootkey(key_name);
-    if (!root)
-    {
-        reg_message(STRING_INVALID_KEY);
-        return 1;
-    }
-
-    if (value_name && value_empty)
-    {
-        reg_message(STRING_INVALID_CMDLINE);
-        return 1;
-    }
+    err = path_open(key_name, &key, FALSE);
+    if (err != ERROR_SUCCESS)
+        goto error;
 
-    if (value_empty && value_all)
+    /* Mutually exclusive options */
+    if ((!!value_name + !!value_empty + !!value_all) > 1)
     {
-        reg_message(STRING_INVALID_CMDLINE);
-        return 1;
+        err = ERROR_BAD_COMMAND;
+        goto error;
     }
 
     if (!force)
     {
-        /* FIXME:  Prompt for delete */
+        WINE_FIXME("Prompt for delete\n");
     }
 
-    /* Delete subtree only if no /v* option is given */
-    if (!value_name && !value_empty && !value_all)
+    if (value_empty || value_name)
     {
-        if (SHDeleteKeyW(root, p) != ERROR_SUCCESS)
-        {
-            reg_message(STRING_CANNOT_FIND);
-            return 1;
-        }
-        reg_message(STRING_SUCCESS);
-        return 0;
-    }
+        if (value_name && value_name[0])
+            err = RegDeleteValueW(key, value_name);
+        else
+            err = RegDeleteValueW(key, NULL);
 
-    if(RegOpenKeyW(root,p,&subkey)!=ERROR_SUCCESS)
-    {
-        reg_message(STRING_CANNOT_FIND);
-        return 1;
+        if (err != ERROR_SUCCESS)
+            goto error;
     }
-
-    if (value_all)
+    else if (value_all)
     {
-        LPWSTR szValue;
-        DWORD maxValue;
-        DWORD count;
-        LONG rc;
-
-        rc = RegQueryInfoKeyW(subkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-            &maxValue, NULL, NULL, NULL);
-        if (rc != ERROR_SUCCESS)
+        WCHAR *enum_v_name;
+        DWORD count, max_size, this_size, i = 0;
+        BOOL incomplete = FALSE;
+
+        err = RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, NULL, NULL,
+                &count, &max_size, NULL, NULL, NULL);
+        if (err != ERROR_SUCCESS)
+            goto error;
+
+        max_size++;
+        enum_v_name = HeapAlloc(GetProcessHeap(), 0, max_size * sizeof(WCHAR));
+        if (!enum_v_name)
         {
-            /* FIXME: failure */
-            RegCloseKey(subkey);
-            return 1;
+            err = ERROR_NOT_ENOUGH_MEMORY;
+            goto error;
         }
-        maxValue++;
-        szValue = HeapAlloc(GetProcessHeap(),0,maxValue*sizeof(WCHAR));
 
-        while (1)
+        while (i < count)
         {
-            count = maxValue;
-            rc = RegEnumValueW(subkey, 0, szValue, &count, NULL, NULL, NULL, NULL);
-            if (rc == ERROR_SUCCESS)
+            this_size = max_size;
+
+            err = RegEnumValueW(key, i, enum_v_name, &this_size, NULL, NULL, NULL, NULL);
+            if (err != ERROR_SUCCESS)
             {
-                rc = RegDeleteValueW(subkey, szValue);
-                if (rc != ERROR_SUCCESS)
-                    break;
+                reg_print_error(err);
+                incomplete = TRUE;
+                i++;
+                continue;
             }
-            else break;
+
+            err = RegDeleteValueW(key, enum_v_name);
+            if (err != ERROR_SUCCESS)
+            {
+                reg_print_error(err);
+                incomplete = TRUE;
+                i++;
+                continue;
+            }
+
+            count--;
         }
-        if (rc != ERROR_SUCCESS)
+
+        HeapFree(GetProcessHeap(), 0, enum_v_name);
+
+        if (incomplete)
         {
-            /* FIXME  delete failed */
+            RegCloseKey(key);
+            return 1;
         }
     }
-    else if (value_name)
+    /* Delete subtree only if no /v* option is given */
+    else
     {
-        if (RegDeleteValueW(subkey,value_name) != ERROR_SUCCESS)
+        if (key == path_get_rootkey(key_name))
         {
-            RegCloseKey(subkey);
-            reg_message(STRING_CANNOT_FIND);
+            /* "This works well enough on native to make you regret you pressed enter" - stefand */
+            WINE_FIXME("Deleting a root key is not implemented.\n");
+            RegCloseKey(key);
             return 1;
         }
-    }
-    else if (value_empty)
-    {
-        RegSetValueExW(subkey,NULL,0,REG_SZ,NULL,0);
+
+        err = SHDeleteKey(key, NULL);
+        if (err != ERROR_SUCCESS)
+            goto error;
+        err = RegDeleteKeyW(key, empty_wstr);
+        if (err != ERROR_SUCCESS)
+            goto error;
     }
 
-    RegCloseKey(subkey);
+    RegCloseKey(key);
     reg_message(STRING_SUCCESS);
     return 0;
+
+error:
+    RegCloseKey(key);
+    reg_print_error(err);
+    return 1;
 }
 
 static int reg_query(WCHAR *key_name, WCHAR *value_name, BOOL value_empty,
@@ -404,7 +579,7 @@ int wmain(int argc, WCHAR *argvW[])
 
         if (argc < 3)
         {
-            reg_message(STRING_INVALID_CMDLINE);
+            reg_print_error(ERROR_BAD_COMMAND);
             return 1;
         }
         else if (argc == 3 && (!lstrcmpW(argvW[2], slashHelpW) ||
@@ -424,7 +599,14 @@ int wmain(int argc, WCHAR *argvW[])
             else if (!lstrcmpiW(argvW[i], slashTW))
                 type = argvW[++i];
             else if (!lstrcmpiW(argvW[i], slashSW))
-                separator = argvW[++i][0];
+            {
+                if (!argvW[++i][0] || argvW[i][1])
+                {
+                    reg_print_error(ERROR_BAD_COMMAND);
+                    return 1;
+                }
+                separator = argvW[i][0];
+            }
             else if (!lstrcmpiW(argvW[i], slashDW))
                 data = argvW[++i];
             else if (!lstrcmpiW(argvW[i], slashFW))
@@ -440,7 +622,7 @@ int wmain(int argc, WCHAR *argvW[])
 
         if (argc < 3)
         {
-            reg_message(STRING_INVALID_CMDLINE);
+            reg_print_error(ERROR_BAD_COMMAND);
             return 1;
         }
         else if (argc == 3 && (!lstrcmpW(argvW[2], slashHelpW) ||
@@ -471,7 +653,7 @@ int wmain(int argc, WCHAR *argvW[])
 
         if (argc < 3)
         {
-            reg_message(STRING_INVALID_CMDLINE);
+            reg_print_error(ERROR_BAD_COMMAND);
             return 1;
         }
         else if (argc == 3 && (!lstrcmpW(argvW[2], slashHelpW) ||
@@ -495,7 +677,7 @@ int wmain(int argc, WCHAR *argvW[])
     }
     else
     {
-        reg_message(STRING_INVALID_CMDLINE);
+        reg_print_error(ERROR_BAD_COMMAND);
         return 1;
     }
 }
index a321efa..567ce02 100644 (file)
@@ -32,3 +32,6 @@
 #define STRING_INVALID_CMDLINE  107
 #define STRING_NO_REMOTE        108
 #define STRING_CANNOT_FIND      109
+#define STRING_ERROR            110
+#define STRING_UNSUPPORTED_TYPE 111
+#define STRING_INVALID_DWORD    112
index 9595ce4..672e088 100644 (file)
@@ -230,7 +230,7 @@ reactos/dll/cpl/inetcpl               # Synced to Wine-1.7.27
 ReactOS shares the following programs with Winehq.
 
 reactos/base/applications/cmdutils/cscript  # Synced to Wine-1.7.27
-reactos/base/applications/cmdutils/reg      # Synced to Wine-1.7.27
+reactos/base/applications/cmdutils/reg      # Synced to WineStaging-1.7.37
 reactos/base/applications/cmdutils/taskkill # Synced to Wine-1.7.27
 reactos/base/applications/cmdutils/wmic     # Synced to Wine-1.7.27
 reactos/base/applications/cmdutils/wscript  # Synced to WineStaging-1.7.37