20 #include <winpr/config.h>
21 #include <winpr/path.h>
28 #include <winpr/wtypes.h>
29 #include <winpr/string.h>
30 #include <winpr/assert.h>
31 #include <winpr/crt.h>
32 #include <winpr/file.h>
34 #include "registry_reg.h"
37 #define TAG WINPR_TAG("registry")
46 static struct reg_data_type REG_DATA_TYPE_TABLE[] = { {
"\"", 1, REG_SZ },
47 {
"dword:", 6, REG_DWORD },
48 {
"str:\"", 5, REG_SZ },
49 {
"str(2):\"", 8, REG_EXPAND_SZ },
50 {
"str(7):\"", 8, REG_MULTI_SZ },
51 {
"hex:", 4, REG_BINARY },
52 {
"hex(2):\"", 8, REG_EXPAND_SZ },
53 {
"hex(7):\"", 8, REG_MULTI_SZ },
54 {
"hex(b):\"", 8, REG_QWORD } };
56 static char* reg_data_type_string(DWORD type)
65 return "REG_EXPAND_SZ";
70 case REG_DWORD_BIG_ENDIAN:
71 return "REG_DWORD_BIG_ENDIAN";
75 return "REG_MULTI_SZ";
76 case REG_RESOURCE_LIST:
77 return "REG_RESOURCE_LIST";
78 case REG_FULL_RESOURCE_DESCRIPTOR:
79 return "REG_FULL_RESOURCE_DESCRIPTOR";
80 case REG_RESOURCE_REQUIREMENTS_LIST:
81 return "REG_RESOURCE_REQUIREMENTS_LIST";
89 static BOOL reg_load_start(Reg* reg)
95 WINPR_ASSERT(reg->fp);
97 if (_fseeki64(reg->fp, 0, SEEK_END) != 0)
99 file_size = _ftelli64(reg->fp);
100 if (_fseeki64(reg->fp, 0, SEEK_SET) != 0)
103 reg->next_line = NULL;
108 buffer = (
char*)realloc(reg->buffer, (
size_t)file_size + 2);
112 reg->buffer = buffer;
114 if (fread(reg->buffer, (
size_t)file_size, 1, reg->fp) != 1)
117 reg->buffer[file_size] =
'\n';
118 reg->buffer[file_size + 1] =
'\0';
119 reg->next_line = strtok_s(reg->buffer,
"\n", ®->saveptr);
123 static void reg_load_finish(Reg* reg)
135 static RegVal* reg_load_value(
const Reg* reg, RegKey* key)
137 const char* p[5] = { 0 };
140 const char* type = NULL;
141 const char* data = NULL;
142 RegVal* value = NULL;
146 WINPR_ASSERT(reg->line);
148 p[0] = reg->line + 1;
149 p[1] = strstr(p[0],
"\"=");
159 p[3] = strchr(p[2],
':');
165 length = (size_t)(p[1] - p[0]);
169 name = (
char*)calloc(length + 1,
sizeof(
char));
174 memcpy(name, p[0], length);
175 value = (RegVal*)calloc(1,
sizeof(RegVal));
181 value->type = REG_NONE;
183 for (
size_t index = 0; index < ARRAYSIZE(REG_DATA_TYPE_TABLE); index++)
185 const struct reg_data_type* current = ®_DATA_TYPE_TABLE[index];
186 WINPR_ASSERT(current->tag);
187 WINPR_ASSERT(current->length > 0);
188 WINPR_ASSERT(current->type != REG_NONE);
190 if (strncmp(type, current->tag, current->length) == 0)
192 value->type = current->type;
201 unsigned long val = 0;
203 val = strtoul(data, NULL, 0);
205 if ((errno != 0) || (val > UINT32_MAX))
207 WLog_WARN(TAG,
"%s::%s value %s invalid", key->name, value->name, data);
210 value->data.dword = (DWORD)val;
215 unsigned long long val = 0;
217 val = strtoull(data, NULL, 0);
219 if ((errno != 0) || (val > UINT64_MAX))
221 WLog_WARN(TAG,
"%s::%s value %s invalid", key->name, value->name, data);
225 value->data.qword = (UINT64)val;
233 char* start = strchr(data,
'"');
239 end = strchr(start + 1,
'"');
242 cmp = end - start + 1;
249 value->data.string = _strdup(start);
251 if (!value->data.string)
256 WLog_ERR(TAG,
"[%s] %s unimplemented format: %s", key->name, value->name,
257 reg_data_type_string(value->type));
267 RegVal* pValue = key->values;
269 while (pValue->next != NULL)
271 pValue = pValue->next;
274 pValue->next = value;
275 value->prev = pValue;
286 static BOOL reg_load_has_next_line(Reg* reg)
291 return (reg->next_line != NULL) ? 1 : 0;
294 static char* reg_load_get_next_line(Reg* reg)
299 reg->line = reg->next_line;
300 reg->next_line = strtok_s(NULL,
"\n", ®->saveptr);
301 reg->line_length = strlen(reg->line);
305 static char* reg_load_peek_next_line(Reg* reg)
308 return reg->next_line;
311 static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey)
319 WINPR_ASSERT(subkey);
320 WINPR_ASSERT(subkey->name);
322 path = _strdup(subkey->name);
327 name = strtok_s(path,
"\\", &save);
331 if (strcmp(key->name, name) == 0)
334 subkey->subname = _strdup(save);
337 if (!subkey->subname)
344 name = strtok_s(NULL,
"\\", &save);
350 static RegKey* reg_load_key(Reg* reg, RegKey* key)
354 RegKey* subkey = NULL;
359 WINPR_ASSERT(reg->line);
360 p[0] = reg->line + 1;
361 p[1] = strrchr(p[0],
']');
365 subkey = (RegKey*)calloc(1,
sizeof(RegKey));
370 length = (size_t)(p[1] - p[0]);
371 subkey->name = (
char*)malloc(length + 1);
379 memcpy(subkey->name, p[0], length);
380 subkey->name[length] =
'\0';
382 while (reg_load_has_next_line(reg))
384 char* line = reg_load_peek_next_line(reg);
389 reg_load_get_next_line(reg);
391 if (reg->line[0] ==
'"')
393 reg_load_value(reg, subkey);
397 reg_insert_key(reg, key, subkey);
401 key->subkeys = subkey;
405 RegKey* pKey = key->subkeys;
407 while (pKey->next != NULL)
419 static void reg_load(Reg* reg)
423 while (reg_load_has_next_line(reg))
425 reg_load_get_next_line(reg);
427 if (reg->line[0] ==
'[')
429 reg_load_key(reg, reg->root_key);
433 reg_load_finish(reg);
436 static void reg_unload_value(Reg* reg, RegVal* value)
444 free(value->data.string);
453 static void reg_unload_key(Reg* reg, RegKey* key)
455 RegVal* pValue = NULL;
460 pValue = key->values;
462 while (pValue != NULL)
464 RegVal* pValueNext = pValue->next;
465 reg_unload_value(reg, pValue);
473 static void reg_unload(Reg* reg)
478 RegKey* pKey = reg->root_key->subkeys;
482 RegKey* pKeyNext = pKey->next;
483 reg_unload_key(reg, pKey);
491 Reg* reg_open(BOOL read_only)
493 Reg* reg = (Reg*)calloc(1,
sizeof(Reg));
498 reg->read_only = read_only;
499 reg->filename = winpr_GetConfigFilePath(TRUE,
"HKLM.reg");
504 reg->fp = winpr_fopen(reg->filename,
"r");
507 reg->fp = winpr_fopen(reg->filename,
"r+");
510 reg->fp = winpr_fopen(reg->filename,
"w+");
516 reg->root_key = (RegKey*)calloc(1,
sizeof(RegKey));
521 reg->root_key->values = NULL;
522 reg->root_key->subkeys = NULL;
523 reg->root_key->name =
"HKEY_LOCAL_MACHINE";
532 void reg_close(Reg* reg)
538 (void)fclose(reg->fp);
544 const char* reg_type_string(DWORD type)
553 return "REG_EXPAND_SZ";
558 case REG_DWORD_BIG_ENDIAN:
559 return "REG_DWORD_BIG_ENDIAN";
563 return "REG_MULTI_SZ";
564 case REG_RESOURCE_LIST:
565 return "REG_RESOURCE_LIST";
566 case REG_FULL_RESOURCE_DESCRIPTOR:
567 return "REG_FULL_RESOURCE_DESCRIPTOR";
568 case REG_RESOURCE_REQUIREMENTS_LIST:
569 return "REG_RESOURCE_REQUIREMENTS_LIST";
573 return "REG_UNKNOWN";