Signed-off-by: Hugh McMaster hugh.mcmaster@outlook.com --- programs/reg/Makefile.in | 1 + programs/reg/add.c | 213 +++++++++++++++++++++++++++++++++++++++ programs/reg/reg.c | 192 ----------------------------------- programs/reg/reg.h | 4 + 4 files changed, 218 insertions(+), 192 deletions(-) create mode 100644 programs/reg/add.c
diff --git a/programs/reg/Makefile.in b/programs/reg/Makefile.in index 161be0062f1..5ef0d0854aa 100644 --- a/programs/reg/Makefile.in +++ b/programs/reg/Makefile.in @@ -5,6 +5,7 @@ DELAYIMPORTS = user32 EXTRADLLFLAGS = -mconsole -municode -mno-cygwin
C_SRCS = \ + add.c \ delete.c \ export.c \ import.c \ diff --git a/programs/reg/add.c b/programs/reg/add.c new file mode 100644 index 00000000000..2d8521f9234 --- /dev/null +++ b/programs/reg/add.c @@ -0,0 +1,213 @@ +/* + * Copyright 2016-2017, 2021 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 <errno.h> +#include <stdlib.h> +#include <windows.h> +#include <wine/heap.h> +#include "reg.h" + +static DWORD wchar_get_type(const WCHAR *type_name) +{ + DWORD i; + + if (!type_name) + return REG_SZ; + + for (i = 0; i < ARRAY_SIZE(type_rels); i++) + { + if (!wcsicmp(type_rels[i].name, type_name)) + return type_rels[i].type; + } + + return ~0u; +} + +/* hexchar_to_byte from programs/regedit/hexedit.c */ +static inline BYTE hexchar_to_byte(WCHAR ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else + return -1; +} + +static LPBYTE get_regdata(const WCHAR *data, DWORD reg_type, WCHAR separator, DWORD *reg_count) +{ + static const WCHAR empty; + LPBYTE out_data = NULL; + *reg_count = 0; + + if (!data) data = ∅ + + switch (reg_type) + { + case REG_NONE: + case REG_SZ: + case REG_EXPAND_SZ: + { + *reg_count = (lstrlenW(data) + 1) * sizeof(WCHAR); + out_data = heap_xalloc(*reg_count); + lstrcpyW((LPWSTR)out_data,data); + break; + } + case REG_DWORD: + /* case REG_DWORD_LITTLE_ENDIAN: */ + case REG_DWORD_BIG_ENDIAN: /* Yes, this is correct! */ + { + LPWSTR rest; + unsigned long val; + val = wcstoul(data, &rest, (towlower(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 = heap_xalloc(*reg_count); + ((LPDWORD)out_data)[0] = val; + break; + } + case REG_BINARY: + { + BYTE hex0, hex1; + int i = 0, destByteIndex = 0, datalen = lstrlenW(data); + *reg_count = ((datalen + datalen % 2) / 2) * sizeof(BYTE); + out_data = heap_xalloc(*reg_count); + if(datalen % 2) + { + hex1 = hexchar_to_byte(data[i++]); + if(hex1 == 0xFF) + goto no_hex_data; + out_data[destByteIndex++] = hex1; + } + for(;i + 1 < datalen;i += 2) + { + hex0 = hexchar_to_byte(data[i]); + hex1 = hexchar_to_byte(data[i + 1]); + if(hex0 == 0xFF || hex1 == 0xFF) + goto no_hex_data; + out_data[destByteIndex++] = (hex0 << 4) | hex1; + } + break; + no_hex_data: + /* cleanup, print error */ + heap_free(out_data); + output_message(STRING_MISSING_HEXDATA); + out_data = NULL; + break; + } + case REG_MULTI_SZ: + { + int i, destindex, len = lstrlenW(data); + WCHAR *buffer = heap_xalloc((len + 2) * sizeof(WCHAR)); + + for (i = 0, destindex = 0; i < len; i++, destindex++) + { + if (!separator && data[i] == '\' && data[i + 1] == '0') + { + buffer[destindex] = 0; + i++; + } + else if (data[i] == separator) + buffer[destindex] = 0; + else + buffer[destindex] = data[i]; + + if (destindex && !buffer[destindex - 1] && (!buffer[destindex] || destindex == 1)) + { + heap_free(buffer); + output_message(STRING_INVALID_STRING); + return NULL; + } + } + buffer[destindex] = 0; + if (destindex && buffer[destindex - 1]) + buffer[++destindex] = 0; + *reg_count = (destindex + 1) * sizeof(WCHAR); + return (BYTE *)buffer; + } + default: + output_message(STRING_UNHANDLED_TYPE, reg_type, data); + } + + return out_data; +} + +int reg_add(HKEY root, WCHAR *path, WCHAR *value_name, BOOL value_empty, + WCHAR *type, WCHAR separator, WCHAR *data, BOOL force) +{ + HKEY key; + + if (RegCreateKeyW(root, path, &key) != ERROR_SUCCESS) + { + output_message(STRING_INVALID_KEY); + return 1; + } + + if (value_name || value_empty || data) + { + DWORD reg_type; + DWORD reg_count = 0; + BYTE* reg_data = NULL; + + if (!force) + { + if (RegQueryValueExW(key, value_name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + if (!ask_confirm(STRING_OVERWRITE_VALUE, value_name)) + { + RegCloseKey(key); + output_message(STRING_CANCELLED); + return 0; + } + } + } + + reg_type = wchar_get_type(type); + if (reg_type == ~0u) + { + RegCloseKey(key); + output_message(STRING_UNSUPPORTED_TYPE, type); + return 1; + } + if ((reg_type == REG_DWORD || reg_type == REG_DWORD_BIG_ENDIAN) && !data) + { + RegCloseKey(key); + output_message(STRING_INVALID_CMDLINE); + return 1; + } + + if (!(reg_data = get_regdata(data, reg_type, separator, ®_count))) + { + RegCloseKey(key); + return 1; + } + + RegSetValueExW(key, value_name, 0, reg_type, reg_data, reg_count); + heap_free(reg_data); + } + + RegCloseKey(key); + output_message(STRING_SUCCESS); + + return 0; +} diff --git a/programs/reg/reg.c b/programs/reg/reg.c index 079ed9b1a1e..071fb6f88ea 100644 --- a/programs/reg/reg.c +++ b/programs/reg/reg.c @@ -17,8 +17,6 @@ */
#include <windows.h> -#include <errno.h> -#include <stdio.h> #include <stdlib.h> #include <wine/debug.h> #include <wine/heap.h> @@ -213,136 +211,6 @@ HKEY path_get_rootkey(const WCHAR *path) return NULL; }
-static DWORD wchar_get_type(const WCHAR *type_name) -{ - DWORD i; - - if (!type_name) - return REG_SZ; - - for (i = 0; i < ARRAY_SIZE(type_rels); i++) - { - if (!wcsicmp(type_rels[i].name, type_name)) - return type_rels[i].type; - } - - return ~0u; -} - -/* hexchar_to_byte from programs/regedit/hexedit.c */ -static inline BYTE hexchar_to_byte(WCHAR ch) -{ - if (ch >= '0' && ch <= '9') - return ch - '0'; - else if (ch >= 'a' && ch <= 'f') - return ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') - return ch - 'A' + 10; - else - return -1; -} - -static LPBYTE get_regdata(const WCHAR *data, DWORD reg_type, WCHAR separator, DWORD *reg_count) -{ - static const WCHAR empty; - LPBYTE out_data = NULL; - *reg_count = 0; - - if (!data) data = ∅ - - switch (reg_type) - { - case REG_NONE: - case REG_SZ: - case REG_EXPAND_SZ: - { - *reg_count = (lstrlenW(data) + 1) * sizeof(WCHAR); - out_data = heap_xalloc(*reg_count); - lstrcpyW((LPWSTR)out_data,data); - break; - } - case REG_DWORD: - /* case REG_DWORD_LITTLE_ENDIAN: */ - case REG_DWORD_BIG_ENDIAN: /* Yes, this is correct! */ - { - LPWSTR rest; - unsigned long val; - val = wcstoul(data, &rest, (towlower(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 = heap_xalloc(*reg_count); - ((LPDWORD)out_data)[0] = val; - break; - } - case REG_BINARY: - { - BYTE hex0, hex1; - int i = 0, destByteIndex = 0, datalen = lstrlenW(data); - *reg_count = ((datalen + datalen % 2) / 2) * sizeof(BYTE); - out_data = heap_xalloc(*reg_count); - if(datalen % 2) - { - hex1 = hexchar_to_byte(data[i++]); - if(hex1 == 0xFF) - goto no_hex_data; - out_data[destByteIndex++] = hex1; - } - for(;i + 1 < datalen;i += 2) - { - hex0 = hexchar_to_byte(data[i]); - hex1 = hexchar_to_byte(data[i + 1]); - if(hex0 == 0xFF || hex1 == 0xFF) - goto no_hex_data; - out_data[destByteIndex++] = (hex0 << 4) | hex1; - } - break; - no_hex_data: - /* cleanup, print error */ - heap_free(out_data); - output_message(STRING_MISSING_HEXDATA); - out_data = NULL; - break; - } - case REG_MULTI_SZ: - { - int i, destindex, len = lstrlenW(data); - WCHAR *buffer = heap_xalloc((len + 2) * sizeof(WCHAR)); - - for (i = 0, destindex = 0; i < len; i++, destindex++) - { - if (!separator && data[i] == '\' && data[i + 1] == '0') - { - buffer[destindex] = 0; - i++; - } - else if (data[i] == separator) - buffer[destindex] = 0; - else - buffer[destindex] = data[i]; - - if (destindex && !buffer[destindex - 1] && (!buffer[destindex] || destindex == 1)) - { - heap_free(buffer); - output_message(STRING_INVALID_STRING); - return NULL; - } - } - buffer[destindex] = 0; - if (destindex && buffer[destindex - 1]) - buffer[++destindex] = 0; - *reg_count = (destindex + 1) * sizeof(WCHAR); - return (BYTE *)buffer; - } - default: - output_message(STRING_UNHANDLED_TYPE, reg_type, data); - } - - return out_data; -} - static BOOL sane_path(const WCHAR *key) { unsigned int i = lstrlenW(key); @@ -362,66 +230,6 @@ static BOOL sane_path(const WCHAR *key) return TRUE; }
-static int reg_add(HKEY root, WCHAR *path, WCHAR *value_name, BOOL value_empty, - WCHAR *type, WCHAR separator, WCHAR *data, BOOL force) -{ - HKEY key; - - if (RegCreateKeyW(root, path, &key) != ERROR_SUCCESS) - { - output_message(STRING_INVALID_KEY); - return 1; - } - - if (value_name || value_empty || data) - { - DWORD reg_type; - DWORD reg_count = 0; - BYTE* reg_data = NULL; - - if (!force) - { - if (RegQueryValueExW(key, value_name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) - { - if (!ask_confirm(STRING_OVERWRITE_VALUE, value_name)) - { - RegCloseKey(key); - output_message(STRING_CANCELLED); - return 0; - } - } - } - - reg_type = wchar_get_type(type); - if (reg_type == ~0u) - { - RegCloseKey(key); - output_message(STRING_UNSUPPORTED_TYPE, type); - return 1; - } - if ((reg_type == REG_DWORD || reg_type == REG_DWORD_BIG_ENDIAN) && !data) - { - RegCloseKey(key); - output_message(STRING_INVALID_CMDLINE); - return 1; - } - - if (!(reg_data = get_regdata(data, reg_type, separator, ®_count))) - { - RegCloseKey(key); - return 1; - } - - RegSetValueExW(key, value_name, 0, reg_type, reg_data, reg_count); - heap_free(reg_data); - } - - RegCloseKey(key); - output_message(STRING_SUCCESS); - - return 0; -} - WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len) { WCHAR *subkey_path; diff --git a/programs/reg/reg.h b/programs/reg/reg.h index c8baaa0f9a9..b14470b2cbf 100644 --- a/programs/reg/reg.h +++ b/programs/reg/reg.h @@ -41,6 +41,10 @@ HKEY path_get_rootkey(const WCHAR *path); WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len); BOOL parse_registry_key(const WCHAR *key, HKEY *root, WCHAR **path, WCHAR **long_key);
+/* add.c */ +int reg_add(HKEY root, WCHAR *path, WCHAR *value_name, BOOL value_empty, + WCHAR *type, WCHAR separator, WCHAR *data, BOOL force); + /* delete.c */ int reg_delete(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name, BOOL value_empty, BOOL value_all, BOOL force);