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 LPBYTE
get_regdata(const WCHAR
*data
, DWORD reg_type
, WCHAR separator
, DWORD
*reg_count
)
53 static const WCHAR empty
;
54 LPBYTE out_data
= NULL
;
57 if (!data
) data
= &empty
;
65 *reg_count
= (lstrlenW(data
) + 1) * sizeof(WCHAR
);
66 out_data
= malloc(*reg_count
);
67 lstrcpyW((LPWSTR
)out_data
,data
);
71 /* case REG_DWORD_LITTLE_ENDIAN: */
72 case REG_DWORD_BIG_ENDIAN
: /* Yes, this is correct! */
76 val
= wcstoul(data
, &rest
, (towlower(data
[1]) == 'x') ? 16 : 10);
77 if (*rest
|| data
[0] == '-' || (val
== ~0u && errno
== ERANGE
)) {
78 output_message(STRING_MISSING_INTEGER
);
81 *reg_count
= sizeof(DWORD
);
82 out_data
= malloc(*reg_count
);
83 ((LPDWORD
)out_data
)[0] = val
;
89 int i
= 0, destByteIndex
= 0, datalen
= lstrlenW(data
);
90 *reg_count
= ((datalen
+ datalen
% 2) / 2) * sizeof(BYTE
);
91 out_data
= malloc(*reg_count
);
94 hex1
= hexchar_to_byte(data
[i
++]);
97 out_data
[destByteIndex
++] = hex1
;
99 for(;i
+ 1 < datalen
;i
+= 2)
101 hex0
= hexchar_to_byte(data
[i
]);
102 hex1
= hexchar_to_byte(data
[i
+ 1]);
103 if(hex0
== 0xFF || hex1
== 0xFF)
105 out_data
[destByteIndex
++] = (hex0
<< 4) | hex1
;
109 /* cleanup, print error */
111 output_message(STRING_MISSING_HEXDATA
);
117 int i
, destindex
, len
= lstrlenW(data
);
118 WCHAR
*buffer
= malloc((len
+ 2) * sizeof(WCHAR
));
120 for (i
= 0, destindex
= 0; i
< len
; i
++, destindex
++)
122 if (!separator
&& data
[i
] == '\\' && data
[i
+ 1] == '0')
124 buffer
[destindex
] = 0;
127 else if (data
[i
] == separator
)
128 buffer
[destindex
] = 0;
130 buffer
[destindex
] = data
[i
];
132 if (destindex
&& !buffer
[destindex
- 1] && (!buffer
[destindex
] || destindex
== 1))
135 output_message(STRING_INVALID_STRING
);
139 buffer
[destindex
] = 0;
140 if (destindex
&& buffer
[destindex
- 1])
141 buffer
[++destindex
] = 0;
142 *reg_count
= (destindex
+ 1) * sizeof(WCHAR
);
143 return (BYTE
*)buffer
;
146 output_message(STRING_UNHANDLED_TYPE
, reg_type
, data
);
152 static int run_add(HKEY root
, WCHAR
*path
, WCHAR
*value_name
, BOOL value_empty
,
153 WCHAR
*type
, WCHAR separator
, WCHAR
*data
, BOOL force
)
157 if (RegCreateKeyExW(root
, path
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
158 KEY_READ
|KEY_WRITE
, NULL
, &key
, NULL
))
160 output_message(STRING_INVALID_KEY
);
164 if (value_name
|| value_empty
|| data
)
168 BYTE
* reg_data
= NULL
;
172 if (RegQueryValueExW(key
, value_name
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
174 if (!ask_confirm(STRING_OVERWRITE_VALUE
, value_name
))
177 output_message(STRING_CANCELLED
);
183 reg_type
= wchar_get_type(type
);
187 output_message(STRING_UNSUPPORTED_TYPE
, type
);
190 if ((reg_type
== REG_DWORD
|| reg_type
== REG_DWORD_BIG_ENDIAN
) && !data
)
193 output_message(STRING_INVALID_CMDLINE
);
197 if (!(reg_data
= get_regdata(data
, reg_type
, separator
, ®_count
)))
203 RegSetValueExW(key
, value_name
, 0, reg_type
, reg_data
, reg_count
);
208 output_message(STRING_SUCCESS
);
213 int reg_add(int argc
, WCHAR
*argvW
[])
216 WCHAR
*path
, *key_name
, *value_name
= NULL
, *type
= NULL
, *data
= NULL
, separator
= '\0';
217 BOOL value_empty
= FALSE
, force
= FALSE
;
220 if (!parse_registry_key(argvW
[2], &root
, &path
, &key_name
))
223 for (i
= 3; i
< argc
; i
++)
227 if (argvW
[i
][0] != '/' && argvW
[i
][0] != '-')
232 if (!lstrcmpiW(str
, L
"ve"))
234 if (value_empty
) goto invalid
;
238 else if (!str
[0] || str
[1])
241 switch (towlower(*str
))
244 if (value_name
|| !(value_name
= argvW
[++i
]))
248 if (type
|| !(type
= argvW
[++i
]))
252 if (data
|| !(data
= argvW
[++i
]))
257 if (separator
|| !str
|| lstrlenW(str
) != 1)
262 if (force
) goto invalid
;
270 if (value_name
&& value_empty
)
273 return run_add(root
, path
, value_name
, value_empty
, type
, separator
, data
, force
);
276 output_message(STRING_INVALID_CMDLINE
);