2 * Copyright 2016-2017, 2021 Hugh McMaster
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 static DWORD
wchar_get_type(const WCHAR
*type_name
)
29 for (i
= 0; i
< ARRAY_SIZE(type_rels
); i
++)
31 if (!wcsicmp(type_rels
[i
].name
, type_name
))
32 return type_rels
[i
].type
;
38 /* hexchar_to_byte from programs/regedit/hexedit.c */
39 static inline BYTE
hexchar_to_byte(WCHAR ch
)
41 if (ch
>= '0' && ch
<= '9')
43 else if (ch
>= 'a' && ch
<= 'f')
45 else if (ch
>= 'A' && ch
<= 'F')
51 static BOOL
get_regdata(const WCHAR
*data
, DWORD reg_type
, WCHAR separator
,
52 BYTE
**data_bytes
, DWORD
*size_bytes
)
54 static const WCHAR empty
;
58 if (!data
) data
= &empty
;
66 *size_bytes
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
67 *data_bytes
= malloc(*size_bytes
);
68 lstrcpyW((WCHAR
*)*data_bytes
, data
);
72 /* case REG_DWORD_LITTLE_ENDIAN: */
73 case REG_DWORD_BIG_ENDIAN
: /* Yes, this is correct! */
77 val
= wcstoul(data
, &rest
, (towlower(data
[1]) == 'x') ? 16 : 10);
78 if (*rest
|| data
[0] == '-' || (val
== ~0u && errno
== ERANGE
)) {
79 output_message(STRING_MISSING_NUMBER
);
82 *size_bytes
= sizeof(DWORD
);
83 *data_bytes
= malloc(*size_bytes
);
84 *(DWORD
*)*data_bytes
= val
;
92 val
= _wcstoui64(data
, &rest
, (towlower(data
[1]) == 'x') ? 16 : 10);
93 if (*rest
|| (val
== ~0ull && errno
== ERANGE
))
95 output_message(STRING_MISSING_NUMBER
);
98 *size_bytes
= sizeof(val
);
99 *data_bytes
= malloc(*size_bytes
);
100 *(UINT64
*)*data_bytes
= val
;
105 BYTE hex0
, hex1
, *ptr
;
106 int i
= 0, destByteIndex
= 0, datalen
= lstrlenW(data
);
108 if (!datalen
) return TRUE
;
110 *size_bytes
= ((datalen
+ datalen
% 2) / 2) * sizeof(BYTE
);
111 *data_bytes
= malloc(*size_bytes
);
115 hex1
= hexchar_to_byte(data
[i
++]);
118 *data_bytes
[destByteIndex
++] = hex1
;
123 for (; i
+ 1 < datalen
; i
+= 2)
125 hex0
= hexchar_to_byte(data
[i
]);
126 hex1
= hexchar_to_byte(data
[i
+ 1]);
127 if (hex0
== 0xFF || hex1
== 0xFF)
129 ptr
[destByteIndex
++] = (hex0
<< 4) | hex1
;
136 output_message(STRING_MISSING_HEXDATA
);
141 int i
, destindex
, len
= lstrlenW(data
);
142 WCHAR
*buffer
= malloc((len
+ 2) * sizeof(WCHAR
));
144 for (i
= 0, destindex
= 0; i
< len
; i
++, destindex
++)
146 if (!separator
&& data
[i
] == '\\' && data
[i
+ 1] == '0')
148 buffer
[destindex
] = 0;
151 else if (data
[i
] == separator
)
152 buffer
[destindex
] = 0;
154 buffer
[destindex
] = data
[i
];
156 if (destindex
&& !buffer
[destindex
- 1] && (!buffer
[destindex
] || destindex
== 1))
159 output_message(STRING_INVALID_STRING
);
163 buffer
[destindex
] = 0;
164 if (destindex
&& buffer
[destindex
- 1])
165 buffer
[++destindex
] = 0;
166 *size_bytes
= (destindex
+ 1) * sizeof(WCHAR
);
167 *data_bytes
= (BYTE
*)buffer
;
171 output_message(STRING_UNHANDLED_TYPE
, reg_type
, data
);
177 static int run_add(HKEY root
, WCHAR
*path
, REGSAM sam
, WCHAR
*value_name
, BOOL value_empty
,
178 WCHAR
*type
, WCHAR separator
, WCHAR
*data
, BOOL force
)
181 DWORD dispos
, data_type
, data_size
;
182 BYTE
*reg_data
= NULL
;
185 if (RegCreateKeyExW(root
, path
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
186 KEY_READ
|KEY_WRITE
|sam
, NULL
, &hkey
, &dispos
))
188 output_message(STRING_ACCESS_DENIED
);
192 if (!force
&& dispos
== REG_OPENED_EXISTING_KEY
)
194 if (RegQueryValueExW(hkey
, value_name
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
196 if (!ask_confirm(STRING_OVERWRITE_VALUE
, value_name
))
199 output_message(STRING_CANCELLED
);
205 data_type
= wchar_get_type(type
);
207 if (data_type
== ~0u)
210 output_message(STRING_UNSUPPORTED_TYPE
, type
);
214 if ((data_type
== REG_DWORD
|| data_type
== REG_DWORD_BIG_ENDIAN
) && !data
)
217 output_message(STRING_INVALID_CMDLINE
);
221 if (!get_regdata(data
, data_type
, separator
, ®_data
, &data_size
))
227 rc
= RegSetValueExW(hkey
, value_name
, 0, data_type
, reg_data
, data_size
);
234 output_message(STRING_ACCESS_DENIED
);
238 output_message(STRING_SUCCESS
);
243 int reg_add(int argc
, WCHAR
*argvW
[])
246 WCHAR
*path
, *value_name
= NULL
, *type
= NULL
, *data
= NULL
, separator
= '\0';
247 BOOL value_empty
= FALSE
, force
= FALSE
;
251 if (!parse_registry_key(argvW
[2], &root
, &path
))
254 for (i
= 3; i
< argc
; i
++)
258 if (argvW
[i
][0] != '/' && argvW
[i
][0] != '-')
263 if (!lstrcmpiW(str
, L
"ve"))
265 if (value_empty
) goto invalid
;
269 else if (!lstrcmpiW(str
, L
"reg:32"))
271 if (sam
& KEY_WOW64_32KEY
) goto invalid
;
272 sam
|= KEY_WOW64_32KEY
;
275 else if (!lstrcmpiW(str
, L
"reg:64"))
277 if (sam
& KEY_WOW64_64KEY
) goto invalid
;
278 sam
|= KEY_WOW64_64KEY
;
281 else if (!str
[0] || str
[1])
284 switch (towlower(*str
))
287 if (value_name
|| !(value_name
= argvW
[++i
]))
291 if (type
|| !(type
= argvW
[++i
]))
295 if (data
|| !(data
= argvW
[++i
]))
300 if (separator
|| !str
|| lstrlenW(str
) != 1)
305 if (force
) goto invalid
;
313 if (value_name
&& value_empty
)
316 if (sam
== (KEY_WOW64_32KEY
|KEY_WOW64_64KEY
))
319 return run_add(root
, path
, sam
, value_name
, value_empty
, type
, separator
, data
, force
);
322 output_message(STRING_INVALID_SYNTAX
);
323 output_message(STRING_FUNC_HELP
, wcsupr(argvW
[1]));