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