reg: Split 'add' functions from reg.c.

Signed-off-by: Hugh McMaster <hugh.mcmaster@outlook.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hugh McMaster 2021-03-17 23:38:06 +11:00 committed by Alexandre Julliard
parent 81a3eecc3c
commit 7e7d92d5e9
4 changed files with 218 additions and 192 deletions

View File

@ -5,6 +5,7 @@ DELAYIMPORTS = user32
EXTRADLLFLAGS = -mconsole -municode -mno-cygwin
C_SRCS = \
add.c \
delete.c \
export.c \
import.c \

213
programs/reg/add.c Normal file
View File

@ -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 = &empty;
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, &reg_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;
}

View File

@ -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 = &empty;
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, &reg_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;

View File

@ -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);