1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2005 Mike McCormack for CodeWeavers 5 * Copyright 2005 Aric Stewart for CodeWeavers 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include <stdarg.h> 23 #include <stdio.h> 24 25 #define COBJMACROS 26 27 #include "windef.h" 28 #include "winbase.h" 29 #include "winerror.h" 30 #include "wine/debug.h" 31 #include "msi.h" 32 #include "winnls.h" 33 #include "objbase.h" 34 #include "oleauto.h" 35 36 #include "msipriv.h" 37 #include "winemsi_s.h" 38 #include "wine/exception.h" 39 40 WINE_DEFAULT_DEBUG_CHANNEL(msi); 41 42 /* types arranged by precedence */ 43 #define FORMAT_NULL 0x0001 44 #define FORMAT_LITERAL 0x0002 45 #define FORMAT_NUMBER 0x0004 46 #define FORMAT_LBRACK 0x0010 47 #define FORMAT_LBRACE 0x0020 48 #define FORMAT_RBRACK 0x0011 49 #define FORMAT_RBRACE 0x0021 50 #define FORMAT_ESCAPE 0x0040 51 #define FORMAT_PROPNULL 0x0080 52 #define FORMAT_ERROR 0x1000 53 #define FORMAT_FAIL 0x2000 54 55 #define left_type(x) (x & 0xF0) 56 57 struct format 58 { 59 MSIPACKAGE *package; 60 MSIRECORD *record; 61 LPWSTR deformatted; 62 int len; 63 int n; 64 BOOL propfailed; 65 BOOL groupfailed; 66 int groups; 67 }; 68 69 struct form_str 70 { 71 struct list entry; 72 int n; 73 int len; 74 int type; 75 BOOL propfound; 76 BOOL nonprop; 77 }; 78 79 struct stack 80 { 81 struct list items; 82 }; 83 84 static struct stack *create_stack(void) 85 { 86 struct stack *stack = malloc(sizeof(*stack)); 87 list_init(&stack->items); 88 return stack; 89 } 90 91 static void free_stack(struct stack *stack) 92 { 93 while (!list_empty(&stack->items)) 94 { 95 struct form_str *str = LIST_ENTRY(list_head(&stack->items), struct form_str, entry); 96 list_remove(&str->entry); 97 free(str); 98 } 99 100 free(stack); 101 } 102 103 static void stack_push(struct stack *stack, struct form_str *str) 104 { 105 list_add_head(&stack->items, &str->entry); 106 } 107 108 static struct form_str *stack_pop(struct stack *stack) 109 { 110 struct form_str *ret; 111 112 if (list_empty(&stack->items)) 113 return NULL; 114 115 ret = LIST_ENTRY(list_head(&stack->items), struct form_str, entry); 116 list_remove(&ret->entry); 117 return ret; 118 } 119 120 static struct form_str *stack_find(struct stack *stack, int type) 121 { 122 struct form_str *str; 123 124 LIST_FOR_EACH_ENTRY(str, &stack->items, struct form_str, entry) 125 { 126 if (str->type == type) 127 return str; 128 } 129 130 return NULL; 131 } 132 133 static struct form_str *stack_peek(struct stack *stack) 134 { 135 return LIST_ENTRY(list_head(&stack->items), struct form_str, entry); 136 } 137 138 static const WCHAR *get_formstr_data(struct format *format, struct form_str *str) 139 { 140 return &format->deformatted[str->n]; 141 } 142 143 static WCHAR *dup_formstr( struct format *format, struct form_str *str, int *ret_len ) 144 { 145 WCHAR *val; 146 147 if (!str->len) return NULL; 148 if ((val = malloc( (str->len + 1) * sizeof(WCHAR) ))) 149 { 150 memcpy( val, get_formstr_data(format, str), str->len * sizeof(WCHAR) ); 151 val[str->len] = 0; 152 *ret_len = str->len; 153 } 154 return val; 155 } 156 157 static WCHAR *deformat_index( struct format *format, struct form_str *str, int *ret_len ) 158 { 159 WCHAR *val, *ret; 160 DWORD len; 161 int field; 162 163 if (!(val = malloc( (str->len + 1) * sizeof(WCHAR) ))) return NULL; 164 lstrcpynW(val, get_formstr_data(format, str), str->len + 1); 165 field = wcstol( val, NULL, 10 ); 166 free( val ); 167 168 if (MSI_RecordIsNull( format->record, field ) || 169 MSI_RecordGetStringW( format->record, field, NULL, &len )) return NULL; 170 171 len++; 172 if (!(ret = malloc( len * sizeof(WCHAR) ))) return NULL; 173 ret[0] = 0; 174 if (MSI_RecordGetStringW( format->record, field, ret, &len )) 175 { 176 free( ret ); 177 return NULL; 178 } 179 *ret_len = len; 180 return ret; 181 } 182 183 static WCHAR *deformat_property( struct format *format, struct form_str *str, int *ret_len ) 184 { 185 WCHAR *prop, *ret; 186 DWORD len = 0; 187 UINT r; 188 189 if (!(prop = malloc( (str->len + 1) * sizeof(WCHAR) ))) return NULL; 190 lstrcpynW( prop, get_formstr_data(format, str), str->len + 1 ); 191 192 r = msi_get_property( format->package->db, prop, NULL, &len ); 193 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) 194 { 195 free( prop ); 196 return NULL; 197 } 198 len++; 199 if ((ret = malloc( len * sizeof(WCHAR) ))) 200 msi_get_property( format->package->db, prop, ret, &len ); 201 free( prop ); 202 *ret_len = len; 203 return ret; 204 } 205 206 static WCHAR *deformat_component( struct format *format, struct form_str *str, int *ret_len ) 207 { 208 WCHAR *key, *ret; 209 MSICOMPONENT *comp; 210 211 if (!(key = malloc( (str->len + 1) * sizeof(WCHAR) ))) return NULL; 212 lstrcpynW(key, get_formstr_data(format, str), str->len + 1); 213 214 if (!(comp = msi_get_loaded_component( format->package, key ))) 215 { 216 free( key ); 217 return NULL; 218 } 219 if (comp->Action == INSTALLSTATE_SOURCE) 220 ret = msi_resolve_source_folder( format->package, comp->Directory, NULL ); 221 else 222 ret = wcsdup( msi_get_target_folder( format->package, comp->Directory ) ); 223 224 if (ret) *ret_len = lstrlenW( ret ); 225 else *ret_len = 0; 226 free( key ); 227 return ret; 228 } 229 230 static WCHAR *deformat_file( struct format *format, struct form_str *str, BOOL shortname, int *ret_len ) 231 { 232 WCHAR *key, *ret = NULL; 233 const MSIFILE *file; 234 DWORD len = 0; 235 236 if (!(key = malloc( (str->len + 1) * sizeof(WCHAR) ))) return NULL; 237 lstrcpynW(key, get_formstr_data(format, str), str->len + 1); 238 239 if (!(file = msi_get_loaded_file( format->package, key ))) goto done; 240 if (!shortname) 241 { 242 if ((ret = wcsdup( file->TargetPath ))) len = lstrlenW( ret ); 243 goto done; 244 } 245 if (!(len = GetShortPathNameW(file->TargetPath, NULL, 0))) 246 { 247 if ((ret = wcsdup( file->TargetPath ))) len = lstrlenW( ret ); 248 goto done; 249 } 250 len++; 251 if ((ret = malloc( len * sizeof(WCHAR) ))) 252 len = GetShortPathNameW( file->TargetPath, ret, len ); 253 254 done: 255 free( key ); 256 *ret_len = len; 257 return ret; 258 } 259 260 static WCHAR *deformat_environment( struct format *format, struct form_str *str, int *ret_len ) 261 { 262 WCHAR *key, *ret = NULL; 263 DWORD len; 264 265 if (!(key = malloc((str->len + 1) * sizeof(WCHAR)))) return NULL; 266 lstrcpynW(key, get_formstr_data(format, str), str->len + 1); 267 268 if ((len = GetEnvironmentVariableW( key, NULL, 0 ))) 269 { 270 len++; 271 if ((ret = malloc( len * sizeof(WCHAR) ))) 272 *ret_len = GetEnvironmentVariableW( key, ret, len ); 273 } 274 free( key ); 275 return ret; 276 } 277 278 static WCHAR *deformat_literal( struct format *format, struct form_str *str, BOOL *propfound, 279 int *type, int *len ) 280 { 281 LPCWSTR data = get_formstr_data(format, str); 282 WCHAR *replaced = NULL; 283 char ch = data[0]; 284 285 if (ch == '\\') 286 { 287 str->n++; 288 if (str->len == 1) 289 { 290 str->len = 0; 291 replaced = NULL; 292 } 293 else 294 { 295 str->len = 1; 296 replaced = dup_formstr( format, str, len ); 297 } 298 } 299 else if (ch == '~') 300 { 301 if (str->len != 1) 302 replaced = NULL; 303 else if ((replaced = malloc( sizeof(WCHAR) ))) 304 { 305 *replaced = 0; 306 *len = 0; 307 } 308 } 309 else if (ch == '%' || ch == '#' || ch == '!' || ch == '$') 310 { 311 str->n++; 312 str->len--; 313 314 switch (ch) 315 { 316 case '%': 317 replaced = deformat_environment( format, str, len ); break; 318 case '#': 319 replaced = deformat_file( format, str, FALSE, len ); break; 320 case '!': 321 replaced = deformat_file( format, str, TRUE, len ); break; 322 case '$': 323 replaced = deformat_component( format, str, len ); break; 324 } 325 326 *type = FORMAT_LITERAL; 327 } 328 else 329 { 330 replaced = deformat_property( format, str, len ); 331 *type = FORMAT_LITERAL; 332 333 if (replaced) 334 *propfound = TRUE; 335 else 336 format->propfailed = TRUE; 337 } 338 339 return replaced; 340 } 341 342 static WCHAR *build_default_format( const MSIRECORD *record ) 343 { 344 int i, count = MSI_RecordGetFieldCount( record ); 345 WCHAR *ret, *tmp, buf[26]; 346 DWORD size = 1; 347 348 if (!(ret = malloc( sizeof(*ret) ))) return NULL; 349 ret[0] = 0; 350 351 for (i = 1; i <= count; i++) 352 { 353 size += swprintf( buf, ARRAY_SIZE(buf), L"%d: [%d] ", i, i ); 354 if (!(tmp = realloc( ret, size * sizeof(*ret) ))) 355 { 356 free( ret ); 357 return NULL; 358 } 359 ret = tmp; 360 lstrcatW( ret, buf ); 361 } 362 return ret; 363 } 364 365 static BOOL format_is_number(WCHAR x) 366 { 367 return ((x >= '0') && (x <= '9')); 368 } 369 370 static BOOL format_str_is_number(LPWSTR str) 371 { 372 LPWSTR ptr; 373 374 for (ptr = str; *ptr; ptr++) 375 if (!format_is_number(*ptr)) 376 return FALSE; 377 378 return TRUE; 379 } 380 381 static BOOL format_is_alpha(WCHAR x) 382 { 383 return (!format_is_number(x) && x != '\0' && 384 x != '[' && x != ']' && x != '{' && x != '}'); 385 } 386 387 static BOOL format_is_literal(WCHAR x) 388 { 389 return (format_is_alpha(x) || format_is_number(x)); 390 } 391 392 static int format_lex(struct format *format, struct form_str **out) 393 { 394 int type, len = 1; 395 struct form_str *str; 396 LPCWSTR data; 397 WCHAR ch; 398 399 *out = NULL; 400 401 if (!format->deformatted) 402 return FORMAT_NULL; 403 404 *out = calloc(1, sizeof(**out)); 405 if (!*out) 406 return FORMAT_FAIL; 407 408 str = *out; 409 str->n = format->n; 410 str->len = 1; 411 data = get_formstr_data(format, str); 412 413 ch = data[0]; 414 switch (ch) 415 { 416 case '{': type = FORMAT_LBRACE; break; 417 case '}': type = FORMAT_RBRACE; break; 418 case '[': type = FORMAT_LBRACK; break; 419 case ']': type = FORMAT_RBRACK; break; 420 case '~': type = FORMAT_PROPNULL; break; 421 case '\0': type = FORMAT_NULL; break; 422 423 default: 424 type = 0; 425 } 426 427 if (type) 428 { 429 str->type = type; 430 format->n++; 431 return type; 432 } 433 434 if (ch == '\\') 435 { 436 while (data[len] && data[len] != ']') 437 len++; 438 439 type = FORMAT_ESCAPE; 440 } 441 else if (format_is_alpha(ch)) 442 { 443 while (format_is_literal(data[len])) 444 len++; 445 446 type = FORMAT_LITERAL; 447 } 448 else if (format_is_number(ch)) 449 { 450 while (format_is_number(data[len])) 451 len++; 452 453 type = FORMAT_NUMBER; 454 455 if (data[len] != ']') 456 { 457 while (format_is_literal(data[len])) 458 len++; 459 460 type = FORMAT_LITERAL; 461 } 462 } 463 else 464 { 465 ERR("Got unknown character %c(%x)\n", ch, ch); 466 return FORMAT_ERROR; 467 } 468 469 format->n += len; 470 str->len = len; 471 str->type = type; 472 473 return type; 474 } 475 476 static struct form_str *format_replace( struct format *format, BOOL propfound, BOOL nonprop, 477 int oldsize, int type, WCHAR *replace, int len ) 478 { 479 struct form_str *ret; 480 LPWSTR str, ptr; 481 DWORD size = 0; 482 int n; 483 484 if (replace) 485 { 486 if (!len) 487 size = 1; 488 else 489 size = len; 490 } 491 492 size -= oldsize; 493 size = format->len + size + 1; 494 495 if (size <= 1) 496 { 497 free(format->deformatted); 498 format->deformatted = NULL; 499 format->len = 0; 500 return NULL; 501 } 502 503 str = malloc(size * sizeof(WCHAR)); 504 if (!str) 505 return NULL; 506 507 str[0] = '\0'; 508 memcpy(str, format->deformatted, format->n * sizeof(WCHAR)); 509 n = format->n; 510 511 if (replace) 512 { 513 if (!len) str[n++] = 0; 514 else 515 { 516 memcpy( str + n, replace, len * sizeof(WCHAR) ); 517 n += len; 518 str[n] = 0; 519 } 520 } 521 522 ptr = &format->deformatted[format->n + oldsize]; 523 memcpy(&str[n], ptr, (lstrlenW(ptr) + 1) * sizeof(WCHAR)); 524 525 free(format->deformatted); 526 format->deformatted = str; 527 format->len = size - 1; 528 529 /* don't reformat the NULL */ 530 if (replace && !len) 531 format->n++; 532 533 if (!replace) 534 return NULL; 535 536 ret = calloc(1, sizeof(*ret)); 537 if (!ret) 538 return NULL; 539 540 ret->len = len; 541 ret->type = type; 542 ret->n = format->n; 543 ret->propfound = propfound; 544 ret->nonprop = nonprop; 545 546 return ret; 547 } 548 549 static WCHAR *replace_stack_group( struct format *format, struct stack *values, 550 BOOL *propfound, BOOL *nonprop, 551 int *oldsize, int *type, int *len ) 552 { 553 WCHAR *replaced; 554 struct form_str *content, *node; 555 int n; 556 557 *nonprop = FALSE; 558 *propfound = FALSE; 559 560 node = stack_pop(values); 561 n = node->n; 562 *oldsize = node->len; 563 free(node); 564 565 while ((node = stack_pop(values))) 566 { 567 *oldsize += node->len; 568 569 if (node->nonprop) 570 *nonprop = TRUE; 571 572 if (node->propfound) 573 *propfound = TRUE; 574 575 free(node); 576 } 577 578 content = calloc(1, sizeof(*content)); 579 content->n = n; 580 content->len = *oldsize; 581 content->type = FORMAT_LITERAL; 582 583 if (!format->groupfailed && (*oldsize == 2 || 584 (format->propfailed && !*nonprop))) 585 { 586 free(content); 587 return NULL; 588 } 589 else if (format->deformatted[content->n + 1] == '{' && 590 format->deformatted[content->n + content->len - 2] == '}') 591 { 592 format->groupfailed = FALSE; 593 content->len = 0; 594 } 595 else if (*propfound && !*nonprop && 596 !format->groupfailed && format->groups == 0) 597 { 598 content->n++; 599 content->len -= 2; 600 } 601 else 602 { 603 if (format->groups != 0) 604 format->groupfailed = TRUE; 605 606 *nonprop = TRUE; 607 } 608 609 replaced = dup_formstr( format, content, len ); 610 *type = content->type; 611 free(content); 612 613 if (format->groups == 0) 614 format->propfailed = FALSE; 615 616 return replaced; 617 } 618 619 static WCHAR *replace_stack_prop( struct format *format, struct stack *values, 620 BOOL *propfound, BOOL *nonprop, 621 int *oldsize, int *type, int *len ) 622 { 623 WCHAR *replaced; 624 struct form_str *content, *node; 625 int n; 626 627 *propfound = FALSE; 628 *nonprop = FALSE; 629 630 node = stack_pop(values); 631 n = node->n; 632 *oldsize = node->len; 633 *type = stack_peek(values)->type; 634 free(node); 635 636 while ((node = stack_pop(values))) 637 { 638 *oldsize += node->len; 639 640 if (*type != FORMAT_ESCAPE && 641 stack_peek(values) && node->type != *type) 642 *type = FORMAT_LITERAL; 643 644 free(node); 645 } 646 647 content = calloc(1, sizeof(*content)); 648 content->n = n + 1; 649 content->len = *oldsize - 2; 650 content->type = *type; 651 652 if (*type == FORMAT_NUMBER && format->record) 653 { 654 replaced = deformat_index( format, content, len ); 655 if (replaced) 656 *propfound = TRUE; 657 else 658 format->propfailed = TRUE; 659 660 if (replaced) 661 *type = format_str_is_number(replaced) ? 662 FORMAT_NUMBER : FORMAT_LITERAL; 663 } 664 else if (format->package) 665 { 666 replaced = deformat_literal( format, content, propfound, type, len ); 667 } 668 else 669 { 670 *nonprop = TRUE; 671 content->n--; 672 content->len += 2; 673 replaced = dup_formstr( format, content, len ); 674 } 675 free(content); 676 return replaced; 677 } 678 679 static UINT replace_stack(struct format *format, struct stack *stack, struct stack *values) 680 { 681 WCHAR *replaced = NULL; 682 struct form_str *beg, *top, *node; 683 BOOL propfound = FALSE, nonprop = FALSE, group = FALSE; 684 int type, n, len = 0, oldsize = 0; 685 686 node = stack_peek(values); 687 type = node->type; 688 n = node->n; 689 690 if (type == FORMAT_LBRACK) 691 replaced = replace_stack_prop( format, values, &propfound, 692 &nonprop, &oldsize, &type, &len ); 693 else if (type == FORMAT_LBRACE) 694 { 695 replaced = replace_stack_group( format, values, &propfound, 696 &nonprop, &oldsize, &type, &len ); 697 group = TRUE; 698 } 699 700 format->n = n; 701 beg = format_replace( format, propfound, nonprop, oldsize, type, replaced, len ); 702 free(replaced); 703 if (!beg) 704 return ERROR_SUCCESS; 705 706 format->n = beg->n + beg->len; 707 708 top = stack_peek(stack); 709 if (top) 710 { 711 type = top->type; 712 713 if ((type == FORMAT_LITERAL || type == FORMAT_NUMBER) && 714 type == beg->type) 715 { 716 top->len += beg->len; 717 718 if (group) 719 top->nonprop = FALSE; 720 721 if (type == FORMAT_LITERAL) 722 top->nonprop = beg->nonprop; 723 724 if (beg->propfound) 725 top->propfound = TRUE; 726 727 free(beg); 728 return ERROR_SUCCESS; 729 } 730 } 731 732 stack_push(stack, beg); 733 return ERROR_SUCCESS; 734 } 735 736 static BOOL verify_format(LPWSTR data) 737 { 738 int count = 0; 739 740 while (*data) 741 { 742 if (*data == '[' && *(data - 1) != '\\') 743 count++; 744 else if (*data == ']') 745 count--; 746 747 data++; 748 } 749 750 if (count > 0) 751 return FALSE; 752 753 return TRUE; 754 } 755 756 static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, 757 WCHAR** data, DWORD *len, 758 MSIRECORD* record) 759 { 760 struct format format; 761 struct form_str *str = NULL; 762 struct stack *stack, *temp; 763 struct form_str *node; 764 int type; 765 766 if (!ptr) 767 { 768 *data = NULL; 769 *len = 0; 770 return ERROR_SUCCESS; 771 } 772 773 *data = wcsdup(ptr); 774 *len = lstrlenW(ptr); 775 776 ZeroMemory(&format, sizeof(format)); 777 format.package = package; 778 format.record = record; 779 format.deformatted = *data; 780 format.len = *len; 781 782 if (!verify_format(*data)) 783 return ERROR_SUCCESS; 784 785 stack = create_stack(); 786 temp = create_stack(); 787 788 while ((type = format_lex(&format, &str)) != FORMAT_NULL) 789 { 790 if (type == FORMAT_LBRACK || type == FORMAT_LBRACE || 791 type == FORMAT_LITERAL || type == FORMAT_NUMBER || 792 type == FORMAT_ESCAPE || type == FORMAT_PROPNULL) 793 { 794 if (type == FORMAT_LBRACE) 795 { 796 format.propfailed = FALSE; 797 format.groups++; 798 } 799 else if (type == FORMAT_ESCAPE && 800 !stack_find(stack, FORMAT_LBRACK)) 801 { 802 format.n -= str->len - 1; 803 str->len = 1; 804 } 805 806 stack_push(stack, str); 807 } 808 else if (type == FORMAT_RBRACK || type == FORMAT_RBRACE) 809 { 810 if (type == FORMAT_RBRACE) 811 format.groups--; 812 813 stack_push(stack, str); 814 815 if (stack_find(stack, left_type(type))) 816 { 817 do 818 { 819 node = stack_pop(stack); 820 stack_push(temp, node); 821 } while (node->type != left_type(type)); 822 823 replace_stack(&format, stack, temp); 824 } 825 } 826 } 827 828 *data = format.deformatted; 829 *len = format.len; 830 831 free(str); 832 free_stack(stack); 833 free_stack(temp); 834 835 return ERROR_SUCCESS; 836 } 837 838 UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, 839 LPDWORD size ) 840 { 841 WCHAR *format, *deformated = NULL; 842 UINT rc = ERROR_INVALID_PARAMETER; 843 DWORD len; 844 MSIRECORD *record_deformated; 845 int field_count, i; 846 847 TRACE("%p %p %p %p\n", package, record, buffer, size); 848 dump_record(record); 849 850 if (!(format = msi_dup_record_field( record, 0 ))) 851 format = build_default_format( record ); 852 853 field_count = MSI_RecordGetFieldCount(record); 854 record_deformated = MSI_CloneRecord(record); 855 if (!record_deformated) 856 { 857 rc = ERROR_OUTOFMEMORY; 858 goto end; 859 } 860 MSI_RecordSetStringW(record_deformated, 0, format); 861 for (i = 1; i <= field_count; i++) 862 { 863 if (MSI_RecordGetString(record, i)) 864 { 865 deformat_string_internal(package, MSI_RecordGetString(record, i), &deformated, &len, NULL); 866 MSI_RecordSetStringW(record_deformated, i, deformated); 867 free(deformated); 868 } 869 } 870 871 deformat_string_internal(package, format, &deformated, &len, record_deformated); 872 if (buffer) 873 { 874 if (*size>len) 875 { 876 memcpy(buffer,deformated,len*sizeof(WCHAR)); 877 rc = ERROR_SUCCESS; 878 buffer[len] = 0; 879 } 880 else 881 { 882 if (*size > 0) 883 { 884 memcpy(buffer,deformated,(*size)*sizeof(WCHAR)); 885 buffer[(*size)-1] = 0; 886 } 887 rc = ERROR_MORE_DATA; 888 } 889 } 890 else rc = ERROR_SUCCESS; 891 892 *size = len; 893 msiobj_release(&record_deformated->hdr); 894 end: 895 free( format ); 896 free( deformated ); 897 return rc; 898 } 899 900 UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord, WCHAR *szResult, DWORD *sz ) 901 { 902 UINT r = ERROR_INVALID_HANDLE; 903 MSIPACKAGE *package; 904 MSIRECORD *record; 905 906 TRACE( "%lu, %lu, %p, %p\n", hInstall, hRecord, szResult, sz ); 907 908 record = msihandle2msiinfo(hRecord, MSIHANDLETYPE_RECORD); 909 if (!record) 910 return ERROR_INVALID_HANDLE; 911 912 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); 913 if (!package) 914 { 915 LPWSTR value = NULL; 916 MSIHANDLE remote; 917 918 if ((remote = msi_get_remote(hInstall))) 919 { 920 __TRY 921 { 922 r = remote_FormatRecord(remote, (struct wire_record *)&record->count, &value); 923 } 924 __EXCEPT(rpc_filter) 925 { 926 r = GetExceptionCode(); 927 } 928 __ENDTRY 929 930 if (!r) 931 r = msi_strncpyW(value, -1, szResult, sz); 932 933 midl_user_free(value); 934 msiobj_release(&record->hdr); 935 return r; 936 } 937 } 938 939 if (!sz) 940 { 941 msiobj_release( &record->hdr ); 942 if (szResult) 943 return ERROR_INVALID_PARAMETER; 944 else 945 return ERROR_SUCCESS; 946 } 947 948 r = MSI_FormatRecordW( package, record, szResult, sz ); 949 msiobj_release( &record->hdr ); 950 if (package) 951 msiobj_release( &package->hdr ); 952 return r; 953 } 954 955 UINT WINAPI MsiFormatRecordA(MSIHANDLE hinst, MSIHANDLE hrec, char *buf, DWORD *sz) 956 { 957 MSIPACKAGE *package; 958 MSIRECORD *rec; 959 LPWSTR value; 960 DWORD len; 961 UINT r; 962 963 TRACE( "%lu, %lu, %p, %p\n", hinst, hrec, buf, sz ); 964 965 rec = msihandle2msiinfo(hrec, MSIHANDLETYPE_RECORD); 966 if (!rec) 967 return ERROR_INVALID_HANDLE; 968 969 package = msihandle2msiinfo(hinst, MSIHANDLETYPE_PACKAGE); 970 if (!package) 971 { 972 LPWSTR value = NULL; 973 MSIHANDLE remote; 974 975 if ((remote = msi_get_remote(hinst))) 976 { 977 __TRY 978 { 979 r = remote_FormatRecord(remote, (struct wire_record *)&rec->count, &value); 980 } 981 __EXCEPT(rpc_filter) 982 { 983 r = GetExceptionCode(); 984 } 985 __ENDTRY 986 987 if (!r) 988 r = msi_strncpyWtoA(value, -1, buf, sz, TRUE); 989 990 midl_user_free(value); 991 msiobj_release(&rec->hdr); 992 return r; 993 } 994 } 995 996 r = MSI_FormatRecordW(package, rec, NULL, &len); 997 if (r != ERROR_SUCCESS) 998 return r; 999 1000 value = malloc(++len * sizeof(WCHAR)); 1001 if (!value) 1002 goto done; 1003 1004 r = MSI_FormatRecordW(package, rec, value, &len); 1005 if (!r) 1006 r = msi_strncpyWtoA(value, len, buf, sz, FALSE); 1007 1008 free(value); 1009 done: 1010 msiobj_release(&rec->hdr); 1011 if (package) msiobj_release(&package->hdr); 1012 return r; 1013 } 1014 1015 /* wrapper to resist a need for a full rewrite right now */ 1016 DWORD deformat_string( MSIPACKAGE *package, const WCHAR *fmt, WCHAR **data ) 1017 { 1018 DWORD len; 1019 MSIRECORD *rec; 1020 1021 *data = NULL; 1022 if (!fmt) return 0; 1023 if (!(rec = MSI_CreateRecord( 1 ))) return 0; 1024 1025 MSI_RecordSetStringW( rec, 0, fmt ); 1026 MSI_FormatRecordW( package, rec, NULL, &len ); 1027 if (!(*data = malloc( ++len * sizeof(WCHAR) ))) 1028 { 1029 msiobj_release( &rec->hdr ); 1030 return 0; 1031 } 1032 MSI_FormatRecordW( package, rec, *data, &len ); 1033 msiobj_release( &rec->hdr ); 1034 return len; 1035 } 1036