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 if (*end != ')' || *(end + 1) != ':' || (val == ~0u && errno == ERANGE)) 343 return FALSE; 344 345 parser->data_type = val; 346 *line = end + 2; 347 } 348 return TRUE; 349 } 350 return FALSE; 351 } 352 353 /****************************************************************************** 354 * Replaces escape sequences with their character equivalents and 355 * null-terminates the string on the first non-escaped double quote. 356 * 357 * Assigns a pointer to the remaining unparsed data in the line. 358 * Returns TRUE or FALSE to indicate whether a closing double quote was found. 359 */ 360 static BOOL REGPROC_unescape_string(WCHAR *str, WCHAR **unparsed) 361 { 362 int str_idx = 0; /* current character under analysis */ 363 int val_idx = 0; /* the last character of the unescaped string */ 364 int len = lstrlenW(str); 365 BOOL ret; 366 367 for (str_idx = 0; str_idx < len; str_idx++, val_idx++) { 368 if (str[str_idx] == '\\') { 369 str_idx++; 370 switch (str[str_idx]) { 371 case 'n': 372 str[val_idx] = '\n'; 373 break; 374 case 'r': 375 str[val_idx] = '\r'; 376 break; 377 case '0': 378 return FALSE; 379 case '\\': 380 case '"': 381 str[val_idx] = str[str_idx]; 382 break; 383 default: 384 if (!str[str_idx]) return FALSE; 385 output_message(STRING_ESCAPE_SEQUENCE, str[str_idx]); 386 str[val_idx] = str[str_idx]; 387 break; 388 } 389 } else if (str[str_idx] == '"') { 390 break; 391 } else { 392 str[val_idx] = str[str_idx]; 393 } 394 } 395 396 ret = (str[str_idx] == '"'); 397 *unparsed = str + str_idx + 1; 398 str[val_idx] = '\0'; 399 return ret; 400 } 401 402 static HKEY parse_key_name(WCHAR *key_name, WCHAR **key_path) 403 { 404 unsigned int i; 405 406 if (!key_name) return 0; 407 408 *key_path = wcschr(key_name, '\\'); 409 if (*key_path) (*key_path)++; 410 411 for (i = 0; i < ARRAY_SIZE(reg_class_keys); i++) 412 { 413 int len = lstrlenW(reg_class_namesW[i]); 414 #ifdef __REACTOS__ 415 if (!_wcsnicmp(key_name, reg_class_namesW[i], len) && 416 #else 417 if (!wcsnicmp(key_name, reg_class_namesW[i], len) && 418 #endif 419 (key_name[len] == 0 || key_name[len] == '\\')) 420 { 421 return reg_class_keys[i]; 422 } 423 } 424 425 return 0; 426 } 427 428 static void close_key(struct parser *parser) 429 { 430 if (parser->hkey) 431 { 432 free(parser->key_name); 433 parser->key_name = NULL; 434 435 RegCloseKey(parser->hkey); 436 parser->hkey = NULL; 437 } 438 } 439 440 /****************************************************************************** 441 * Opens the registry key given by the input path. 442 * This key must be closed by calling close_key(). 443 */ 444 static LONG open_key(struct parser *parser, WCHAR *path) 445 { 446 HKEY key_class; 447 WCHAR *key_path; 448 LONG res; 449 450 close_key(parser); 451 452 /* Get the registry class */ 453 if (!path || !(key_class = parse_key_name(path, &key_path))) 454 return ERROR_INVALID_PARAMETER; 455 456 res = RegCreateKeyExW(key_class, key_path, 0, NULL, REG_OPTION_NON_VOLATILE, 457 KEY_ALL_ACCESS, NULL, &parser->hkey, NULL); 458 459 if (res == ERROR_SUCCESS) 460 { 461 parser->key_name = malloc((lstrlenW(path) + 1) * sizeof(WCHAR)); 462 lstrcpyW(parser->key_name, path); 463 } 464 else 465 parser->hkey = NULL; 466 467 return res; 468 } 469 470 static void free_parser_data(struct parser *parser) 471 { 472 if (parser->parse_type == REG_DWORD || parser->parse_type == REG_BINARY) 473 free(parser->data); 474 475 parser->data = NULL; 476 parser->data_size = 0; 477 } 478 479 static void prepare_hex_string_data(struct parser *parser) 480 { 481 if (parser->data_type == REG_EXPAND_SZ || parser->data_type == REG_MULTI_SZ || 482 parser->data_type == REG_SZ) 483 { 484 if (parser->is_unicode) 485 { 486 WCHAR *data = parser->data; 487 DWORD len = parser->data_size / sizeof(WCHAR); 488 489 if (data[len - 1] != 0) 490 { 491 data[len] = 0; 492 parser->data_size += sizeof(WCHAR); 493 } 494 } 495 else 496 { 497 BYTE *data = parser->data; 498 499 if (data[parser->data_size - 1] != 0) 500 { 501 data[parser->data_size] = 0; 502 parser->data_size++; 503 } 504 505 parser->data = GetWideStringN(parser->data, parser->data_size, &parser->data_size); 506 parser->data_size *= sizeof(WCHAR); 507 free(data); 508 } 509 } 510 } 511 512 enum reg_versions { 513 REG_VERSION_31, 514 REG_VERSION_40, 515 REG_VERSION_50, 516 REG_VERSION_FUZZY, 517 REG_VERSION_INVALID 518 }; 519 520 static enum reg_versions parse_file_header(const WCHAR *s) 521 { 522 static const WCHAR header_31[] = L"REGEDIT"; 523 524 while (*s == ' ' || *s == '\t') s++; 525 526 if (!lstrcmpW(s, header_31)) 527 return REG_VERSION_31; 528 529 if (!lstrcmpW(s, L"REGEDIT4")) 530 return REG_VERSION_40; 531 532 if (!lstrcmpW(s, L"Windows Registry Editor Version 5.00")) 533 return REG_VERSION_50; 534 535 /* The Windows version accepts registry file headers beginning with "REGEDIT" and ending 536 * with other characters, as long as "REGEDIT" appears at the start of the line. For example, 537 * "REGEDIT 4", "REGEDIT9" and "REGEDIT4FOO" are all treated as valid file headers. 538 * In all such cases, however, the contents of the registry file are not imported. 539 */ 540 if (!wcsncmp(s, header_31, 7)) /* "REGEDIT" without NUL */ 541 return REG_VERSION_FUZZY; 542 543 return REG_VERSION_INVALID; 544 } 545 546 /* handler for parser HEADER state */ 547 static WCHAR *header_state(struct parser *parser, WCHAR *pos) 548 { 549 WCHAR *line, *header; 550 551 if (!(line = get_line(parser->file))) 552 return NULL; 553 554 if (!parser->is_unicode) 555 { 556 header = malloc((lstrlenW(line) + 3) * sizeof(WCHAR)); 557 header[0] = parser->two_wchars[0]; 558 header[1] = parser->two_wchars[1]; 559 lstrcpyW(header + 2, line); 560 parser->reg_version = parse_file_header(header); 561 free(header); 562 } 563 else parser->reg_version = parse_file_header(line); 564 565 switch (parser->reg_version) 566 { 567 case REG_VERSION_31: 568 set_state(parser, PARSE_WIN31_LINE); 569 break; 570 case REG_VERSION_40: 571 case REG_VERSION_50: 572 set_state(parser, LINE_START); 573 break; 574 default: 575 get_line(NULL); /* Reset static variables */ 576 return NULL; 577 } 578 579 return line; 580 } 581 582 /* handler for parser PARSE_WIN31_LINE state */ 583 static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos) 584 { 585 WCHAR *line, *value; 586 static WCHAR hkcr[] = L"HKEY_CLASSES_ROOT"; 587 unsigned int key_end = 0; 588 589 if (!(line = get_line(parser->file))) 590 return NULL; 591 592 if (wcsncmp(line, hkcr, lstrlenW(hkcr))) 593 return line; 594 595 /* get key name */ 596 while (line[key_end] && !iswspace(line[key_end])) key_end++; 597 598 value = line + key_end; 599 while (*value == ' ' || *value == '\t') value++; 600 601 if (*value == '=') value++; 602 if (*value == ' ') value++; /* at most one space is skipped */ 603 604 line[key_end] = 0; 605 606 if (open_key(parser, line) != ERROR_SUCCESS) 607 { 608 output_message(STRING_OPEN_KEY_FAILED, line); 609 return line; 610 } 611 612 parser->value_name = NULL; 613 parser->data_type = REG_SZ; 614 parser->data = value; 615 parser->data_size = (lstrlenW(value) + 1) * sizeof(WCHAR); 616 617 set_state(parser, SET_VALUE); 618 return value; 619 } 620 621 /* handler for parser LINE_START state */ 622 static WCHAR *line_start_state(struct parser *parser, WCHAR *pos) 623 { 624 WCHAR *line, *p; 625 626 if (!(line = get_line(parser->file))) 627 return NULL; 628 629 for (p = line; *p; p++) 630 { 631 switch (*p) 632 { 633 case '[': 634 set_state(parser, KEY_NAME); 635 return p + 1; 636 case '@': 637 set_state(parser, DEFAULT_VALUE_NAME); 638 return p; 639 case '"': 640 set_state(parser, QUOTED_VALUE_NAME); 641 return p + 1; 642 case ' ': 643 case '\t': 644 break; 645 default: 646 return p; 647 } 648 } 649 650 return p; 651 } 652 653 /* handler for parser KEY_NAME state */ 654 static WCHAR *key_name_state(struct parser *parser, WCHAR *pos) 655 { 656 WCHAR *p = pos, *key_end; 657 658 if (*p == ' ' || *p == '\t' || !(key_end = wcsrchr(p, ']'))) 659 goto done; 660 661 *key_end = 0; 662 663 if (*p == '-') 664 { 665 set_state(parser, DELETE_KEY); 666 return p + 1; 667 } 668 else if (open_key(parser, p) != ERROR_SUCCESS) 669 output_message(STRING_OPEN_KEY_FAILED, p); 670 671 done: 672 set_state(parser, LINE_START); 673 return p; 674 } 675 676 /* handler for parser DELETE_KEY state */ 677 static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos) 678 { 679 WCHAR *p = pos; 680 681 close_key(parser); 682 683 if (*p == 'H' || *p == 'h') 684 delete_registry_key(p); 685 686 set_state(parser, LINE_START); 687 return p; 688 } 689 690 /* handler for parser DEFAULT_VALUE_NAME state */ 691 static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos) 692 { 693 free(parser->value_name); 694 parser->value_name = NULL; 695 696 set_state(parser, DATA_START); 697 return pos + 1; 698 } 699 700 /* handler for parser QUOTED_VALUE_NAME state */ 701 static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos) 702 { 703 WCHAR *val_name = pos, *p; 704 705 free(parser->value_name); 706 parser->value_name = NULL; 707 708 if (!REGPROC_unescape_string(val_name, &p)) 709 goto invalid; 710 711 /* copy the value name in case we need to parse multiple lines and the buffer is overwritten */ 712 parser->value_name = malloc((lstrlenW(val_name) + 1) * sizeof(WCHAR)); 713 lstrcpyW(parser->value_name, val_name); 714 715 set_state(parser, DATA_START); 716 return p; 717 718 invalid: 719 set_state(parser, LINE_START); 720 return val_name; 721 } 722 723 /* handler for parser DATA_START state */ 724 static WCHAR *data_start_state(struct parser *parser, WCHAR *pos) 725 { 726 WCHAR *p = pos; 727 unsigned int len; 728 729 while (*p == ' ' || *p == '\t') p++; 730 if (*p != '=') goto done; 731 p++; 732 while (*p == ' ' || *p == '\t') p++; 733 734 /* trim trailing whitespace */ 735 len = lstrlenW(p); 736 while (len > 0 && (p[len - 1] == ' ' || p[len - 1] == '\t')) len--; 737 p[len] = 0; 738 739 if (*p == '-') 740 set_state(parser, DELETE_VALUE); 741 else 742 set_state(parser, DATA_TYPE); 743 return p; 744 745 done: 746 set_state(parser, LINE_START); 747 return p; 748 } 749 750 /* handler for parser DELETE_VALUE state */ 751 static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos) 752 { 753 WCHAR *p = pos + 1; 754 755 while (*p == ' ' || *p == '\t') p++; 756 if (*p && *p != ';') goto done; 757 758 RegDeleteValueW(parser->hkey, parser->value_name); 759 760 done: 761 set_state(parser, LINE_START); 762 return p; 763 } 764 765 /* handler for parser DATA_TYPE state */ 766 static WCHAR *data_type_state(struct parser *parser, WCHAR *pos) 767 { 768 WCHAR *line = pos; 769 770 if (!parse_data_type(parser, &line)) 771 { 772 set_state(parser, LINE_START); 773 return line; 774 } 775 776 switch (parser->parse_type) 777 { 778 case REG_SZ: 779 set_state(parser, STRING_DATA); 780 break; 781 case REG_DWORD: 782 set_state(parser, DWORD_DATA); 783 break; 784 case REG_BINARY: /* all hex data types, including undefined */ 785 set_state(parser, HEX_DATA); 786 break; 787 default: 788 set_state(parser, UNKNOWN_DATA); 789 } 790 791 return line; 792 } 793 794 /* handler for parser STRING_DATA state */ 795 static WCHAR *string_data_state(struct parser *parser, WCHAR *pos) 796 { 797 WCHAR *line; 798 799 parser->data = pos; 800 801 if (!REGPROC_unescape_string(parser->data, &line)) 802 goto invalid; 803 804 while (*line == ' ' || *line == '\t') line++; 805 if (*line && *line != ';') goto invalid; 806 807 parser->data_size = (lstrlenW(parser->data) + 1) * sizeof(WCHAR); 808 809 set_state(parser, SET_VALUE); 810 return line; 811 812 invalid: 813 free_parser_data(parser); 814 set_state(parser, LINE_START); 815 return line; 816 } 817 818 /* handler for parser DWORD_DATA state */ 819 static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos) 820 { 821 WCHAR *line = pos; 822 823 parser->data = malloc(sizeof(DWORD)); 824 825 if (!convert_hex_to_dword(line, parser->data)) 826 goto invalid; 827 828 parser->data_size = sizeof(DWORD); 829 830 set_state(parser, SET_VALUE); 831 return line; 832 833 invalid: 834 free_parser_data(parser); 835 set_state(parser, LINE_START); 836 return line; 837 } 838 839 /* handler for parser HEX_DATA state */ 840 static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos) 841 { 842 WCHAR *line = pos; 843 844 if (!*line) 845 goto set_value; 846 847 if (!convert_hex_csv_to_hex(parser, &line)) 848 goto invalid; 849 850 if (parser->backslash) 851 { 852 set_state(parser, EOL_BACKSLASH); 853 return line; 854 } 855 856 prepare_hex_string_data(parser); 857 858 set_value: 859 set_state(parser, SET_VALUE); 860 return line; 861 862 invalid: 863 free_parser_data(parser); 864 set_state(parser, LINE_START); 865 return line; 866 } 867 868 /* handler for parser EOL_BACKSLASH state */ 869 static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos) 870 { 871 WCHAR *p = pos; 872 873 while (*p == ' ' || *p == '\t') p++; 874 if (*p && *p != ';') goto invalid; 875 876 set_state(parser, HEX_MULTILINE); 877 return pos; 878 879 invalid: 880 free_parser_data(parser); 881 set_state(parser, LINE_START); 882 return p; 883 } 884 885 /* handler for parser HEX_MULTILINE state */ 886 static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos) 887 { 888 WCHAR *line; 889 890 if (!(line = get_line(parser->file))) 891 { 892 prepare_hex_string_data(parser); 893 set_state(parser, SET_VALUE); 894 return pos; 895 } 896 897 while (*line == ' ' || *line == '\t') line++; 898 if (!*line || *line == ';') return line; 899 900 if (!iswxdigit(*line)) goto invalid; 901 902 set_state(parser, HEX_DATA); 903 return line; 904 905 invalid: 906 free_parser_data(parser); 907 set_state(parser, LINE_START); 908 return line; 909 } 910 911 /* handler for parser UNKNOWN_DATA state */ 912 static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos) 913 { 914 output_message(STRING_UNKNOWN_DATA_FORMAT, parser->data_type); 915 916 set_state(parser, LINE_START); 917 return pos; 918 } 919 920 /* handler for parser SET_VALUE state */ 921 static WCHAR *set_value_state(struct parser *parser, WCHAR *pos) 922 { 923 RegSetValueExW(parser->hkey, parser->value_name, 0, parser->data_type, 924 parser->data, parser->data_size); 925 926 free_parser_data(parser); 927 928 if (parser->reg_version == REG_VERSION_31) 929 set_state(parser, PARSE_WIN31_LINE); 930 else 931 set_state(parser, LINE_START); 932 933 return pos; 934 } 935 936 static WCHAR *get_lineA(FILE *fp) 937 { 938 static WCHAR *lineW; 939 static size_t size; 940 static char *buf, *next; 941 char *line; 942 943 free(lineW); 944 945 if (!fp) goto cleanup; 946 947 if (!size) 948 { 949 size = REG_VAL_BUF_SIZE; 950 buf = malloc(size); 951 *buf = 0; 952 next = buf; 953 } 954 line = next; 955 956 while (next) 957 { 958 char *p = strpbrk(line, "\r\n"); 959 if (!p) 960 { 961 size_t len, count; 962 len = strlen(next); 963 memmove(buf, next, len + 1); 964 if (size - len < 3) 965 { 966 size *= 2; 967 buf = realloc(buf, size); 968 } 969 if (!(count = fread(buf + len, 1, size - len - 1, fp))) 970 { 971 next = NULL; 972 lineW = GetWideString(buf); 973 return lineW; 974 } 975 buf[len + count] = 0; 976 next = buf; 977 line = buf; 978 continue; 979 } 980 next = p + 1; 981 if (*p == '\r' && *(p + 1) == '\n') next++; 982 *p = 0; 983 lineW = GetWideString(line); 984 return lineW; 985 } 986 987 cleanup: 988 lineW = NULL; 989 if (size) free(buf); 990 size = 0; 991 return NULL; 992 } 993 994 static WCHAR *get_lineW(FILE *fp) 995 { 996 static size_t size; 997 static WCHAR *buf, *next; 998 WCHAR *line; 999 1000 if (!fp) goto cleanup; 1001 1002 if (!size) 1003 { 1004 size = REG_VAL_BUF_SIZE; 1005 buf = malloc(size * sizeof(WCHAR)); 1006 *buf = 0; 1007 next = buf; 1008 } 1009 line = next; 1010 1011 while (next) 1012 { 1013 WCHAR *p = wcspbrk(line, L"\r\n"); 1014 if (!p) 1015 { 1016 size_t len, count; 1017 len = lstrlenW(next); 1018 memmove(buf, next, (len + 1) * sizeof(WCHAR)); 1019 if (size - len < 3) 1020 { 1021 size *= 2; 1022 buf = realloc(buf, size * sizeof(WCHAR)); 1023 } 1024 if (!(count = fread(buf + len, sizeof(WCHAR), size - len - 1, fp))) 1025 { 1026 next = NULL; 1027 return buf; 1028 } 1029 buf[len + count] = 0; 1030 next = buf; 1031 line = buf; 1032 continue; 1033 } 1034 next = p + 1; 1035 if (*p == '\r' && *(p + 1) == '\n') next++; 1036 *p = 0; 1037 return line; 1038 } 1039 1040 cleanup: 1041 if (size) free(buf); 1042 size = 0; 1043 return NULL; 1044 } 1045 1046 /****************************************************************************** 1047 * Reads contents of the specified file into the registry. 1048 */ 1049 BOOL import_registry_file(FILE *reg_file) 1050 { 1051 BYTE s[2]; 1052 struct parser parser; 1053 WCHAR *pos; 1054 1055 if (!reg_file || (fread(s, 2, 1, reg_file) != 1)) 1056 return FALSE; 1057 1058 parser.is_unicode = (s[0] == 0xff && s[1] == 0xfe); 1059 get_line = parser.is_unicode ? get_lineW : get_lineA; 1060 1061 parser.file = reg_file; 1062 parser.two_wchars[0] = s[0]; 1063 parser.two_wchars[1] = s[1]; 1064 parser.reg_version = -1; 1065 parser.hkey = NULL; 1066 parser.key_name = NULL; 1067 parser.value_name = NULL; 1068 parser.parse_type = 0; 1069 parser.data_type = 0; 1070 parser.data = NULL; 1071 parser.data_size = 0; 1072 parser.backslash = FALSE; 1073 parser.state = HEADER; 1074 1075 pos = parser.two_wchars; 1076 1077 /* parser main loop */ 1078 while (pos) 1079 pos = (parser_funcs[parser.state])(&parser, pos); 1080 1081 if (parser.reg_version == REG_VERSION_FUZZY || parser.reg_version == REG_VERSION_INVALID) 1082 return parser.reg_version == REG_VERSION_FUZZY; 1083 1084 free(parser.value_name); 1085 close_key(&parser); 1086 1087 return TRUE; 1088 } 1089 1090 /****************************************************************************** 1091 * Removes the registry key with all subkeys. Parses full key name. 1092 * 1093 * Parameters: 1094 * reg_key_name - full name of registry branch to delete. Ignored if is NULL, 1095 * empty, points to register key class, does not exist. 1096 */ 1097 void delete_registry_key(WCHAR *reg_key_name) 1098 { 1099 WCHAR *key_name = NULL; 1100 HKEY key_class; 1101 1102 if (!reg_key_name || !reg_key_name[0]) 1103 return; 1104 1105 if (!(key_class = parse_key_name(reg_key_name, &key_name))) 1106 { 1107 if (key_name) *(key_name - 1) = 0; 1108 #ifdef __REACTOS__ 1109 output_message(STRING_INVALID_SYSTEM_KEY, reg_key_name); 1110 return; 1111 #else 1112 error_exit(STRING_INVALID_SYSTEM_KEY, reg_key_name); 1113 #endif 1114 } 1115 1116 if (!key_name || !*key_name) 1117 #ifdef __REACTOS__ 1118 { 1119 output_message(STRING_DELETE_FAILED, reg_key_name); 1120 return; 1121 } 1122 #else 1123 error_exit(STRING_DELETE_FAILED, reg_key_name); 1124 #endif 1125 1126 #ifdef __REACTOS__ 1127 SHDeleteKey(key_class, key_name); 1128 #else 1129 RegDeleteTreeW(key_class, key_name); 1130 #endif 1131 } 1132 1133 static void REGPROC_write_line(FILE *fp, const WCHAR *str, BOOL unicode) 1134 { 1135 if (unicode) 1136 fwrite(str, sizeof(WCHAR), lstrlenW(str), fp); 1137 else 1138 { 1139 char *strA = GetMultiByteString(str); 1140 fputs(strA, fp); 1141 free(strA); 1142 } 1143 } 1144 1145 static WCHAR *REGPROC_escape_string(WCHAR *str, size_t str_len, size_t *line_len) 1146 { 1147 size_t i, escape_count, pos; 1148 WCHAR *buf; 1149 1150 for (i = 0, escape_count = 0; i < str_len; i++) 1151 { 1152 WCHAR c = str[i]; 1153 1154 if (!c) break; 1155 1156 if (c == '\r' || c == '\n' || c == '\\' || c == '"') 1157 escape_count++; 1158 } 1159 1160 buf = malloc((str_len + escape_count + 1) * sizeof(WCHAR)); 1161 1162 for (i = 0, pos = 0; i < str_len; i++, pos++) 1163 { 1164 WCHAR c = str[i]; 1165 1166 if (!c) break; 1167 1168 switch (c) 1169 { 1170 case '\r': 1171 buf[pos++] = '\\'; 1172 buf[pos] = 'r'; 1173 break; 1174 case '\n': 1175 buf[pos++] = '\\'; 1176 buf[pos] = 'n'; 1177 break; 1178 case '\\': 1179 buf[pos++] = '\\'; 1180 buf[pos] = '\\'; 1181 break; 1182 case '"': 1183 buf[pos++] = '\\'; 1184 buf[pos] = '"'; 1185 break; 1186 default: 1187 buf[pos] = c; 1188 } 1189 } 1190 1191 buf[pos] = 0; 1192 *line_len = pos; 1193 return buf; 1194 } 1195 1196 static size_t export_value_name(FILE *fp, WCHAR *name, size_t len, BOOL unicode) 1197 { 1198 static const WCHAR default_name[] = L"@="; 1199 size_t line_len; 1200 1201 if (name && *name) 1202 { 1203 WCHAR *str = REGPROC_escape_string(name, len, &line_len); 1204 WCHAR *buf = malloc((line_len + 4) * sizeof(WCHAR)); 1205 #ifdef __REACTOS__ 1206 StringCchPrintfW(buf, line_len + 4, L"\"%s\"=", str); 1207 line_len = wcslen(buf); 1208 #else 1209 line_len = swprintf(buf, line_len + 4, L"\"%s\"=", str); 1210 #endif 1211 REGPROC_write_line(fp, buf, unicode); 1212 free(buf); 1213 free(str); 1214 } 1215 else 1216 { 1217 line_len = lstrlenW(default_name); 1218 REGPROC_write_line(fp, default_name, unicode); 1219 } 1220 1221 return line_len; 1222 } 1223 1224 static void export_string_data(WCHAR **buf, WCHAR *data, size_t size) 1225 { 1226 size_t len = 0, line_len; 1227 WCHAR *str; 1228 1229 if (size) 1230 len = size / sizeof(WCHAR) - 1; 1231 str = REGPROC_escape_string(data, len, &line_len); 1232 *buf = malloc((line_len + 3) * sizeof(WCHAR)); 1233 #ifdef __REACTOS__ 1234 StringCchPrintfW(*buf, line_len + 3, L"\"%s\"", str); 1235 #else 1236 swprintf(*buf, line_len + 3, L"\"%s\"", str); 1237 #endif 1238 free(str); 1239 } 1240 1241 static void export_dword_data(WCHAR **buf, DWORD *data) 1242 { 1243 *buf = malloc(15 * sizeof(WCHAR)); 1244 #ifdef __REACTOS__ 1245 StringCchPrintfW(*buf, 15, L"dword:%08x", *data); 1246 #else 1247 swprintf(*buf, 15, L"dword:%08x", *data); 1248 #endif 1249 } 1250 1251 static size_t export_hex_data_type(FILE *fp, DWORD type, BOOL unicode) 1252 { 1253 static const WCHAR hex[] = L"hex:"; 1254 size_t line_len; 1255 1256 if (type == REG_BINARY) 1257 { 1258 line_len = lstrlenW(hex); 1259 REGPROC_write_line(fp, hex, unicode); 1260 } 1261 else 1262 { 1263 WCHAR *buf = malloc(15 * sizeof(WCHAR)); 1264 #ifdef __REACTOS__ 1265 StringCchPrintfW(buf, 15, L"hex(%x):", type); 1266 line_len = wcslen(buf); 1267 #else 1268 line_len = swprintf(buf, 15, L"hex(%x):", type); 1269 #endif 1270 REGPROC_write_line(fp, buf, unicode); 1271 free(buf); 1272 } 1273 1274 return line_len; 1275 } 1276 1277 #define MAX_HEX_CHARS 77 1278 1279 static void export_hex_data(FILE *fp, WCHAR **buf, DWORD type, DWORD line_len, 1280 void *data, DWORD size, BOOL unicode) 1281 { 1282 size_t num_commas, i, pos; 1283 1284 line_len += export_hex_data_type(fp, type, unicode); 1285 1286 if (!size) return; 1287 1288 if (!unicode && (type == REG_EXPAND_SZ || type == REG_MULTI_SZ)) 1289 data = GetMultiByteStringN(data, size / sizeof(WCHAR), &size); 1290 1291 num_commas = size - 1; 1292 *buf = malloc(size * 3 * sizeof(WCHAR)); 1293 1294 for (i = 0, pos = 0; i < size; i++) 1295 { 1296 #ifdef __REACTOS__ 1297 StringCchPrintfW(*buf + pos, 3, L"%02x", ((BYTE *)data)[i]); 1298 pos += wcslen(*buf + pos); 1299 #else 1300 pos += swprintf(*buf + pos, 3, L"%02x", ((BYTE *)data)[i]); 1301 #endif 1302 if (i == num_commas) break; 1303 (*buf)[pos++] = ','; 1304 (*buf)[pos] = 0; 1305 line_len += 3; 1306 1307 if (line_len >= MAX_HEX_CHARS) 1308 { 1309 REGPROC_write_line(fp, *buf, unicode); 1310 REGPROC_write_line(fp, L"\\\r\n ", unicode); 1311 line_len = 2; 1312 pos = 0; 1313 } 1314 } 1315 } 1316 1317 static void export_newline(FILE *fp, BOOL unicode) 1318 { 1319 REGPROC_write_line(fp, L"\r\n", unicode); 1320 } 1321 1322 static void export_data(FILE *fp, WCHAR *value_name, DWORD value_len, DWORD type, 1323 void *data, size_t size, BOOL unicode) 1324 { 1325 WCHAR *buf = NULL; 1326 size_t line_len = export_value_name(fp, value_name, value_len, unicode); 1327 1328 switch (type) 1329 { 1330 case REG_SZ: 1331 export_string_data(&buf, data, size); 1332 break; 1333 case REG_DWORD: 1334 if (size) 1335 { 1336 export_dword_data(&buf, data); 1337 break; 1338 } 1339 /* fall through */ 1340 case REG_NONE: 1341 case REG_EXPAND_SZ: 1342 case REG_BINARY: 1343 case REG_MULTI_SZ: 1344 default: 1345 export_hex_data(fp, &buf, type, line_len, data, size, unicode); 1346 break; 1347 } 1348 1349 if (size || type == REG_SZ) 1350 { 1351 REGPROC_write_line(fp, buf, unicode); 1352 free(buf); 1353 } 1354 1355 export_newline(fp, unicode); 1356 } 1357 1358 static WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len) 1359 { 1360 WCHAR *subkey_path; 1361 1362 subkey_path = malloc((path_len + subkey_len + 2) * sizeof(WCHAR)); 1363 #ifdef __REACTOS__ 1364 StringCchPrintfW(subkey_path, path_len + subkey_len + 2, L"%s\\%s", path, subkey_name); 1365 #else 1366 swprintf(subkey_path, path_len + subkey_len + 2, L"%s\\%s", path, subkey_name); 1367 #endif 1368 1369 return subkey_path; 1370 } 1371 1372 static void export_key_name(FILE *fp, WCHAR *name, BOOL unicode) 1373 { 1374 WCHAR *buf; 1375 1376 buf = malloc((lstrlenW(name) + 7) * sizeof(WCHAR)); 1377 #ifdef __REACTOS__ 1378 StringCchPrintfW(buf, lstrlenW(name) + 7, L"\r\n[%s]\r\n", name); 1379 #else 1380 swprintf(buf, lstrlenW(name) + 7, L"\r\n[%s]\r\n", name); 1381 #endif 1382 REGPROC_write_line(fp, buf, unicode); 1383 free(buf); 1384 } 1385 1386 #define MAX_SUBKEY_LEN 257 1387 1388 static void export_registry_data(FILE *fp, HKEY key, WCHAR *path, BOOL unicode) 1389 { 1390 LONG rc; 1391 DWORD max_value_len = 256, value_len; 1392 DWORD max_data_bytes = 2048, data_size; 1393 DWORD subkey_len; 1394 DWORD i, type, path_len; 1395 WCHAR *value_name, *subkey_name, *subkey_path; 1396 BYTE *data; 1397 HKEY subkey; 1398 1399 export_key_name(fp, path, unicode); 1400 1401 value_name = malloc(max_value_len * sizeof(WCHAR)); 1402 data = malloc(max_data_bytes); 1403 1404 i = 0; 1405 for (;;) 1406 { 1407 value_len = max_value_len; 1408 data_size = max_data_bytes; 1409 rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size); 1410 if (rc == ERROR_SUCCESS) 1411 { 1412 export_data(fp, value_name, value_len, type, data, data_size, unicode); 1413 i++; 1414 } 1415 else if (rc == ERROR_MORE_DATA) 1416 { 1417 if (data_size > max_data_bytes) 1418 { 1419 max_data_bytes = data_size; 1420 data = realloc(data, max_data_bytes); 1421 } 1422 else 1423 { 1424 max_value_len *= 2; 1425 value_name = realloc(value_name, max_value_len * sizeof(WCHAR)); 1426 } 1427 } 1428 else break; 1429 } 1430 1431 free(data); 1432 free(value_name); 1433 1434 subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); 1435 1436 path_len = lstrlenW(path); 1437 1438 i = 0; 1439 for (;;) 1440 { 1441 subkey_len = MAX_SUBKEY_LEN; 1442 rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); 1443 if (rc == ERROR_SUCCESS) 1444 { 1445 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len); 1446 if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey)) 1447 { 1448 export_registry_data(fp, subkey, subkey_path, unicode); 1449 RegCloseKey(subkey); 1450 } 1451 free(subkey_path); 1452 i++; 1453 } 1454 else break; 1455 } 1456 1457 free(subkey_name); 1458 } 1459 1460 static FILE *REGPROC_open_export_file(WCHAR *file_name, BOOL unicode) 1461 { 1462 FILE *file; 1463 1464 if (!lstrcmpW(file_name, L"-")) 1465 { 1466 file = stdout; 1467 _setmode(_fileno(file), _O_BINARY); 1468 } 1469 else 1470 { 1471 file = _wfopen(file_name, L"wb"); 1472 if (!file) 1473 { 1474 _wperror(L"regedit"); 1475 #ifdef __REACTOS__ 1476 output_message(STRING_CANNOT_OPEN_FILE, file_name); 1477 return NULL; 1478 #else 1479 error_exit(STRING_CANNOT_OPEN_FILE, file_name); 1480 #endif 1481 } 1482 } 1483 1484 if (unicode) 1485 { 1486 static const BYTE bom[] = {0xff,0xfe}; 1487 static const WCHAR header[] = L"Windows Registry Editor Version 5.00\r\n"; 1488 1489 fwrite(bom, sizeof(BYTE), ARRAY_SIZE(bom), file); 1490 fwrite(header, sizeof(WCHAR), lstrlenW(header), file); 1491 } 1492 else 1493 fputs("REGEDIT4\r\n", file); 1494 1495 return file; 1496 } 1497 1498 static HKEY open_export_key(HKEY key_class, WCHAR *subkey, WCHAR *path) 1499 { 1500 HKEY key; 1501 1502 if (!RegOpenKeyExW(key_class, subkey, 0, KEY_READ, &key)) 1503 return key; 1504 1505 output_message(STRING_OPEN_KEY_FAILED, path); 1506 return NULL; 1507 } 1508 1509 static BOOL export_key(WCHAR *file_name, WCHAR *path, BOOL unicode) 1510 { 1511 HKEY key_class, key; 1512 WCHAR *subkey; 1513 FILE *fp; 1514 1515 if (!(key_class = parse_key_name(path, &subkey))) 1516 { 1517 if (subkey) *(subkey - 1) = 0; 1518 output_message(STRING_INVALID_SYSTEM_KEY, path); 1519 return FALSE; 1520 } 1521 1522 if (!(key = open_export_key(key_class, subkey, path))) 1523 return FALSE; 1524 1525 fp = REGPROC_open_export_file(file_name, unicode); 1526 #ifdef __REACTOS__ 1527 if (!fp) 1528 return TRUE; /* Error message is already displayed */ 1529 #endif 1530 export_registry_data(fp, key, path, unicode); 1531 export_newline(fp, unicode); 1532 fclose(fp); 1533 1534 RegCloseKey(key); 1535 return TRUE; 1536 } 1537 1538 static BOOL export_all(WCHAR *file_name, WCHAR *path, BOOL unicode) 1539 { 1540 FILE *fp; 1541 int i; 1542 HKEY classes[] = {HKEY_LOCAL_MACHINE, HKEY_USERS}, key; 1543 WCHAR *class_name; 1544 1545 fp = REGPROC_open_export_file(file_name, unicode); 1546 #ifdef __REACTOS__ 1547 if (!fp) 1548 return TRUE; /* Error message is already displayed */ 1549 #endif 1550 1551 for (i = 0; i < ARRAY_SIZE(classes); i++) 1552 { 1553 if (!(key = open_export_key(classes[i], NULL, path))) 1554 { 1555 fclose(fp); 1556 return FALSE; 1557 } 1558 1559 class_name = malloc((lstrlenW(reg_class_namesW[i]) + 1) * sizeof(WCHAR)); 1560 lstrcpyW(class_name, reg_class_namesW[i]); 1561 1562 export_registry_data(fp, classes[i], class_name, unicode); 1563 1564 free(class_name); 1565 RegCloseKey(key); 1566 } 1567 1568 export_newline(fp, unicode); 1569 fclose(fp); 1570 1571 return TRUE; 1572 } 1573 1574 BOOL export_registry_key(WCHAR *file_name, WCHAR *path, DWORD format) 1575 { 1576 BOOL unicode = (format == REG_FORMAT_5); 1577 1578 if (path && *path) 1579 return export_key(file_name, path, unicode); 1580 else 1581 return export_all(file_name, path, unicode); 1582 } 1583