winprefs v0.3.2
A registry exporter for programmers.
Loading...
Searching...
No Matches
reg_code.c
1#include "reg_code.h"
2#include "constants.h"
3#include "reg_command.h"
4#include "registry.h"
5
6static wchar_t *get_top_key_string(const wchar_t *reg_path) {
7 wchar_t *out = calloc(20, WL);
8 if (!out) { // LCOV_EXCL_START
9 return nullptr;
10 } // LCOV_EXCL_STOP
11 wmemset(out, L'\0', 20);
12 if (!_wcsnicmp(reg_path, L"HKCU", 4) || !_wcsnicmp(reg_path, L"HKEY_CURRENT_USER", 17)) {
13 wmemcpy(out, L"HKEY_CURRENT_USER", 17);
14 } else if (!_wcsnicmp(reg_path, L"HKCR", 4) || !_wcsnicmp(reg_path, L"HKEY_CLASSES_ROOT", 17)) {
15 wmemcpy(out, L"HKEY_CLASSES_ROOT", 17);
16 } else if (!_wcsnicmp(reg_path, L"HKLM", 4) ||
17 !_wcsnicmp(reg_path, L"HKEY_LOCAL_MACHINE", 18)) {
18 wmemcpy(out, L"HKEY_LOCAL_MACHINE", 18);
19 } else if (!_wcsnicmp(reg_path, L"HKCC", 4) ||
20 !_wcsnicmp(reg_path, L"HKEY_CURRENT_CONFIG", 19)) {
21 wmemcpy(out, L"HKEY_CURRENT_CONFIG", 19);
22 } else if (!_wcsnicmp(reg_path, L"HKU", 3) || !_wcsnicmp(reg_path, L"HKEY_USERS", 10)) {
23 wmemcpy(out, L"HKEY_USERS", 10);
24 } else if (!_wcsnicmp(reg_path, L"HKDD", 4) || !_wcsnicmp(reg_path, L"HKEY_DYN_DATA", 13)) {
25 wmemcpy(out, L"HKEY_DYN_DATA", 13);
26 } else {
27 free(out);
28 out = nullptr;
29 }
30 return out;
31}
32
33static wchar_t *escape_for_c(const wchar_t *input, bool escape_null, size_t length) {
34 if (input == nullptr || (escape_null && length == 0)) { // LCOV_EXCL_START
35 errno = EINVAL;
36 return nullptr;
37 } // LCOV_EXCL_STOP
38 size_t n_chars = !escape_null ? wcslen(input) : length;
39 unsigned i, j;
40 size_t new_n_chars = 0;
41 for (i = 0; i < n_chars; i++) {
42 new_n_chars++;
43 if (input[i] == L'"' || input[i] == L'\\' || (escape_null && input[i] == L'\0')) {
44 new_n_chars++;
45 }
46 }
47 wchar_t *out = calloc(new_n_chars + 1, WL);
48 if (!out) { // LCOV_EXCL_START
49 return nullptr;
50 } // LCOV_EXCL_STOP
51 wmemset(out, L'\0', new_n_chars + 1);
52 if (n_chars == new_n_chars) {
53 wmemcpy(out, input, new_n_chars + 1);
54 return out;
55 }
56 for (i = 0, j = 0; i < n_chars && j < new_n_chars; i++, j++) {
57 if (input[i] == L'"' || input[i] == L'\\' || (escape_null && input[i] == L'\0')) {
58 out[j++] = L'\\';
59 }
60 out[j] = (escape_null && input[i] == L'\0') ? L'0' : input[i];
61 }
62 return out;
63}
64
65static wchar_t *convert_data_for_c(DWORD reg_type, const char *data, size_t data_len) {
66 if (reg_type == REG_BINARY) {
67 size_t i;
68 int j;
69 size_t n_bin_chars = 7 * data_len;
70 size_t new_len = n_bin_chars + 1;
71 wchar_t *bin = calloc(new_len, WL);
72 wchar_t conv[7];
73 if (!bin) { // LCOV_EXCL_START
74 return nullptr;
75 } // LCOV_EXCL_STOP
76 wmemset(bin, L'\0', new_len);
77 for (i = 0, j = 0; i < data_len; i++) {
78 wmemset(conv, L'\0', 7);
79 _snwprintf(conv, 7, L"0x%02x%ls", data[i] & 0xFF, i < (data_len - 1) ? L", " : L"");
80 wcsncat(bin + j, conv, i < (data_len - 1) ? 6 : 4);
81 j += i < (data_len - 1) ? 6 : 4;
82 }
83 size_t s_size = new_len + 4;
84 wchar_t *out = calloc(s_size, WL);
85 if (!out) { // LCOV_EXCL_START
86 free(bin);
87 return nullptr;
88 } // LCOV_EXCL_STOP
89 wmemset(out, L'\0', s_size);
90 _snwprintf(out, s_size, L"{ %ls }", bin);
91 free(bin);
92 return out;
93 }
94 if (reg_type == REG_EXPAND_SZ || reg_type == REG_SZ) {
95 wchar_t *escaped = escape_for_c((wchar_t *)data, false, 0);
96 if (!escaped) { // LCOV_EXCL_START
97 return nullptr;
98 } // LCOV_EXCL_STOP
99 size_t escaped_len = wcslen(escaped);
100 size_t total_size = escaped_len + 1;
101 wchar_t *out = calloc(total_size, WL);
102 if (!out) { // LCOV_EXCL_START
103 return nullptr;
104 } // LCOV_EXCL_STOP
105 wmemset(out, L'\0', total_size);
106 _snwprintf(out, escaped ? total_size : 5, L"%ls", escaped ? escaped : L"NULL");
107 free(escaped);
108 return out;
109 }
110 if (reg_type == REG_MULTI_SZ) {
111 wchar_t *w_data = (wchar_t *)data;
112 size_t w_data_len = (data_len % WL == 0) ? data_len / WL : (data_len / WL) + 1;
113 size_t real_len = determine_multi_sz_size(w_data, w_data_len);
114 if (real_len > 2) {
115 wchar_t *escaped = escape_for_c((wchar_t *)data, true, real_len);
116 if (!escaped) { // LCOV_EXCL_START
117 return nullptr;
118 } // LCOV_EXCL_STOP
119 int req_size = _snwprintf(nullptr, 0, L"%ls\\0", escaped) + 1;
120 wchar_t *out = calloc((size_t)req_size, WL);
121 if (!out) { // LCOV_EXCL_START
122 return nullptr;
123 } // LCOV_EXCL_STOP
124 _snwprintf(out, (size_t)req_size, L"%ls\\0", escaped);
125 free(escaped);
126 return out;
127 }
128 debug_print(L"Skipping incorrectly stored REG_MULTI_SZ (length = %lu, w_data_len = %lu).\n",
129 data_len,
130 w_data_len);
131 return nullptr;
132 }
133 if (reg_type == REG_DWORD) {
134 int req_size = _snwprintf(nullptr, 0, L"%lu", *(DWORD *)data);
135 wchar_t *out = calloc((size_t)(req_size + 1), WL);
136 if (!out) { // LCOV_EXCL_START
137 return nullptr;
138 } // LCOV_EXCL_STOP
139 wmemset(out, 0, (size_t)(req_size + 1));
140 _snwprintf(out, (size_t)req_size + 1, L"%lu", *(DWORD *)data);
141 return out;
142 }
143 if (reg_type == REG_QWORD) {
144 int req_size = _snwprintf(nullptr, 0, L"%llu", *(UINT64 *)data);
145 wchar_t *out = calloc((size_t)(req_size + 1), WL);
146 if (!out) { // LCOV_EXCL_START
147 return nullptr;
148 } // LCOV_EXCL_STOP
149 wmemset(out, 0, (size_t)(req_size + 1));
150 _snwprintf(out, (size_t)(req_size + 1), L"%llu", *(UINT64 *)data);
151 return out;
152 }
153 errno = EINVAL;
154 return nullptr;
155}
156
157bool do_write_c_reg_code(writer_t *writer,
158 const wchar_t *full_path,
159 const wchar_t *prop,
160 const char *value,
161 size_t data_len,
162 unsigned long type) {
163 bool ret = true;
164 wchar_t *escaped_key, *escaped_d, *escaped_prop, *top_key_s, *out;
165 escaped_key = escaped_d = escaped_prop = top_key_s = out = nullptr;
166 wchar_t *first_backslash = wcschr(full_path, L'\\');
167 if (!first_backslash) {
168 goto fail;
169 }
170 wchar_t *subkey = first_backslash + 1;
171 escaped_key = escape_for_c(subkey, false, 0);
172 escaped_d = convert_data_for_c(type, value, data_len);
173 escaped_prop = escape_for_c(prop, false, 0);
174 top_key_s = get_top_key_string(full_path);
175 if (!escaped_key || !top_key_s) {
176 goto fail;
177 }
178 if (type == REG_MULTI_SZ && !escaped_d) {
179 goto cleanup;
180 }
181 wchar_t reg_type[14];
182 memset(reg_type, 0, sizeof(reg_type));
183 switch (type) {
184 case REG_NONE:
185 wcsncpy(reg_type, L"REG_NONE", 8);
186 break;
187 case REG_BINARY:
188 wcsncpy(reg_type, L"REG_BINARY", 10);
189 break;
190 case REG_SZ:
191 wcsncpy(reg_type, L"REG_SZ", 6);
192 break;
193 case REG_EXPAND_SZ:
194 wcsncpy(reg_type, L"REG_EXPAND_SZ", 13);
195 break;
196 case REG_MULTI_SZ:
197 wcsncpy(reg_type, L"REG_MULTI_SZ", 12);
198 break;
199 case REG_DWORD:
200 wcsncpy(reg_type, L"REG_DWORD", 9);
201 break;
202 case REG_QWORD:
203 wcsncpy(reg_type, L"REG_QWORD", 9);
204 break;
205 default: // LCOV_EXCL_START
206 goto cleanup;
207 // LCOV_EXCL_STOP
208 }
209 if (type == REG_DWORD || type == REG_QWORD) {
210 int req_size = _snwprintf(nullptr,
211 0,
212 C_REGSETKEYVALUEW_TEMPLATE_NUMERIC,
213 type == REG_DWORD ? L"d" : L"q",
214 escaped_d,
215 top_key_s,
216 escaped_key,
217 escaped_prop ? escaped_prop : L"",
218 reg_type,
219 type == REG_DWORD ? L"d" : L"q",
220 type == REG_DWORD ? KEYWORD_DWORD : KEYWORD_QWORD);
221 out = calloc((size_t)req_size + 1, WL);
222 if (!out) { // LCOV_EXCL_START
223 return false;
224 } // LCOV_EXCL_STOP
225 wmemset(out, L'\0', (size_t)(req_size + 1));
226 _snwprintf(out,
227 (size_t)(req_size + 1),
228 C_REGSETKEYVALUEW_TEMPLATE_NUMERIC,
229 type == REG_DWORD ? L"d" : L"q",
230 escaped_d ? escaped_d : L"",
231 top_key_s,
232 escaped_key,
233 escaped_prop ? escaped_prop : L"",
234 reg_type,
235 type == REG_DWORD ? L"d" : L"q",
236 type == REG_DWORD ? KEYWORD_DWORD : KEYWORD_QWORD);
237 } else if (type == REG_SZ || type == REG_EXPAND_SZ || type == REG_MULTI_SZ) {
238 int req_size = _snwprintf(nullptr,
239 0,
240 C_REGSETKEYVALUEW_TEMPLATE_SZ,
241 top_key_s,
242 escaped_key,
243 escaped_prop ? escaped_prop : L"",
244 reg_type,
245 escaped_d ? escaped_d : L"",
246 data_len);
247 out = calloc((size_t)req_size + 1, WL);
248 if (!out) { // LCOV_EXCL_START
249 goto fail;
250 } // LCOV_EXCL_STOP
251 wmemset(out, L'\0', (size_t)req_size + 1);
252 _snwprintf(out,
253 (size_t)req_size + 1,
254 C_REGSETKEYVALUEW_TEMPLATE_SZ,
255 top_key_s,
256 escaped_key,
257 escaped_prop ? escaped_prop : L"",
258 reg_type,
259 escaped_d ? escaped_d : L"",
260 data_len);
261 } else if (type == REG_NONE) {
262 int req_size = _snwprintf(nullptr,
263 0,
264 C_REGSETKEYVALUEW_TEMPLATE_NONE,
265 top_key_s,
266 escaped_key,
267 escaped_prop ? escaped_prop : L"");
268 out = calloc((size_t)req_size + 1, WL);
269 if (!out) { // LCOV_EXCL_START
270 goto fail;
271 } // LCOV_EXCL_STOP
272 wmemset(out, L'\0', (size_t)req_size + 1);
273 _snwprintf(out,
274 (size_t)req_size + 1,
275 C_REGSETKEYVALUEW_TEMPLATE_NONE,
276 top_key_s,
277 escaped_key,
278 escaped_prop ? escaped_prop : L"");
279 } else if (type == REG_BINARY) {
280 int req_size = _snwprintf(nullptr,
281 0,
282 C_REGSETKEYVALUEW_TEMPLATE_BINARY,
283 escaped_d,
284 top_key_s,
285 escaped_key,
286 escaped_prop ? escaped_prop : L"",
287 data_len);
288 out = calloc((size_t)req_size + 1, WL);
289 if (!out) { // LCOV_EXCL_START
290 goto fail;
291 } // LCOV_EXCL_STOP
292 wmemset(out, L'\0', (size_t)req_size + 1);
293 _snwprintf(out,
294 (size_t)req_size + 1,
295 C_REGSETKEYVALUEW_TEMPLATE_BINARY,
296 escaped_d,
297 top_key_s,
298 escaped_key,
299 escaped_prop ? escaped_prop : L"",
300 data_len);
301 } else {
302 errno = EINVAL;
303 ret = false;
304 }
305 if (ret && out) {
306 ret = write_output(out, false, writer);
307 }
308 goto cleanup;
309fail:
310 ret = false;
311cleanup:
312 free(escaped_key);
313 free(escaped_d);
314 free(escaped_prop);
315 free(top_key_s);
316 free(out);
317 return ret;
318}
319
320static wchar_t *convert_data_for_c_sharp(DWORD reg_type, const char *data, size_t data_len) {
321 wchar_t *out, *escaped, *strings;
322 out = escaped = strings = nullptr;
323 if (reg_type == REG_BINARY || reg_type == REG_NONE || reg_type == REG_QWORD ||
324 reg_type == REG_DWORD) {
325 out = convert_data_for_c(reg_type, data, data_len);
326 if (!out) { // LCOV_EXCL_START
327 goto fail;
328 } // LCOV_EXCL_STOP
329 goto cleanup;
330 }
331 if (reg_type == REG_SZ || reg_type == REG_EXPAND_SZ) {
332 escaped = convert_data_for_c(reg_type, data, data_len);
333 if (!escaped) { // LCOV_EXCL_START
334 goto fail;
335 } // LCOV_EXCL_STOP
336 size_t escaped_len = wcslen(escaped);
337 out = calloc(escaped_len + 3, WL);
338 if (!out) { // LCOV_EXCL_START
339 goto fail;
340 } // LCOV_EXCL_STOP
341 _snwprintf(out, escaped_len + 3, L"\"%ls\"", escaped);
342 goto cleanup;
343 }
344 if (reg_type != REG_MULTI_SZ) {
345 errno = EINVAL;
346 goto fail;
347 }
348 wchar_t *w_data = (wchar_t *)data;
349 size_t w_data_len = (data_len % WL == 0) ? data_len / WL : (data_len / WL) + 1;
350 size_t real_len = determine_multi_sz_size(w_data, w_data_len);
351 if (real_len <= 2) {
352 debug_print(L"Skipping incorrectly stored REG_MULTI_SZ (length = %lu, w_data_len = %lu).\n",
353 data_len,
354 w_data_len);
355 goto cleanup;
356 }
357 unsigned i, j;
358 size_t strings_size = 0;
359 for (i = 0; i < w_data_len; i++) {
360 strings_size++;
361 if (w_data[i] == L'"' || w_data[i] == L'\\') {
362 strings_size++;
363 } else if (w_data[i] == L'\0') {
364 strings_size += 4;
365 }
366 }
367 size_t total_size = 5 + strings_size;
368 strings = calloc(strings_size + 1, WL);
369 if (!strings) { // LCOV_EXCL_START
370 goto fail;
371 } // LCOV_EXCL_STOP
372 wmemset(strings, L'\0', strings_size + 1);
373 strings[0] = L'"';
374 for (i = 0, j = 1; i < w_data_len - 2 && j < strings_size; i++, j++) {
375 if (w_data[i] == L'\0') {
376 strings[j++] = L'"';
377 if (j < (strings_size - 1)) {
378 strings[j++] = L',';
379 strings[j++] = L' ';
380 strings[j] = L'"';
381 }
382 continue;
383 }
384 if (w_data[i] == L'"' || w_data[i] == L'\\') {
385 strings[j++] = L'\\';
386 }
387 strings[j] = w_data[i];
388 }
389 out = calloc(total_size, WL);
390 if (!out) { // LCOV_EXCL_START
391 goto fail;
392 } // LCOV_EXCL_STOP
393 _snwprintf(out, total_size - 1, L"{ %ls\" }", strings);
394 goto cleanup;
395fail:
396 out = nullptr;
397cleanup:
398 free(escaped);
399 free(strings);
400 return out;
401}
402
403bool do_write_c_sharp_reg_code(writer_t *writer,
404 const wchar_t *full_path,
405 const wchar_t *prop,
406 const char *value,
407 size_t data_len,
408 unsigned long type) {
409 bool ret = true;
410 wchar_t *out, *escaped_key, *escaped_d, *escaped_prop, *top_key_s;
411 out = escaped_key = escaped_d = escaped_prop = top_key_s = nullptr;
412 wchar_t *first_backslash = wcschr(full_path, L'\\');
413 if (!first_backslash) {
414 goto fail;
415 }
416 wchar_t *subkey = first_backslash + 1;
417 escaped_key = escape_for_c(subkey, false, 0);
418 escaped_d = convert_data_for_c_sharp(type, value, data_len);
419 escaped_prop = escape_for_c(prop, false, 0);
420 top_key_s = get_top_key_string(full_path);
421 if (!escaped_key || !top_key_s) {
422 goto fail;
423 }
424 if (type == REG_MULTI_SZ && !escaped_d) {
425 goto cleanup;
426 }
427 wchar_t reg_type[33];
428 memset(reg_type, 0, sizeof(reg_type));
429 switch (type) {
430 case REG_NONE:
431 wcsncpy(reg_type, L", RegistryValueKind.None", 24);
432 break;
433 case REG_BINARY:
434 wcsncpy(reg_type, L", RegistryValueKind.Binary", 26);
435 break;
436 case REG_EXPAND_SZ:
437 wcsncpy(reg_type, L", RegistryValueKind.ExpandString", 32);
438 break;
439 case REG_SZ:
440 case REG_MULTI_SZ:
441 reg_type[0] = L'\0';
442 break;
443 case REG_DWORD:
444 wcsncpy(reg_type, L", RegistryValueKind.DWord", 25);
445 break;
446 case REG_QWORD:
447 wcsncpy(reg_type, L", RegistryValueKind.QWord", 25);
448 break;
449 default: // LCOV_EXCL_START
450 goto cleanup;
451 // LCOV_EXCL_STOP
452 }
453 int req_size = _snwprintf(nullptr,
454 0,
455 C_SHARP_REGISTRY_SET_VALUE_TEMPLATE,
456 top_key_s,
457 escaped_key,
458 escaped_prop ? escaped_prop : L"",
459 escaped_d ? escaped_d :
460 type == REG_NONE ? L"null" :
461 L"",
462 reg_type);
463 out = calloc((size_t)req_size + 1, WL);
464 if (!out) { // LCOV_EXCL_START
465 goto fail;
466 } // LCOV_EXCL_STOP
467 wmemset(out, L'\0', (size_t)req_size + 1);
468 _snwprintf(out,
469 (size_t)req_size + 1,
470 C_SHARP_REGISTRY_SET_VALUE_TEMPLATE,
471 top_key_s,
472 escaped_key,
473 escaped_prop ? escaped_prop : L"",
474 escaped_d ? escaped_d :
475 type == REG_NONE ? L"null" :
476 L"",
477 reg_type);
478 ret = write_output(out, false, writer);
479 goto cleanup;
480fail:
481 ret = false;
482cleanup:
483 free(escaped_d);
484 free(escaped_key);
485 free(escaped_prop);
486 free(out);
487 free(top_key_s);
488 return ret;
489}