1 /* 2 * Registry processing routines. Routines, common for registry 3 * processing frontends. 4 * 5 * Copyright 1999 Sylvain St-Germain 6 * Copyright 2002 Andriy Palamarchuk 7 * Copyright 2008 Alexander N. Sørnes <alex@thehandofagony.com> 8 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 9 */ 10 11 #ifdef __REACTOS__ 12 #include <fcntl.h> 13 #include <io.h> 14 #include "regedit.h" 15 #else 16 #include <errno.h> 17 #include <fcntl.h> 18 #include <io.h> 19 #include <windows.h> 20 #include <commctrl.h> 21 22 #include "main.h" 23 #endif 24 25 #define REG_VAL_BUF_SIZE 4096 26 27 static HKEY reg_class_keys[] = { 28 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, 29 HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA 30 }; 31 32 /****************************************************************************** 33 * Allocates memory and converts input from multibyte to wide chars 34 * Returned string must be freed by the caller 35 */ 36 static WCHAR* GetWideString(const char* strA) 37 { 38 if(strA) 39 { 40 WCHAR* strW; 41 int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0); 42 43 strW = malloc(len * sizeof(WCHAR)); 44 MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len); 45 return strW; 46 } 47 return NULL; 48 } 49 50 /****************************************************************************** 51 * Allocates memory and converts input from multibyte to wide chars 52 * Returned string must be freed by the caller 53 */ 54 static WCHAR* GetWideStringN(const char* strA, int chars, DWORD *len) 55 { 56 if(strA) 57 { 58 WCHAR* strW; 59 *len = MultiByteToWideChar(CP_ACP, 0, strA, chars, NULL, 0); 60 61 strW = malloc(*len * sizeof(WCHAR)); 62 MultiByteToWideChar(CP_ACP, 0, strA, chars, strW, *len); 63 return strW; 64 } 65 *len = 0; 66 return NULL; 67 } 68 69 /****************************************************************************** 70 * Allocates memory and converts input from wide chars to multibyte 71 * Returned string must be freed by the caller 72 */ 73 char* GetMultiByteString(const WCHAR* strW) 74 { 75 if(strW) 76 { 77 char* strA; 78 int len = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL); 79 80 strA = malloc(len); 81 WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, len, NULL, NULL); 82 return strA; 83 } 84 return NULL; 85 } 86 87 /****************************************************************************** 88 * Allocates memory and converts input from wide chars to multibyte 89 * Returned string must be freed by the caller 90 */ 91 static char* GetMultiByteStringN(const WCHAR* strW, int chars, DWORD* len) 92 { 93 if(strW) 94 { 95 char* strA; 96 *len = WideCharToMultiByte(CP_ACP, 0, strW, chars, NULL, 0, NULL, NULL); 97 98 strA = malloc(*len); 99 WideCharToMultiByte(CP_ACP, 0, strW, chars, strA, *len, NULL, NULL); 100 return strA; 101 } 102 *len = 0; 103 return NULL; 104 } 105 106 static WCHAR *(*get_line)(FILE *); 107 108 /* parser definitions */ 109 enum parser_state 110 { 111 HEADER, /* parsing the registry file version header */ 112 PARSE_WIN31_LINE, /* parsing a Windows 3.1 registry line */ 113 LINE_START, /* at the beginning of a registry line */ 114 KEY_NAME, /* parsing a key name */ 115 DELETE_KEY, /* deleting a registry key */ 116 DEFAULT_VALUE_NAME, /* parsing a default value name */ 117 QUOTED_VALUE_NAME, /* parsing a double-quoted value name */ 118 DATA_START, /* preparing for data parsing operations */ 119 DELETE_VALUE, /* deleting a registry value */ 120 DATA_TYPE, /* parsing the registry data type */ 121 STRING_DATA, /* parsing REG_SZ data */ 122 DWORD_DATA, /* parsing DWORD data */ 123 HEX_DATA, /* parsing REG_BINARY, REG_NONE, REG_EXPAND_SZ or REG_MULTI_SZ data */ 124 EOL_BACKSLASH, /* preparing to parse multiple lines of hex data */ 125 HEX_MULTILINE, /* parsing multiple lines of hex data */ 126 UNKNOWN_DATA, /* parsing an unhandled or invalid data type */ 127 SET_VALUE, /* adding a value to the registry */ 128 NB_PARSER_STATES 129 }; 130 131 struct parser 132 { 133 FILE *file; /* pointer to a registry file */ 134 WCHAR two_wchars[2]; /* first two characters from the encoding check */ 135 BOOL is_unicode; /* parsing Unicode or ASCII data */ 136 short int reg_version; /* registry file version */ 137 HKEY hkey; /* current registry key */ 138 WCHAR *key_name; /* current key name */ 139 WCHAR *value_name; /* value name */ 140 DWORD parse_type; /* generic data type for parsing */ 141 DWORD data_type; /* data type */ 142 void *data; /* value data */ 143 DWORD data_size; /* size of the data (in bytes) */ 144 BOOL backslash; /* TRUE if the current line contains a backslash */ 145 enum parser_state state; /* current parser state */ 146 }; 147 148 typedef WCHAR *(*parser_state_func)(struct parser *parser, WCHAR *pos); 149 150 /* parser state machine functions */ 151 static WCHAR *header_state(struct parser *parser, WCHAR *pos); 152 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos); 153 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos); 154 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos); 155 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos); 156 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos); 157 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos); 158 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos); 159 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos); 160 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos); 161 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos); 162 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos); 163 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos); 164 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos); 165 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos); 166 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos); 167 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos); 168 169 static const parser_state_func parser_funcs[NB_PARSER_STATES] = 170 { 171 header_state, /* HEADER */ 172 parse_win31_line_state, /* PARSE_WIN31_LINE */ 173 line_start_state, /* LINE_START */ 174 key_name_state, /* KEY_NAME */ 175 delete_key_state, /* DELETE_KEY */ 176 default_value_name_state, /* DEFAULT_VALUE_NAME */ 177 quoted_value_name_state, /* QUOTED_VALUE_NAME */ 178 data_start_state, /* DATA_START */ 179 delete_value_state, /* DELETE_VALUE */ 180 data_type_state, /* DATA_TYPE */ 181 string_data_state, /* STRING_DATA */ 182 dword_data_state, /* DWORD_DATA */ 183 hex_data_state, /* HEX_DATA */ 184 eol_backslash_state, /* EOL_BACKSLASH */ 185 hex_multiline_state, /* HEX_MULTILINE */ 186 unknown_data_state, /* UNKNOWN_DATA */ 187 set_value_state, /* SET_VALUE */ 188 }; 189 190 /* set the new parser state and return the previous one */ 191 static inline enum parser_state set_state(struct parser *parser, enum parser_state state) 192 { 193 enum parser_state ret = parser->state; 194 parser->state = state; 195 return ret; 196 } 197 198 /****************************************************************************** 199 * Converts a hex representation of a DWORD into a DWORD. 200 */ 201 static BOOL convert_hex_to_dword(WCHAR *str, DWORD *dw) 202 { 203 WCHAR *p, *end; 204 int count = 0; 205 206 while (*str == ' ' || *str == '\t') str++; 207 if (!*str) goto error; 208 209 p = str; 210 while (iswxdigit(*p)) 211 { 212 count++; 213 p++; 214 } 215 if (count > 8) goto error; 216 217 end = p; 218 while (*p == ' ' || *p == '\t') p++; 219 if (*p && *p != ';') goto error; 220 221 *end = 0; 222 *dw = wcstoul(str, &end, 16); 223 return TRUE; 224 225 error: 226 return FALSE; 227 } 228 229 /****************************************************************************** 230 * Converts comma-separated hex data into a binary string and modifies 231 * the input parameter to skip the concatenating backslash, if found. 232 * 233 * Returns TRUE or FALSE to indicate whether parsing was successful. 234 */ 235 static BOOL convert_hex_csv_to_hex(struct parser *parser, WCHAR **str) 236 { 237 size_t size; 238 BYTE *d; 239 WCHAR *s; 240 241 parser->backslash = FALSE; 242 243 /* The worst case is 1 digit + 1 comma per byte */ 244 size = ((lstrlenW(*str) + 1) / 2) + parser->data_size; 245 parser->data = realloc(parser->data, size); 246 247 s = *str; 248 d = (BYTE *)parser->data + parser->data_size; 249 250 while (*s) 251 { 252 WCHAR *end; 253 unsigned long wc; 254 255 wc = wcstoul(s, &end, 16); 256 if (wc > 0xff) return FALSE; 257 258 if (s == end && wc == 0) 259 { 260 while (*end == ' ' || *end == '\t') end++; 261 if (*end == '\\') 262 { 263 parser->backslash = TRUE; 264 *str = end + 1; 265 return TRUE; 266 } 267 else if (*end == ';') 268 return TRUE; 269 return FALSE; 270 } 271 272 *d++ = wc; 273 parser->data_size++; 274 275 if (*end && *end != ',') 276 { 277 while (*end == ' ' || *end == '\t') end++; 278 if (*end && *end != ';') return FALSE; 279 return TRUE; 280 } 281 282 if (*end) end++; 283 s = end; 284 } 285 286 return TRUE; 287 } 288 289 /****************************************************************************** 290 * Parses the data type of the registry value being imported and modifies 291 * the input parameter to skip the string representation of the data type. 292 * 293 * Returns TRUE or FALSE to indicate whether a data type was found. 294 */ 295 static BOOL parse_data_type(struct parser *parser, WCHAR **line) 296 { 297 struct data_type { const WCHAR *tag; int len; int type; int parse_type; }; 298 299 static const struct data_type data_types[] = { 300 /* tag len type parse type */ 301 { L"\"", 1, REG_SZ, REG_SZ }, 302 { L"hex:", 4, REG_BINARY, REG_BINARY }, 303 { L"dword:", 6, REG_DWORD, REG_DWORD }, 304 { L"hex(", 4, -1, REG_BINARY }, /* REG_NONE, REG_EXPAND_SZ, REG_MULTI_SZ */ 305 { NULL, 0, 0, 0 } 306 }; 307 308 const struct data_type *ptr; 309 310 for (ptr = data_types; ptr->tag; ptr++) 311 { 312 if (wcsncmp(ptr->tag, *line, ptr->len)) 313 continue; 314 315 parser->parse_type = ptr->parse_type; 316 parser->data_type = ptr->parse_type; 317 *line += ptr->len; 318 319 if (ptr->type == -1) 320 { 321 WCHAR *end; 322 DWORD val; 323 324 if (!**line || towlower((*line)[1]) == 'x') 325 return FALSE; 326 327 /* "hex(xx):" is special */ 328 val = wcstoul(*line, &end, 16); 329 #ifdef __REACTOS__ 330 /* Up to 8 hex digits, "hex(000000002)" is invalid */ 331 if (*end != ')' || *(end + 1) != ':' || (val == ~0u && errno == ERANGE) || end - *line > 8) 332 #else 333 if (*end != ')' || *(end + 1) != ':' || (val == ~0u && errno == ERANGE)) 334 #endif 335 return FALSE; 336 337 parser->data_type = val; 338 *line = end + 2; 339 } 340 return TRUE; 341 } 342 return FALSE; 343 } 344 345 /****************************************************************************** 346 * Replaces escape sequences with their character equivalents and 347 * null-terminates the string on the first non-escaped double quote. 348 * 349 * Assigns a pointer to the remaining unparsed data in the line. 350 * Returns TRUE or FALSE to indicate whether a closing double quote was found. 351 */ 352 static BOOL REGPROC_unescape_string(WCHAR *str, WCHAR **unparsed) 353 { 354 int str_idx = 0; /* current character under analysis */ 355 int val_idx = 0; /* the last character of the unescaped string */ 356 int len = lstrlenW(str); 357 BOOL ret; 358 359 for (str_idx = 0; str_idx < len; str_idx++, val_idx++) { 360 if (str[str_idx] == '\\') { 361 str_idx++; 362 switch (str[str_idx]) { 363 case 'n': 364 str[val_idx] = '\n'; 365 break; 366 case 'r': 367 str[val_idx] = '\r'; 368 break; 369 case '0': 370 return FALSE; 371 case '\\': 372 case '"': 373 str[val_idx] = str[str_idx]; 374 break; 375 default: 376 if (!str[str_idx]) return FALSE; 377 output_message(STRING_ESCAPE_SEQUENCE, str[str_idx]); 378 str[val_idx] = str[str_idx]; 379 break; 380 } 381 } else if (str[str_idx] == '"') { 382 break; 383 } else { 384 str[val_idx] = str[str_idx]; 385 } 386 } 387 388 ret = (str[str_idx] == '"'); 389 *unparsed = str + str_idx + 1; 390 str[val_idx] = '\0'; 391 return ret; 392 } 393 394 static HKEY parse_key_name(WCHAR *key_name, WCHAR **key_path) 395 { 396 unsigned int i; 397 398 if (!key_name) return 0; 399 400 *key_path = wcschr(key_name, '\\'); 401 if (*key_path) (*key_path)++; 402 403 for (i = 0; i < ARRAY_SIZE(reg_class_keys); i++) 404 { 405 int len = lstrlenW(reg_class_namesW[i]); 406 #ifdef __REACTOS__ 407 if (!_wcsnicmp(key_name, reg_class_namesW[i], len) && 408 #else 409 if (!wcsnicmp(key_name, reg_class_namesW[i], len) && 410 #endif 411 (key_name[len] == 0 || key_name[len] == '\\')) 412 { 413 return reg_class_keys[i]; 414 } 415 } 416 417 return 0; 418 } 419 420 static void close_key(struct parser *parser) 421 { 422 if (parser->hkey) 423 { 424 free(parser->key_name); 425 parser->key_name = NULL; 426 427 RegCloseKey(parser->hkey); 428 parser->hkey = NULL; 429 } 430 } 431 432 /****************************************************************************** 433 * Opens the registry key given by the input path. 434 * This key must be closed by calling close_key(). 435 */ 436 static LONG open_key(struct parser *parser, WCHAR *path) 437 { 438 HKEY key_class; 439 WCHAR *key_path; 440 LONG res; 441 442 close_key(parser); 443 444 /* Get the registry class */ 445 if (!path || !(key_class = parse_key_name(path, &key_path))) 446 return ERROR_INVALID_PARAMETER; 447 448 res = RegCreateKeyExW(key_class, key_path, 0, NULL, REG_OPTION_NON_VOLATILE, 449 KEY_ALL_ACCESS, NULL, &parser->hkey, NULL); 450 451 if (res == ERROR_SUCCESS) 452 { 453 parser->key_name = malloc((lstrlenW(path) + 1) * sizeof(WCHAR)); 454 lstrcpyW(parser->key_name, path); 455 } 456 else 457 parser->hkey = NULL; 458 459 return res; 460 } 461 462 static void free_parser_data(struct parser *parser) 463 { 464 if (parser->parse_type == REG_DWORD || parser->parse_type == REG_BINARY) 465 free(parser->data); 466 467 parser->data = NULL; 468 parser->data_size = 0; 469 } 470 471 static void prepare_hex_string_data(struct parser *parser) 472 { 473 if (parser->data_type == REG_EXPAND_SZ || parser->data_type == REG_MULTI_SZ || 474 parser->data_type == REG_SZ) 475 { 476 if (parser->is_unicode) 477 { 478 WCHAR *data = parser->data; 479 DWORD len = parser->data_size / sizeof(WCHAR); 480 481 if (data[len - 1] != 0) 482 { 483 data[len] = 0; 484 parser->data_size += sizeof(WCHAR); 485 } 486 } 487 else 488 { 489 BYTE *data = parser->data; 490 491 if (data[parser->data_size - 1] != 0) 492 { 493 data[parser->data_size] = 0; 494 parser->data_size++; 495 } 496 497 parser->data = GetWideStringN(parser->data, parser->data_size, &parser->data_size); 498 parser->data_size *= sizeof(WCHAR); 499 free(data); 500 } 501 } 502 } 503 504 enum reg_versions { 505 REG_VERSION_31, 506 REG_VERSION_40, 507 REG_VERSION_50, 508 REG_VERSION_FUZZY, 509 REG_VERSION_INVALID 510 }; 511 512 static enum reg_versions parse_file_header(const WCHAR *s) 513 { 514 static const WCHAR header_31[] = L"REGEDIT"; 515 516 while (*s == ' ' || *s == '\t') s++; 517 518 if (!lstrcmpW(s, header_31)) 519 return REG_VERSION_31; 520 521 if (!lstrcmpW(s, L"REGEDIT4")) 522 return REG_VERSION_40; 523 524 if (!lstrcmpW(s, L"Windows Registry Editor Version 5.00")) 525 return REG_VERSION_50; 526 527 /* The Windows version accepts registry file headers beginning with "REGEDIT" and ending 528 * with other characters, as long as "REGEDIT" appears at the start of the line. For example, 529 * "REGEDIT 4", "REGEDIT9" and "REGEDIT4FOO" are all treated as valid file headers. 530 * In all such cases, however, the contents of the registry file are not imported. 531 */ 532 if (!wcsncmp(s, header_31, 7)) /* "REGEDIT" without NUL */ 533 return REG_VERSION_FUZZY; 534 535 return REG_VERSION_INVALID; 536 } 537 538 /* handler for parser HEADER state */ 539 static WCHAR *header_state(struct parser *parser, WCHAR *pos) 540 { 541 WCHAR *line, *header; 542 543 if (!(line = get_line(parser->file))) 544 return NULL; 545 546 if (!parser->is_unicode) 547 { 548 header = malloc((lstrlenW(line) + 3) * sizeof(WCHAR)); 549 header[0] = parser->two_wchars[0]; 550 header[1] = parser->two_wchars[1]; 551 lstrcpyW(header + 2, line); 552 parser->reg_version = parse_file_header(header); 553 free(header); 554 } 555 else parser->reg_version = parse_file_header(line); 556 557 switch (parser->reg_version) 558 { 559 case REG_VERSION_31: 560 set_state(parser, PARSE_WIN31_LINE); 561 break; 562 case REG_VERSION_40: 563 case REG_VERSION_50: 564 set_state(parser, LINE_START); 565 break; 566 default: 567 get_line(NULL); /* Reset static variables */ 568 return NULL; 569 } 570 571 return line; 572 } 573 574 /* handler for parser PARSE_WIN31_LINE state */ 575 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos) 576 { 577 WCHAR *line, *value; 578 static WCHAR hkcr[] = L"HKEY_CLASSES_ROOT"; 579 unsigned int key_end = 0; 580 581 if (!(line = get_line(parser->file))) 582 return NULL; 583 584 if (wcsncmp(line, hkcr, lstrlenW(hkcr))) 585 return line; 586 587 /* get key name */ 588 while (line[key_end] && !iswspace(line[key_end])) key_end++; 589 590 value = line + key_end; 591 while (*value == ' ' || *value == '\t') value++; 592 593 if (*value == '=') value++; 594 if (*value == ' ') value++; /* at most one space is skipped */ 595 596 line[key_end] = 0; 597 598 if (open_key(parser, line) != ERROR_SUCCESS) 599 { 600 output_message(STRING_OPEN_KEY_FAILED, line); 601 return line; 602 } 603 604 parser->value_name = NULL; 605 parser->data_type = REG_SZ; 606 parser->data = value; 607 parser->data_size = (lstrlenW(value) + 1) * sizeof(WCHAR); 608 609 set_state(parser, SET_VALUE); 610 return value; 611 } 612 613 /* handler for parser LINE_START state */ 614 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos) 615 { 616 WCHAR *line, *p; 617 618 if (!(line = get_line(parser->file))) 619 return NULL; 620 621 for (p = line; *p; p++) 622 { 623 switch (*p) 624 { 625 case '[': 626 set_state(parser, KEY_NAME); 627 return p + 1; 628 case '@': 629 set_state(parser, DEFAULT_VALUE_NAME); 630 return p; 631 case '"': 632 set_state(parser, QUOTED_VALUE_NAME); 633 return p + 1; 634 case ' ': 635 case '\t': 636 break; 637 default: 638 return p; 639 } 640 } 641 642 return p; 643 } 644 645 /* handler for parser KEY_NAME state */ 646 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos) 647 { 648 WCHAR *p = pos, *key_end; 649 650 if (*p == ' ' || *p == '\t' || !(key_end = wcsrchr(p, ']'))) 651 goto done; 652 653 *key_end = 0; 654 655 if (*p == '-') 656 { 657 set_state(parser, DELETE_KEY); 658 return p + 1; 659 } 660 else if (open_key(parser, p) != ERROR_SUCCESS) 661 output_message(STRING_OPEN_KEY_FAILED, p); 662 663 done: 664 set_state(parser, LINE_START); 665 return p; 666 } 667 668 /* handler for parser DELETE_KEY state */ 669 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos) 670 { 671 WCHAR *p = pos; 672 673 close_key(parser); 674 675 if (*p == 'H' || *p == 'h') 676 delete_registry_key(p); 677 678 set_state(parser, LINE_START); 679 return p; 680 } 681 682 /* handler for parser DEFAULT_VALUE_NAME state */ 683 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos) 684 { 685 free(parser->value_name); 686 parser->value_name = NULL; 687 688 set_state(parser, DATA_START); 689 return pos + 1; 690 } 691 692 /* handler for parser QUOTED_VALUE_NAME state */ 693 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos) 694 { 695 WCHAR *val_name = pos, *p; 696 697 free(parser->value_name); 698 parser->value_name = NULL; 699 700 if (!REGPROC_unescape_string(val_name, &p)) 701 goto invalid; 702 703 /* copy the value name in case we need to parse multiple lines and the buffer is overwritten */ 704 parser->value_name = malloc((lstrlenW(val_name) + 1) * sizeof(WCHAR)); 705 lstrcpyW(parser->value_name, val_name); 706 707 set_state(parser, DATA_START); 708 return p; 709 710 invalid: 711 set_state(parser, LINE_START); 712 return val_name; 713 } 714 715 /* handler for parser DATA_START state */ 716 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos) 717 { 718 WCHAR *p = pos; 719 unsigned int len; 720 721 while (*p == ' ' || *p == '\t') p++; 722 if (*p != '=') goto done; 723 p++; 724 while (*p == ' ' || *p == '\t') p++; 725 726 /* trim trailing whitespace */ 727 len = lstrlenW(p); 728 while (len > 0 && (p[len - 1] == ' ' || p[len - 1] == '\t')) len--; 729 p[len] = 0; 730 731 if (*p == '-') 732 set_state(parser, DELETE_VALUE); 733 else 734 set_state(parser, DATA_TYPE); 735 return p; 736 737 done: 738 set_state(parser, LINE_START); 739 return p; 740 } 741 742 /* handler for parser DELETE_VALUE state */ 743 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos) 744 { 745 WCHAR *p = pos + 1; 746 747 while (*p == ' ' || *p == '\t') p++; 748 if (*p && *p != ';') goto done; 749 750 RegDeleteValueW(parser->hkey, parser->value_name); 751 752 done: 753 set_state(parser, LINE_START); 754 return p; 755 } 756 757 /* handler for parser DATA_TYPE state */ 758 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos) 759 { 760 WCHAR *line = pos; 761 762 if (!parse_data_type(parser, &line)) 763 { 764 set_state(parser, LINE_START); 765 return line; 766 } 767 768 switch (parser->parse_type) 769 { 770 case REG_SZ: 771 set_state(parser, STRING_DATA); 772 break; 773 case REG_DWORD: 774 set_state(parser, DWORD_DATA); 775 break; 776 case REG_BINARY: /* all hex data types, including undefined */ 777 set_state(parser, HEX_DATA); 778 break; 779 default: 780 set_state(parser, UNKNOWN_DATA); 781 } 782 783 return line; 784 } 785 786 /* handler for parser STRING_DATA state */ 787 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos) 788 { 789 WCHAR *line; 790 791 parser->data = pos; 792 793 if (!REGPROC_unescape_string(parser->data, &line)) 794 goto invalid; 795 796 while (*line == ' ' || *line == '\t') line++; 797 if (*line && *line != ';') goto invalid; 798 799 parser->data_size = (lstrlenW(parser->data) + 1) * sizeof(WCHAR); 800 801 set_state(parser, SET_VALUE); 802 return line; 803 804 invalid: 805 free_parser_data(parser); 806 set_state(parser, LINE_START); 807 return line; 808 } 809 810 /* handler for parser DWORD_DATA state */ 811 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos) 812 { 813 WCHAR *line = pos; 814 815 parser->data = malloc(sizeof(DWORD)); 816 817 if (!convert_hex_to_dword(line, parser->data)) 818 goto invalid; 819 820 parser->data_size = sizeof(DWORD); 821 822 set_state(parser, SET_VALUE); 823 return line; 824 825 invalid: 826 free_parser_data(parser); 827 set_state(parser, LINE_START); 828 return line; 829 } 830 831 /* handler for parser HEX_DATA state */ 832 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos) 833 { 834 WCHAR *line = pos; 835 836 if (!*line) 837 goto set_value; 838 839 if (!convert_hex_csv_to_hex(parser, &line)) 840 goto invalid; 841 842 if (parser->backslash) 843 { 844 set_state(parser, EOL_BACKSLASH); 845 return line; 846 } 847 848 prepare_hex_string_data(parser); 849 850 set_value: 851 set_state(parser, SET_VALUE); 852 return line; 853 854 invalid: 855 free_parser_data(parser); 856 set_state(parser, LINE_START); 857 return line; 858 } 859 860 /* handler for parser EOL_BACKSLASH state */ 861 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos) 862 { 863 WCHAR *p = pos; 864 865 while (*p == ' ' || *p == '\t') p++; 866 if (*p && *p != ';') goto invalid; 867 868 set_state(parser, HEX_MULTILINE); 869 return pos; 870 871 invalid: 872 free_parser_data(parser); 873 set_state(parser, LINE_START); 874 return p; 875 } 876 877 /* handler for parser HEX_MULTILINE state */ 878 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos) 879 { 880 WCHAR *line; 881 882 if (!(line = get_line(parser->file))) 883 { 884 prepare_hex_string_data(parser); 885 set_state(parser, SET_VALUE); 886 return pos; 887 } 888 889 while (*line == ' ' || *line == '\t') line++; 890 if (!*line || *line == ';') return line; 891 892 if (!iswxdigit(*line)) goto invalid; 893 894 set_state(parser, HEX_DATA); 895 return line; 896 897 invalid: 898 free_parser_data(parser); 899 set_state(parser, LINE_START); 900 return line; 901 } 902 903 /* handler for parser UNKNOWN_DATA state */ 904 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos) 905 { 906 output_message(STRING_UNKNOWN_DATA_FORMAT, parser->data_type); 907 908 set_state(parser, LINE_START); 909 return pos; 910 } 911 912 /* handler for parser SET_VALUE state */ 913 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos) 914 { 915 RegSetValueExW(parser->hkey, parser->value_name, 0, parser->data_type, 916 parser->data, parser->data_size); 917 918 free_parser_data(parser); 919 920 if (parser->reg_version == REG_VERSION_31) 921 set_state(parser, PARSE_WIN31_LINE); 922 else 923 set_state(parser, LINE_START); 924 925 return pos; 926 } 927 928 static WCHAR *get_lineA(FILE *fp) 929 { 930 static WCHAR *lineW; 931 static size_t size; 932 static char *buf, *next; 933 char *line; 934 935 free(lineW); 936 937 if (!fp) goto cleanup; 938 939 if (!size) 940 { 941 size = REG_VAL_BUF_SIZE; 942 buf = malloc(size); 943 *buf = 0; 944 next = buf; 945 } 946 line = next; 947 948 while (next) 949 { 950 char *p = strpbrk(line, "\r\n"); 951 if (!p) 952 { 953 size_t len, count; 954 len = strlen(next); 955 memmove(buf, next, len + 1); 956 if (size - len < 3) 957 { 958 size *= 2; 959 buf = realloc(buf, size); 960 } 961 if (!(count = fread(buf + len, 1, size - len - 1, fp))) 962 { 963 next = NULL; 964 lineW = GetWideString(buf); 965 return lineW; 966 } 967 buf[len + count] = 0; 968 next = buf; 969 line = buf; 970 continue; 971 } 972 next = p + 1; 973 if (*p == '\r' && *(p + 1) == '\n') next++; 974 *p = 0; 975 lineW = GetWideString(line); 976 return lineW; 977 } 978 979 cleanup: 980 lineW = NULL; 981 if (size) free(buf); 982 size = 0; 983 return NULL; 984 } 985 986 static WCHAR *get_lineW(FILE *fp) 987 { 988 static size_t size; 989 static WCHAR *buf, *next; 990 WCHAR *line; 991 992 if (!fp) goto cleanup; 993 994 if (!size) 995 { 996 size = REG_VAL_BUF_SIZE; 997 buf = malloc(size * sizeof(WCHAR)); 998 *buf = 0; 999 next = buf; 1000 } 1001 line = next; 1002 1003 while (next) 1004 { 1005 WCHAR *p = wcspbrk(line, L"\r\n"); 1006 if (!p) 1007 { 1008 size_t len, count; 1009 len = lstrlenW(next); 1010 memmove(buf, next, (len + 1) * sizeof(WCHAR)); 1011 if (size - len < 3) 1012 { 1013 size *= 2; 1014 buf = realloc(buf, size * sizeof(WCHAR)); 1015 } 1016 if (!(count = fread(buf + len, sizeof(WCHAR), size - len - 1, fp))) 1017 { 1018 next = NULL; 1019 return buf; 1020 } 1021 buf[len + count] = 0; 1022 next = buf; 1023 line = buf; 1024 continue; 1025 } 1026 next = p + 1; 1027 if (*p == '\r' && *(p + 1) == '\n') next++; 1028 *p = 0; 1029 return line; 1030 } 1031 1032 cleanup: 1033 if (size) free(buf); 1034 size = 0; 1035 return NULL; 1036 } 1037 1038 /****************************************************************************** 1039 * Reads contents of the specified file into the registry. 1040 */ 1041 BOOL import_registry_file(FILE *reg_file) 1042 { 1043 BYTE s[2]; 1044 struct parser parser; 1045 WCHAR *pos; 1046 1047 if (!reg_file || (fread(s, 2, 1, reg_file) != 1)) 1048 return FALSE; 1049 1050 parser.is_unicode = (s[0] == 0xff && s[1] == 0xfe); 1051 get_line = parser.is_unicode ? get_lineW : get_lineA; 1052 1053 parser.file = reg_file; 1054 parser.two_wchars[0] = s[0]; 1055 parser.two_wchars[1] = s[1]; 1056 parser.reg_version = -1; 1057 parser.hkey = NULL; 1058 parser.key_name = NULL; 1059 parser.value_name = NULL; 1060 parser.parse_type = 0; 1061 parser.data_type = 0; 1062 parser.data = NULL; 1063 parser.data_size = 0; 1064 parser.backslash = FALSE; 1065 parser.state = HEADER; 1066 1067 pos = parser.two_wchars; 1068 1069 /* parser main loop */ 1070 while (pos) 1071 pos = (parser_funcs[parser.state])(&parser, pos); 1072 1073 if (parser.reg_version == REG_VERSION_FUZZY || parser.reg_version == REG_VERSION_INVALID) 1074 return parser.reg_version == REG_VERSION_FUZZY; 1075 1076 free(parser.value_name); 1077 close_key(&parser); 1078 1079 return TRUE; 1080 } 1081 1082 /****************************************************************************** 1083 * Removes the registry key with all subkeys. Parses full key name. 1084 * 1085 * Parameters: 1086 * reg_key_name - full name of registry branch to delete. Ignored if is NULL, 1087 * empty, points to register key class, does not exist. 1088 */ 1089 void delete_registry_key(WCHAR *reg_key_name) 1090 { 1091 WCHAR *key_name = NULL; 1092 HKEY key_class; 1093 1094 if (!reg_key_name || !reg_key_name[0]) 1095 return; 1096 1097 if (!(key_class = parse_key_name(reg_key_name, &key_name))) 1098 { 1099 if (key_name) *(key_name - 1) = 0; 1100 #ifdef __REACTOS__ 1101 output_message(STRING_INVALID_SYSTEM_KEY, reg_key_name); 1102 return; 1103 #else 1104 error_exit(STRING_INVALID_SYSTEM_KEY, reg_key_name); 1105 #endif 1106 } 1107 1108 if (!key_name || !*key_name) 1109 #ifdef __REACTOS__ 1110 { 1111 output_message(STRING_DELETE_FAILED, reg_key_name); 1112 return; 1113 } 1114 #else 1115 error_exit(STRING_DELETE_FAILED, reg_key_name); 1116 #endif 1117 1118 #ifdef __REACTOS__ 1119 SHDeleteKey(key_class, key_name); 1120 #else 1121 RegDeleteTreeW(key_class, key_name); 1122 #endif 1123 } 1124 1125 static void REGPROC_write_line(FILE *fp, const WCHAR *str, BOOL unicode) 1126 { 1127 if (unicode) 1128 fwrite(str, sizeof(WCHAR), lstrlenW(str), fp); 1129 else 1130 { 1131 char *strA = GetMultiByteString(str); 1132 fputs(strA, fp); 1133 free(strA); 1134 } 1135 } 1136 1137 static WCHAR *REGPROC_escape_string(WCHAR *str, size_t str_len, size_t *line_len) 1138 { 1139 size_t i, escape_count, pos; 1140 WCHAR *buf; 1141 1142 for (i = 0, escape_count = 0; i < str_len; i++) 1143 { 1144 WCHAR c = str[i]; 1145 1146 if (!c) break; 1147 1148 if (c == '\r' || c == '\n' || c == '\\' || c == '"') 1149 escape_count++; 1150 } 1151 1152 buf = malloc((str_len + escape_count + 1) * sizeof(WCHAR)); 1153 1154 for (i = 0, pos = 0; i < str_len; i++, pos++) 1155 { 1156 WCHAR c = str[i]; 1157 1158 if (!c) break; 1159 1160 switch (c) 1161 { 1162 case '\r': 1163 buf[pos++] = '\\'; 1164 buf[pos] = 'r'; 1165 break; 1166 case '\n': 1167 buf[pos++] = '\\'; 1168 buf[pos] = 'n'; 1169 break; 1170 case '\\': 1171 buf[pos++] = '\\'; 1172 buf[pos] = '\\'; 1173 break; 1174 case '"': 1175 buf[pos++] = '\\'; 1176 buf[pos] = '"'; 1177 break; 1178 default: 1179 buf[pos] = c; 1180 } 1181 } 1182 1183 buf[pos] = 0; 1184 *line_len = pos; 1185 return buf; 1186 } 1187 1188 static size_t export_value_name(FILE *fp, WCHAR *name, size_t len, BOOL unicode) 1189 { 1190 static const WCHAR default_name[] = L"@="; 1191 size_t line_len; 1192 1193 if (name && *name) 1194 { 1195 WCHAR *str = REGPROC_escape_string(name, len, &line_len); 1196 WCHAR *buf = malloc((line_len + 4) * sizeof(WCHAR)); 1197 #ifdef __REACTOS__ 1198 StringCchPrintfW(buf, line_len + 4, L"\"%s\"=", str); 1199 line_len = wcslen(buf); 1200 #else 1201 line_len = swprintf(buf, line_len + 4, L"\"%s\"=", str); 1202 #endif 1203 REGPROC_write_line(fp, buf, unicode); 1204 free(buf); 1205 free(str); 1206 } 1207 else 1208 { 1209 line_len = lstrlenW(default_name); 1210 REGPROC_write_line(fp, default_name, unicode); 1211 } 1212 1213 return line_len; 1214 } 1215 1216 static void export_string_data(WCHAR **buf, WCHAR *data, size_t size) 1217 { 1218 size_t len = 0, line_len; 1219 WCHAR *str; 1220 1221 if (size) 1222 len = size / sizeof(WCHAR) - 1; 1223 str = REGPROC_escape_string(data, len, &line_len); 1224 *buf = malloc((line_len + 3) * sizeof(WCHAR)); 1225 #ifdef __REACTOS__ 1226 StringCchPrintfW(*buf, line_len + 3, L"\"%s\"", str); 1227 #else 1228 swprintf(*buf, line_len + 3, L"\"%s\"", str); 1229 #endif 1230 free(str); 1231 } 1232 1233 static void export_dword_data(WCHAR **buf, DWORD *data) 1234 { 1235 *buf = malloc(15 * sizeof(WCHAR)); 1236 #ifdef __REACTOS__ 1237 StringCchPrintfW(*buf, 15, L"dword:%08x", *data); 1238 #else 1239 swprintf(*buf, 15, L"dword:%08x", *data); 1240 #endif 1241 } 1242 1243 static size_t export_hex_data_type(FILE *fp, DWORD type, BOOL unicode) 1244 { 1245 static const WCHAR hex[] = L"hex:"; 1246 size_t line_len; 1247 1248 if (type == REG_BINARY) 1249 { 1250 line_len = lstrlenW(hex); 1251 REGPROC_write_line(fp, hex, unicode); 1252 } 1253 else 1254 { 1255 WCHAR *buf = malloc(15 * sizeof(WCHAR)); 1256 #ifdef __REACTOS__ 1257 StringCchPrintfW(buf, 15, L"hex(%x):", type); 1258 line_len = wcslen(buf); 1259 #else 1260 line_len = swprintf(buf, 15, L"hex(%x):", type); 1261 #endif 1262 REGPROC_write_line(fp, buf, unicode); 1263 free(buf); 1264 } 1265 1266 return line_len; 1267 } 1268 1269 #define MAX_HEX_CHARS 77 1270 1271 static void export_hex_data(FILE *fp, WCHAR **buf, DWORD type, DWORD line_len, 1272 void *data, DWORD size, BOOL unicode) 1273 { 1274 size_t num_commas, i, pos; 1275 1276 line_len += export_hex_data_type(fp, type, unicode); 1277 1278 if (!size) return; 1279 1280 if (!unicode && (type == REG_EXPAND_SZ || type == REG_MULTI_SZ)) 1281 data = GetMultiByteStringN(data, size / sizeof(WCHAR), &size); 1282 1283 num_commas = size - 1; 1284 *buf = malloc(size * 3 * sizeof(WCHAR)); 1285 1286 for (i = 0, pos = 0; i < size; i++) 1287 { 1288 #ifdef __REACTOS__ 1289 StringCchPrintfW(*buf + pos, 3, L"%02x", ((BYTE *)data)[i]); 1290 pos += wcslen(*buf + pos); 1291 #else 1292 pos += swprintf(*buf + pos, 3, L"%02x", ((BYTE *)data)[i]); 1293 #endif 1294 if (i == num_commas) break; 1295 (*buf)[pos++] = ','; 1296 (*buf)[pos] = 0; 1297 line_len += 3; 1298 1299 if (line_len >= MAX_HEX_CHARS) 1300 { 1301 REGPROC_write_line(fp, *buf, unicode); 1302 REGPROC_write_line(fp, L"\\\r\n ", unicode); 1303 line_len = 2; 1304 pos = 0; 1305 } 1306 } 1307 } 1308 1309 static void export_newline(FILE *fp, BOOL unicode) 1310 { 1311 REGPROC_write_line(fp, L"\r\n", unicode); 1312 } 1313 1314 static void export_data(FILE *fp, WCHAR *value_name, DWORD value_len, DWORD type, 1315 void *data, size_t size, BOOL unicode) 1316 { 1317 WCHAR *buf = NULL; 1318 size_t line_len = export_value_name(fp, value_name, value_len, unicode); 1319 1320 switch (type) 1321 { 1322 case REG_SZ: 1323 export_string_data(&buf, data, size); 1324 break; 1325 case REG_DWORD: 1326 if (size) 1327 { 1328 export_dword_data(&buf, data); 1329 break; 1330 } 1331 /* fall through */ 1332 case REG_NONE: 1333 case REG_EXPAND_SZ: 1334 case REG_BINARY: 1335 case REG_MULTI_SZ: 1336 default: 1337 export_hex_data(fp, &buf, type, line_len, data, size, unicode); 1338 break; 1339 } 1340 1341 if (size || type == REG_SZ) 1342 { 1343 REGPROC_write_line(fp, buf, unicode); 1344 free(buf); 1345 } 1346 1347 export_newline(fp, unicode); 1348 } 1349 1350 static WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len) 1351 { 1352 WCHAR *subkey_path; 1353 1354 subkey_path = malloc((path_len + subkey_len + 2) * sizeof(WCHAR)); 1355 #ifdef __REACTOS__ 1356 StringCchPrintfW(subkey_path, path_len + subkey_len + 2, L"%s\\%s", path, subkey_name); 1357 #else 1358 swprintf(subkey_path, path_len + subkey_len + 2, L"%s\\%s", path, subkey_name); 1359 #endif 1360 1361 return subkey_path; 1362 } 1363 1364 static void export_key_name(FILE *fp, WCHAR *name, BOOL unicode) 1365 { 1366 WCHAR *buf; 1367 1368 buf = malloc((lstrlenW(name) + 7) * sizeof(WCHAR)); 1369 #ifdef __REACTOS__ 1370 StringCchPrintfW(buf, lstrlenW(name) + 7, L"\r\n[%s]\r\n", name); 1371 #else 1372 swprintf(buf, lstrlenW(name) + 7, L"\r\n[%s]\r\n", name); 1373 #endif 1374 REGPROC_write_line(fp, buf, unicode); 1375 free(buf); 1376 } 1377 1378 #define MAX_SUBKEY_LEN 257 1379 1380 static void export_registry_data(FILE *fp, HKEY key, WCHAR *path, BOOL unicode) 1381 { 1382 LONG rc; 1383 DWORD max_value_len = 256, value_len; 1384 DWORD max_data_bytes = 2048, data_size; 1385 DWORD subkey_len; 1386 DWORD i, type, path_len; 1387 WCHAR *value_name, *subkey_name, *subkey_path; 1388 BYTE *data; 1389 HKEY subkey; 1390 1391 export_key_name(fp, path, unicode); 1392 1393 value_name = malloc(max_value_len * sizeof(WCHAR)); 1394 data = malloc(max_data_bytes); 1395 1396 i = 0; 1397 for (;;) 1398 { 1399 value_len = max_value_len; 1400 data_size = max_data_bytes; 1401 rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size); 1402 if (rc == ERROR_SUCCESS) 1403 { 1404 export_data(fp, value_name, value_len, type, data, data_size, unicode); 1405 i++; 1406 } 1407 else if (rc == ERROR_MORE_DATA) 1408 { 1409 if (data_size > max_data_bytes) 1410 { 1411 max_data_bytes = data_size; 1412 data = realloc(data, max_data_bytes); 1413 } 1414 else 1415 { 1416 max_value_len *= 2; 1417 value_name = realloc(value_name, max_value_len * sizeof(WCHAR)); 1418 } 1419 } 1420 else break; 1421 } 1422 1423 free(data); 1424 free(value_name); 1425 1426 subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); 1427 1428 path_len = lstrlenW(path); 1429 1430 i = 0; 1431 for (;;) 1432 { 1433 subkey_len = MAX_SUBKEY_LEN; 1434 rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); 1435 if (rc == ERROR_SUCCESS) 1436 { 1437 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len); 1438 if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey)) 1439 { 1440 export_registry_data(fp, subkey, subkey_path, unicode); 1441 RegCloseKey(subkey); 1442 } 1443 free(subkey_path); 1444 i++; 1445 } 1446 else break; 1447 } 1448 1449 free(subkey_name); 1450 } 1451 1452 static FILE *REGPROC_open_export_file(WCHAR *file_name, BOOL unicode) 1453 { 1454 FILE *file; 1455 1456 if (!lstrcmpW(file_name, L"-")) 1457 { 1458 file = stdout; 1459 _setmode(_fileno(file), _O_BINARY); 1460 } 1461 else 1462 { 1463 file = _wfopen(file_name, L"wb"); 1464 if (!file) 1465 { 1466 _wperror(L"regedit"); 1467 #ifdef __REACTOS__ 1468 output_message(STRING_CANNOT_OPEN_FILE, file_name); 1469 return NULL; 1470 #else 1471 error_exit(STRING_CANNOT_OPEN_FILE, file_name); 1472 #endif 1473 } 1474 } 1475 1476 if (unicode) 1477 { 1478 static const BYTE bom[] = {0xff,0xfe}; 1479 static const WCHAR header[] = L"Windows Registry Editor Version 5.00\r\n"; 1480 1481 fwrite(bom, sizeof(BYTE), ARRAY_SIZE(bom), file); 1482 fwrite(header, sizeof(WCHAR), lstrlenW(header), file); 1483 } 1484 else 1485 fputs("REGEDIT4\r\n", file); 1486 1487 return file; 1488 } 1489 1490 static HKEY open_export_key(HKEY key_class, WCHAR *subkey, WCHAR *path) 1491 { 1492 HKEY key; 1493 1494 if (!RegOpenKeyExW(key_class, subkey, 0, KEY_READ, &key)) 1495 return key; 1496 1497 output_message(STRING_OPEN_KEY_FAILED, path); 1498 return NULL; 1499 } 1500 1501 static BOOL export_key(WCHAR *file_name, WCHAR *path, BOOL unicode) 1502 { 1503 HKEY key_class, key; 1504 WCHAR *subkey; 1505 FILE *fp; 1506 1507 if (!(key_class = parse_key_name(path, &subkey))) 1508 { 1509 if (subkey) *(subkey - 1) = 0; 1510 output_message(STRING_INVALID_SYSTEM_KEY, path); 1511 return FALSE; 1512 } 1513 1514 if (!(key = open_export_key(key_class, subkey, path))) 1515 return FALSE; 1516 1517 fp = REGPROC_open_export_file(file_name, unicode); 1518 #ifdef __REACTOS__ 1519 if (!fp) 1520 return TRUE; /* Error message is already displayed */ 1521 #endif 1522 export_registry_data(fp, key, path, unicode); 1523 export_newline(fp, unicode); 1524 fclose(fp); 1525 1526 RegCloseKey(key); 1527 return TRUE; 1528 } 1529 1530 static BOOL export_all(WCHAR *file_name, WCHAR *path, BOOL unicode) 1531 { 1532 FILE *fp; 1533 int i; 1534 HKEY classes[] = {HKEY_LOCAL_MACHINE, HKEY_USERS}, key; 1535 WCHAR *class_name; 1536 1537 fp = REGPROC_open_export_file(file_name, unicode); 1538 #ifdef __REACTOS__ 1539 if (!fp) 1540 return TRUE; /* Error message is already displayed */ 1541 #endif 1542 1543 for (i = 0; i < ARRAY_SIZE(classes); i++) 1544 { 1545 if (!(key = open_export_key(classes[i], NULL, path))) 1546 { 1547 fclose(fp); 1548 return FALSE; 1549 } 1550 1551 class_name = malloc((lstrlenW(reg_class_namesW[i]) + 1) * sizeof(WCHAR)); 1552 lstrcpyW(class_name, reg_class_namesW[i]); 1553 1554 export_registry_data(fp, classes[i], class_name, unicode); 1555 1556 free(class_name); 1557 RegCloseKey(key); 1558 } 1559 1560 export_newline(fp, unicode); 1561 fclose(fp); 1562 1563 return TRUE; 1564 } 1565 1566 BOOL export_registry_key(WCHAR *file_name, WCHAR *path, DWORD format) 1567 { 1568 BOOL unicode = (format == REG_FORMAT_5); 1569 1570 if (path && *path) 1571 return export_key(file_name, path, unicode); 1572 else 1573 return export_all(file_name, path, unicode); 1574 } 1575