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 BYTE
*get_regdata(const WCHAR
*data
, DWORD reg_type
, WCHAR separator
, DWORD
*size_bytes
)
53 static const WCHAR empty
;
54 LPBYTE out_data
= NULL
;
58 if (!data
) data
= &empty
;
66 *size_bytes
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
67 out_data
= malloc(*size_bytes
);
68 lstrcpyW((LPWSTR
)out_data
,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_INTEGER
);
82 *size_bytes
= sizeof(DWORD
);
83 out_data
= malloc(*size_bytes
);
84 ((LPDWORD
)out_data
)[0] = val
;
90 int i
= 0, destByteIndex
= 0, datalen
= lstrlenW(data
);
91 *size_bytes
= ((datalen
+ datalen
% 2) / 2) * sizeof(BYTE
);
92 out_data
= malloc(*size_bytes
);
95 hex1
= hexchar_to_byte(data
[i
++]);
98 out_data
[destByteIndex
++] = hex1
;
100 for(;i
+ 1 < datalen
;i
+= 2)
102 hex0
= hexchar_to_byte(data
[i
]);
103 hex1
= hexchar_to_byte(data
[i
+ 1]);
104 if(hex0
== 0xFF || hex1
== 0xFF)
106 out_data
[destByteIndex
++] = (hex0
<< 4) | hex1
;
110 /* cleanup, print error */
112 output_message(STRING_MISSING_HEXDATA
);
118 int i
, destindex
, len
= lstrlenW(data
);
119 WCHAR
*buffer
= malloc((len
+ 2) * sizeof(WCHAR
));
121 for (i
= 0, destindex
= 0; i
< len
; i
++, destindex
++)
123 if (!separator
&& data
[i
] == '\\' && data
[i
+ 1] == '0')
125 buffer
[destindex
] = 0;
128 else if (data
[i
] == separator
)
129 buffer
[destindex
] = 0;
131 buffer
[destindex
] = data
[i
];
133 if (destindex
&& !buffer
[destindex
- 1] && (!buffer
[destindex
] || destindex
== 1))
136 output_message(STRING_INVALID_STRING
);
140 buffer
[destindex
] = 0;
141 if (destindex
&& buffer
[destindex
- 1])
142 buffer
[++destindex
] = 0;
143 *size_bytes
= (destindex
+ 1) * sizeof(WCHAR
);
144 return (BYTE
*)buffer
;
147 output_message(STRING_UNHANDLED_TYPE
, reg_type
, data
);
153 static int run_add(HKEY root
, WCHAR
*path
, WCHAR
*value_name
, BOOL value_empty
,
154 WCHAR
*type
, WCHAR separator
, WCHAR
*data
, BOOL force
)
157 DWORD data_type
, data_size
;
158 BYTE
*reg_data
= NULL
;
161 if (RegCreateKeyExW(root
, path
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
162 KEY_READ
|KEY_WRITE
, NULL
, &hkey
, NULL
))
164 output_message(STRING_ACCESS_DENIED
);
170 if (RegQueryValueExW(hkey
, value_name
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
172 if (!ask_confirm(STRING_OVERWRITE_VALUE
, value_name
))
175 output_message(STRING_CANCELLED
);
181 data_type
= wchar_get_type(type
);
183 if (data_type
== ~0u)
186 output_message(STRING_UNSUPPORTED_TYPE
, type
);
190 if ((data_type
== REG_DWORD
|| data_type
== REG_DWORD_BIG_ENDIAN
) && !data
)
193 output_message(STRING_INVALID_CMDLINE
);
197 if (!(reg_data
= get_regdata(data
, data_type
, separator
, &data_size
)))
203 rc
= RegSetValueExW(hkey
, value_name
, 0, data_type
, reg_data
, data_size
);
210 output_message(STRING_ACCESS_DENIED
);
214 output_message(STRING_SUCCESS
);
219 int reg_add(int argc
, WCHAR
*argvW
[])
222 WCHAR
*path
, *value_name
= NULL
, *type
= NULL
, *data
= NULL
, separator
= '\0';
223 BOOL value_empty
= FALSE
, force
= FALSE
;
226 if (!parse_registry_key(argvW
[2], &root
, &path
))
229 for (i
= 3; i
< argc
; i
++)
233 if (argvW
[i
][0] != '/' && argvW
[i
][0] != '-')
238 if (!lstrcmpiW(str
, L
"ve"))
240 if (value_empty
) goto invalid
;
244 else if (!lstrcmpiW(str
, L
"reg:32") || !lstrcmpiW(str
, L
"reg:64"))
246 else if (!str
[0] || str
[1])
249 switch (towlower(*str
))
252 if (value_name
|| !(value_name
= argvW
[++i
]))
256 if (type
|| !(type
= argvW
[++i
]))
260 if (data
|| !(data
= argvW
[++i
]))
265 if (separator
|| !str
|| lstrlenW(str
) != 1)
270 if (force
) goto invalid
;
278 if (value_name
&& value_empty
)
281 return run_add(root
, path
, value_name
, value_empty
, type
, separator
, data
, force
);
284 output_message(STRING_INVALID_SYNTAX
);
285 output_message(STRING_FUNC_HELP
, wcsupr(argvW
[1]));