gdiplus: In GdipImageSelectActiveFrame rely on codec->select_func() to fail.
[wine.git] / tools / winedump / reg.c
blobf100eb4717140bb3c775556f71e26267983dea03
1 /*
2 * Dump Windows NT Registry File (REGF)
4 * Copyright 2023 Piotr Caban for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "winedump.h"
24 #define BLOCK_SIZE 4096
26 #define SECSPERDAY 86400
27 /* 1601 to 1970 is 369 years plus 89 leap days */
28 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
29 #define TICKSPERSEC 10000000
31 enum file_type
33 REG_HIVE
36 typedef struct
38 unsigned int signature;
39 unsigned int seq_prim;
40 unsigned int seq_sec;
41 FILETIME modif_time;
42 unsigned int ver_major;
43 unsigned int ver_minor;
44 enum file_type file_type;
45 unsigned int unk1;
46 unsigned int root_key_off;
47 unsigned int hive_bins_size;
48 unsigned int unk2[116];
49 unsigned int checksum;
50 } header;
52 enum key_flags
54 KEY_IS_VOLATILE = 0x01,
55 KEY_HIVE_EXIT = 0x02,
56 KEY_HIVE_ENTRY = 0x04,
57 KEY_NO_DELETE = 0x08,
58 KEY_SYM_LINK = 0x10,
59 KEY_COMP_NAME = 0x20
62 typedef struct
64 unsigned int size;
65 short signature;
66 short flags;
67 FILETIME timestamp;
68 int unk1;
69 unsigned int parent_off;
70 unsigned int sub_keys;
71 unsigned int volatile_sub_keys;
72 unsigned int sub_keys_list_off;
73 unsigned int volatile_sub_keys_list_off;
74 unsigned int values;
75 unsigned int values_list_off;
76 unsigned int sec_key_off;
77 unsigned int class_off;
78 unsigned int max_name_size;
79 unsigned int max_class_size;
80 unsigned int max_val_name_size;
81 unsigned int max_val_size;
82 int unk2;
83 unsigned short name_size;
84 unsigned short class_size;
85 } named_key;
87 enum val_flags
89 VAL_COMP_NAME = 0x1
92 typedef struct
94 unsigned int size;
95 unsigned short signature;
96 unsigned short name_size;
97 unsigned int data_size;
98 unsigned int data_off;
99 unsigned int data_type;
100 unsigned short flags;
101 unsigned short padding;
102 } value_key;
104 typedef struct
106 unsigned int size;
107 unsigned short signature;
108 unsigned short count;
109 } key_list;
111 static unsigned int path_len;
112 static char path[512*256];
114 static BOOL dump_key(unsigned int hive_off, unsigned int off);
116 static time_t filetime_to_time_t(FILETIME ft)
118 ULONGLONG *ull = (ULONGLONG *)&ft;
119 time_t t = *ull / TICKSPERSEC - SECS_1601_TO_1970;
120 return *ull ? t : 0;
123 static const char *filetime_str(FILETIME ft)
125 return get_time_str(filetime_to_time_t(ft));
128 static unsigned int header_checksum(const header *h)
130 unsigned int i, checksum = 0;
132 for (i = 0; i < FIELD_OFFSET(header, checksum) / sizeof(int); i++)
133 checksum ^= ((unsigned int*)h)[i];
134 return checksum;
137 enum FileSig get_kind_reg(void)
139 const header *hdr;
141 hdr = PRD(0, BLOCK_SIZE);
142 if (hdr && !memcmp(&hdr->signature, "regf", sizeof(hdr->signature)))
143 return SIG_REG;
144 return SIG_UNKNOWN;
147 static BOOL dump_subkeys(unsigned int hive_off, unsigned int off)
149 const key_list *key_list = PRD(hive_off + off, sizeof(*key_list));
150 const unsigned int *offs;
151 unsigned int i;
153 if (!key_list)
154 return FALSE;
156 if (!memcmp(&key_list->signature, "lf", 2) ||
157 !memcmp(&key_list->signature, "lh", 2) ||
158 !memcmp(&key_list->signature, "li", 2))
160 unsigned int elem_size = memcmp(&key_list->signature, "li", 2) ? 2 : 1;
162 offs = PRD(hive_off + off + sizeof(*key_list),
163 key_list->count * elem_size * sizeof(*offs));
164 if (!offs)
165 return FALSE;
167 for (i = 0; i < key_list->count; i++)
169 if (!dump_key(hive_off, offs[elem_size * i]))
170 return FALSE;
173 else if (!memcmp(&key_list->signature, "ri", 2))
175 offs = PRD(hive_off + off + sizeof(*key_list), key_list->count * sizeof(*offs));
176 if (!offs)
177 return FALSE;
179 for (i = 0; i < key_list->count; i++)
181 if (!dump_subkeys(hive_off, offs[i]))
182 return FALSE;
185 else
187 return FALSE;
190 return TRUE;
193 static BOOL dump_value(unsigned int hive_off, unsigned int off)
195 unsigned int i, len, data_size;
196 const void *data = NULL;
197 const char *name, *str;
198 const value_key *val;
200 val = PRD(hive_off + off, sizeof(*val));
201 if (!val || memcmp(&val->signature, "vk", 2))
202 return FALSE;
204 if (!(val->data_size & 0x80000000) && val->data_size > 4 * BLOCK_SIZE)
206 printf("Warning: data blocks not supported\n");
207 return TRUE;
210 if (val->name_size && !(val->flags & VAL_COMP_NAME))
212 name = PRD(hive_off + off + sizeof(*val), val->name_size);
213 if (!name)
214 return FALSE;
215 name = get_unicode_str((WCHAR *)name, val->name_size / sizeof(WCHAR));
216 len = strlen(name) + 1;
218 printf("%s=", name);
220 else if (val->name_size)
222 name = PRD(hive_off + off + sizeof(*val), val->name_size);
223 if (!name)
224 return FALSE;
225 len = val->name_size + 3;
227 printf("\"%.*s\"=", val->name_size, name);
229 else
231 len = 2;
232 printf("@=");
235 data_size = val->data_size;
236 if (data_size & 0x80000000)
238 data = &val->data_off;
239 data_size &= ~0x80000000;
241 else if (data_size)
243 data = PRD(hive_off + val->data_off + sizeof(unsigned int), data_size);
244 if (!data)
245 return FALSE;
248 switch (val->data_type)
250 case REG_NONE:
251 /* TODO: dump as REG_NONE value. */
252 printf("hex:");
253 break;
254 case REG_EXPAND_SZ:
255 printf("str(2):");
256 /* fall through */
257 case REG_SZ:
258 printf("%s", !data ? "\"\"" :
259 get_unicode_str((const WCHAR *)data, data_size / sizeof(WCHAR)));
260 break;
261 case REG_QWORD:
262 case REG_BINARY:
263 printf("hex%s:", val->data_type == REG_QWORD ? "(b)" : "");
264 len += 4 + (val->data_type == REG_QWORD ? 3 : 0);
265 for (i = 0; i < data_size; i++)
267 if (i)
269 printf(",");
270 len += 1;
272 if (len > 76)
274 printf("\\\n ");
275 len = 2;
277 printf("%02x", ((BYTE *)data)[i]);
278 len += 2;
280 break;
281 case REG_DWORD:
282 assert(data_size == sizeof(DWORD));
283 printf("dword:%08x", *(unsigned int *)data);
284 break;
285 case REG_MULTI_SZ:
286 printf("str(7):\"");
288 while(data_size > sizeof(WCHAR))
290 for (len = 0; len < data_size / sizeof(WCHAR); len++)
291 if (!((WCHAR *)data)[len])
292 break;
293 str = get_unicode_str(data, len);
295 printf("%.*s\\0", (unsigned int)strlen(str + 1) - 1, str + 1);
296 data = ((WCHAR *)data) + len + 1;
297 data_size -= (len + 1) * sizeof(WCHAR);
299 printf("\"");
300 break;
301 default:
302 printf("unhandled data type %d", val->data_type);
305 printf("\n");
306 return TRUE;
309 static BOOL dump_key(unsigned int hive_off, unsigned int off)
311 const named_key *key;
312 const char *name;
313 BOOL ret = TRUE;
315 key = PRD(hive_off + off, sizeof(*key));
316 if (!key || memcmp(&key->signature, "nk", 2))
317 return FALSE;
319 if (!(key->flags & KEY_COMP_NAME))
321 printf("unsupported key flags: %x\n", key->flags);
322 return FALSE;
325 name = PRD(hive_off + off + sizeof(*key), key->name_size);
326 if (!name)
327 return FALSE;
328 if (path_len)
329 path[path_len++] = '\\';
330 memcpy(path + path_len, name, key->name_size);
331 path_len += key->name_size;
332 path[path_len] = 0;
334 if ((!key->sub_keys && !key->volatile_sub_keys) || key->values)
336 printf("[%s] %u\n", path, (int)filetime_to_time_t(key->timestamp));
337 printf("#time=%x%08x\n", (int)key->timestamp.dwHighDateTime, (int)key->timestamp.dwLowDateTime);
339 if (key->values)
341 const unsigned int *offs = PRD(hive_off + key->values_list_off + sizeof(unsigned int),
342 key->values * sizeof(unsigned int));
343 unsigned int i;
345 if (!offs)
346 return FALSE;
348 for (i = 0; i < key->values; i++)
350 ret = dump_value(hive_off, offs[i]);
351 if (!ret)
352 return ret;
355 else
357 printf("@=\"\"\n");
359 if (!ret)
360 return FALSE;
362 printf("\n");
365 if (key->sub_keys)
366 ret = dump_subkeys(hive_off, key->sub_keys_list_off);
368 path_len -= key->name_size + 1;
369 path[path_len] = 0;
370 return ret;
373 void reg_dump(void)
375 const header *hdr;
377 hdr = PRD(0, sizeof(BLOCK_SIZE));
378 if (!hdr)
379 return;
381 printf("File Header\n");
382 printf(" %-20s %.4s\n", "signature:", (char*)&hdr->signature);
383 printf(" %-20s %u\n", "primary sequence:", hdr->seq_prim);
384 printf(" %-20s %u\n", "secondary sequence:", hdr->seq_sec);
385 printf(" %-20s %s\n", "modification time:", filetime_str(hdr->modif_time));
386 printf(" %-20s %u.%d\n", "version:", hdr->ver_major, hdr->ver_minor);
387 printf(" %-20s %u\n", "file type:", hdr->file_type);
388 printf(" %-20s %u\n", "root key offset:", hdr->root_key_off);
389 printf(" %-20s %u\n", "hive bins size:", hdr->hive_bins_size);
390 printf(" %-20s %x (%svalid)\n", "checksum:", hdr->checksum,
391 header_checksum(hdr) == hdr->checksum ? "" : "in");
392 printf("\n");
394 if (hdr->ver_major != 1 || hdr->ver_minor < 2 || hdr->ver_minor > 5 ||
395 hdr->file_type != REG_HIVE)
397 printf("unsupported format, exiting\n");
398 return;
401 path_len = 0;
402 path[0] = 0;
403 if (!dump_key(BLOCK_SIZE, hdr->root_key_off))
404 printf("error dumping file\n");