1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2002-2004 Mike McCormack for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "msipriv.h" 22 23 WINE_DEFAULT_DEBUG_CHANNEL(msidb); 24 25 #define MSIFIELD_NULL 0 26 #define MSIFIELD_INT 1 27 #define MSIFIELD_WSTR 3 28 #define MSIFIELD_STREAM 4 29 #define MSIFIELD_INTPTR 5 30 31 static void MSI_FreeField( MSIFIELD *field ) 32 { 33 switch( field->type ) 34 { 35 case MSIFIELD_NULL: 36 case MSIFIELD_INT: 37 case MSIFIELD_INTPTR: 38 break; 39 case MSIFIELD_WSTR: 40 msi_free( field->u.szwVal); 41 break; 42 case MSIFIELD_STREAM: 43 IStream_Release( field->u.stream ); 44 break; 45 default: 46 ERR("Invalid field type %d\n", field->type); 47 } 48 } 49 50 void MSI_CloseRecord( MSIOBJECTHDR *arg ) 51 { 52 MSIRECORD *rec = (MSIRECORD *) arg; 53 UINT i; 54 55 for( i=0; i<=rec->count; i++ ) 56 MSI_FreeField( &rec->fields[i] ); 57 } 58 59 MSIRECORD *MSI_CreateRecord( UINT cParams ) 60 { 61 MSIRECORD *rec; 62 63 TRACE("%d\n", cParams); 64 65 if( cParams>65535 ) 66 return NULL; 67 68 rec = alloc_msiobject( MSIHANDLETYPE_RECORD, FIELD_OFFSET(MSIRECORD, fields[cParams + 1]), 69 MSI_CloseRecord ); 70 if( rec ) 71 rec->count = cParams; 72 return rec; 73 } 74 75 MSIHANDLE WINAPI MsiCreateRecord( UINT cParams ) 76 { 77 MSIRECORD *rec; 78 MSIHANDLE ret = 0; 79 80 TRACE("%d\n", cParams); 81 82 rec = MSI_CreateRecord( cParams ); 83 if( rec ) 84 { 85 ret = alloc_msihandle( &rec->hdr ); 86 msiobj_release( &rec->hdr ); 87 } 88 return ret; 89 } 90 91 UINT MSI_RecordGetFieldCount( const MSIRECORD *rec ) 92 { 93 return rec->count; 94 } 95 96 UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle ) 97 { 98 MSIRECORD *rec; 99 UINT ret; 100 101 TRACE("%d\n", handle ); 102 103 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 104 if( !rec ) 105 return -1; 106 107 msiobj_lock( &rec->hdr ); 108 ret = MSI_RecordGetFieldCount( rec ); 109 msiobj_unlock( &rec->hdr ); 110 msiobj_release( &rec->hdr ); 111 112 return ret; 113 } 114 115 static BOOL string2intW( LPCWSTR str, int *out ) 116 { 117 int x = 0; 118 LPCWSTR p = str; 119 120 if( *p == '-' ) /* skip the minus sign */ 121 p++; 122 while ( *p ) 123 { 124 if( (*p < '0') || (*p > '9') ) 125 return FALSE; 126 x *= 10; 127 x += (*p - '0'); 128 p++; 129 } 130 131 if( str[0] == '-' ) /* check if it's negative */ 132 x = -x; 133 *out = x; 134 135 return TRUE; 136 } 137 138 WCHAR *msi_strdupW( const WCHAR *value, int len ) 139 { 140 WCHAR *ret; 141 142 if (!value) return NULL; 143 if (!(ret = msi_alloc( (len + 1) * sizeof(WCHAR) ))) return NULL; 144 memcpy( ret, value, len * sizeof(WCHAR) ); 145 ret[len] = 0; 146 return ret; 147 } 148 149 UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n, 150 MSIRECORD *out_rec, UINT out_n ) 151 { 152 UINT r = ERROR_SUCCESS; 153 154 msiobj_lock( &in_rec->hdr ); 155 156 if ( in_n > in_rec->count || out_n > out_rec->count ) 157 r = ERROR_FUNCTION_FAILED; 158 else if ( in_rec != out_rec || in_n != out_n ) 159 { 160 LPWSTR str; 161 MSIFIELD *in, *out; 162 163 in = &in_rec->fields[in_n]; 164 out = &out_rec->fields[out_n]; 165 166 switch ( in->type ) 167 { 168 case MSIFIELD_NULL: 169 break; 170 case MSIFIELD_INT: 171 out->u.iVal = in->u.iVal; 172 break; 173 case MSIFIELD_INTPTR: 174 out->u.pVal = in->u.pVal; 175 break; 176 case MSIFIELD_WSTR: 177 if ((str = msi_strdupW( in->u.szwVal, in->len ))) 178 { 179 out->u.szwVal = str; 180 out->len = in->len; 181 } 182 else r = ERROR_OUTOFMEMORY; 183 break; 184 case MSIFIELD_STREAM: 185 IStream_AddRef( in->u.stream ); 186 out->u.stream = in->u.stream; 187 break; 188 default: 189 ERR("invalid field type %d\n", in->type); 190 } 191 if (r == ERROR_SUCCESS) 192 out->type = in->type; 193 } 194 195 msiobj_unlock( &in_rec->hdr ); 196 return r; 197 } 198 199 INT_PTR MSI_RecordGetIntPtr( MSIRECORD *rec, UINT iField ) 200 { 201 int ret; 202 203 TRACE( "%p %d\n", rec, iField ); 204 205 if( iField > rec->count ) 206 return MININT_PTR; 207 208 switch( rec->fields[iField].type ) 209 { 210 case MSIFIELD_INT: 211 return rec->fields[iField].u.iVal; 212 case MSIFIELD_INTPTR: 213 return rec->fields[iField].u.pVal; 214 case MSIFIELD_WSTR: 215 if( string2intW( rec->fields[iField].u.szwVal, &ret ) ) 216 return ret; 217 return MININT_PTR; 218 default: 219 break; 220 } 221 222 return MININT_PTR; 223 } 224 225 int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField) 226 { 227 int ret = 0; 228 229 TRACE("%p %d\n", rec, iField ); 230 231 if( iField > rec->count ) 232 return MSI_NULL_INTEGER; 233 234 switch( rec->fields[iField].type ) 235 { 236 case MSIFIELD_INT: 237 return rec->fields[iField].u.iVal; 238 case MSIFIELD_INTPTR: 239 return rec->fields[iField].u.pVal; 240 case MSIFIELD_WSTR: 241 if( string2intW( rec->fields[iField].u.szwVal, &ret ) ) 242 return ret; 243 return MSI_NULL_INTEGER; 244 default: 245 break; 246 } 247 248 return MSI_NULL_INTEGER; 249 } 250 251 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField) 252 { 253 MSIRECORD *rec; 254 UINT ret; 255 256 TRACE("%d %d\n", handle, iField ); 257 258 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 259 if( !rec ) 260 return MSI_NULL_INTEGER; 261 262 msiobj_lock( &rec->hdr ); 263 ret = MSI_RecordGetInteger( rec, iField ); 264 msiobj_unlock( &rec->hdr ); 265 msiobj_release( &rec->hdr ); 266 267 return ret; 268 } 269 270 UINT WINAPI MsiRecordClearData( MSIHANDLE handle ) 271 { 272 MSIRECORD *rec; 273 UINT i; 274 275 TRACE("%d\n", handle ); 276 277 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 278 if( !rec ) 279 return ERROR_INVALID_HANDLE; 280 281 msiobj_lock( &rec->hdr ); 282 for( i=0; i<=rec->count; i++) 283 { 284 MSI_FreeField( &rec->fields[i] ); 285 rec->fields[i].type = MSIFIELD_NULL; 286 rec->fields[i].u.iVal = 0; 287 } 288 msiobj_unlock( &rec->hdr ); 289 msiobj_release( &rec->hdr ); 290 291 return ERROR_SUCCESS; 292 } 293 294 UINT MSI_RecordSetIntPtr( MSIRECORD *rec, UINT iField, INT_PTR pVal ) 295 { 296 TRACE("%p %u %ld\n", rec, iField, pVal); 297 298 if( iField > rec->count ) 299 return ERROR_INVALID_PARAMETER; 300 301 MSI_FreeField( &rec->fields[iField] ); 302 rec->fields[iField].type = MSIFIELD_INTPTR; 303 rec->fields[iField].u.pVal = pVal; 304 305 return ERROR_SUCCESS; 306 } 307 308 UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal ) 309 { 310 TRACE("%p %u %d\n", rec, iField, iVal); 311 312 if( iField > rec->count ) 313 return ERROR_INVALID_PARAMETER; 314 315 MSI_FreeField( &rec->fields[iField] ); 316 317 if (iVal == MSI_NULL_INTEGER) 318 { 319 rec->fields[iField].type = MSIFIELD_NULL; 320 rec->fields[iField].u.szwVal = NULL; 321 } 322 else 323 { 324 rec->fields[iField].type = MSIFIELD_INT; 325 rec->fields[iField].u.iVal = iVal; 326 } 327 328 return ERROR_SUCCESS; 329 } 330 331 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal ) 332 { 333 MSIRECORD *rec; 334 UINT ret; 335 336 TRACE("%d %u %d\n", handle, iField, iVal); 337 338 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 339 if( !rec ) 340 return ERROR_INVALID_HANDLE; 341 342 msiobj_lock( &rec->hdr ); 343 ret = MSI_RecordSetInteger( rec, iField, iVal ); 344 msiobj_unlock( &rec->hdr ); 345 msiobj_release( &rec->hdr ); 346 return ret; 347 } 348 349 BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField ) 350 { 351 BOOL r = TRUE; 352 353 TRACE("%p %d\n", rec, iField ); 354 355 r = ( iField > rec->count ) || 356 ( rec->fields[iField].type == MSIFIELD_NULL ); 357 358 return r; 359 } 360 361 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField ) 362 { 363 MSIRECORD *rec; 364 UINT ret; 365 366 TRACE("%d %d\n", handle, iField ); 367 368 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 369 if( !rec ) 370 return FALSE; 371 msiobj_lock( &rec->hdr ); 372 ret = MSI_RecordIsNull( rec, iField ); 373 msiobj_unlock( &rec->hdr ); 374 msiobj_release( &rec->hdr ); 375 return ret; 376 377 } 378 379 UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField, 380 LPSTR szValue, LPDWORD pcchValue) 381 { 382 UINT len = 0, ret = ERROR_SUCCESS; 383 CHAR buffer[16]; 384 385 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue); 386 387 if( iField > rec->count ) 388 { 389 if ( szValue && *pcchValue > 0 ) 390 szValue[0] = 0; 391 392 *pcchValue = 0; 393 return ERROR_SUCCESS; 394 } 395 396 switch( rec->fields[iField].type ) 397 { 398 case MSIFIELD_INT: 399 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal); 400 len = lstrlenA( buffer ); 401 if (szValue) 402 lstrcpynA(szValue, buffer, *pcchValue); 403 break; 404 case MSIFIELD_WSTR: 405 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, 406 rec->fields[iField].len + 1, NULL, 0 , NULL, NULL ); 407 if (szValue) 408 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, 409 rec->fields[iField].len + 1, szValue, *pcchValue, NULL, NULL ); 410 if( szValue && *pcchValue && len>*pcchValue ) 411 szValue[*pcchValue-1] = 0; 412 if( len ) 413 len--; 414 break; 415 case MSIFIELD_NULL: 416 if( szValue && *pcchValue > 0 ) 417 szValue[0] = 0; 418 break; 419 default: 420 ret = ERROR_INVALID_PARAMETER; 421 break; 422 } 423 424 if( szValue && *pcchValue <= len ) 425 ret = ERROR_MORE_DATA; 426 *pcchValue = len; 427 428 return ret; 429 } 430 431 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, UINT iField, 432 LPSTR szValue, LPDWORD pcchValue) 433 { 434 MSIRECORD *rec; 435 UINT ret; 436 437 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue); 438 439 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 440 if( !rec ) 441 return ERROR_INVALID_HANDLE; 442 msiobj_lock( &rec->hdr ); 443 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue); 444 msiobj_unlock( &rec->hdr ); 445 msiobj_release( &rec->hdr ); 446 return ret; 447 } 448 449 const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len ) 450 { 451 if (field > rec->count) 452 return NULL; 453 454 if (rec->fields[field].type != MSIFIELD_WSTR) 455 return NULL; 456 457 if (len) *len = rec->fields[field].len; 458 459 return rec->fields[field].u.szwVal; 460 } 461 462 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField ) 463 { 464 return msi_record_get_string( rec, iField, NULL ); 465 } 466 467 UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField, 468 LPWSTR szValue, LPDWORD pcchValue) 469 { 470 static const WCHAR szFormat[] = {'%','d',0}; 471 UINT len = 0, ret = ERROR_SUCCESS; 472 WCHAR buffer[16]; 473 474 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue); 475 476 if( iField > rec->count ) 477 { 478 if ( szValue && *pcchValue > 0 ) 479 szValue[0] = 0; 480 481 *pcchValue = 0; 482 return ERROR_SUCCESS; 483 } 484 485 switch( rec->fields[iField].type ) 486 { 487 case MSIFIELD_INT: 488 wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal); 489 len = lstrlenW( buffer ); 490 if (szValue) 491 lstrcpynW(szValue, buffer, *pcchValue); 492 break; 493 case MSIFIELD_WSTR: 494 len = rec->fields[iField].len; 495 if (szValue) 496 memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) ); 497 break; 498 case MSIFIELD_NULL: 499 if( szValue && *pcchValue > 0 ) 500 szValue[0] = 0; 501 break; 502 default: 503 break; 504 } 505 506 if( szValue && *pcchValue <= len ) 507 ret = ERROR_MORE_DATA; 508 *pcchValue = len; 509 510 return ret; 511 } 512 513 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField, 514 LPWSTR szValue, LPDWORD pcchValue) 515 { 516 MSIRECORD *rec; 517 UINT ret; 518 519 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue); 520 521 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 522 if( !rec ) 523 return ERROR_INVALID_HANDLE; 524 525 msiobj_lock( &rec->hdr ); 526 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue ); 527 msiobj_unlock( &rec->hdr ); 528 msiobj_release( &rec->hdr ); 529 return ret; 530 } 531 532 static UINT msi_get_stream_size( IStream *stm ) 533 { 534 STATSTG stat; 535 HRESULT r; 536 537 r = IStream_Stat( stm, &stat, STATFLAG_NONAME ); 538 if( FAILED(r) ) 539 return 0; 540 return stat.cbSize.QuadPart; 541 } 542 543 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField) 544 { 545 TRACE("%p %d\n", rec, iField); 546 547 if( iField > rec->count ) 548 return 0; 549 550 switch( rec->fields[iField].type ) 551 { 552 case MSIFIELD_INT: 553 return sizeof (INT); 554 case MSIFIELD_WSTR: 555 return rec->fields[iField].len; 556 case MSIFIELD_NULL: 557 break; 558 case MSIFIELD_STREAM: 559 return msi_get_stream_size( rec->fields[iField].u.stream ); 560 } 561 return 0; 562 } 563 564 UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField) 565 { 566 MSIRECORD *rec; 567 UINT ret; 568 569 TRACE("%d %d\n", handle, iField); 570 571 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 572 if( !rec ) 573 return 0; 574 msiobj_lock( &rec->hdr ); 575 ret = MSI_RecordDataSize( rec, iField); 576 msiobj_unlock( &rec->hdr ); 577 msiobj_release( &rec->hdr ); 578 return ret; 579 } 580 581 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue ) 582 { 583 WCHAR *valueW = NULL; 584 MSIRECORD *rec; 585 UINT ret; 586 587 TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue)); 588 589 if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY; 590 591 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 592 if( !rec ) 593 { 594 msi_free( valueW ); 595 return ERROR_INVALID_HANDLE; 596 } 597 msiobj_lock( &rec->hdr ); 598 ret = MSI_RecordSetStringW( rec, iField, valueW ); 599 msiobj_unlock( &rec->hdr ); 600 msiobj_release( &rec->hdr ); 601 msi_free( valueW ); 602 return ret; 603 } 604 605 UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len ) 606 { 607 if (field > rec->count) 608 return ERROR_INVALID_FIELD; 609 610 MSI_FreeField( &rec->fields[field] ); 611 612 if (value && len < 0) len = strlenW( value ); 613 614 if (value && len) 615 { 616 rec->fields[field].type = MSIFIELD_WSTR; 617 rec->fields[field].u.szwVal = msi_strdupW( value, len ); 618 rec->fields[field].len = len; 619 } 620 else 621 { 622 rec->fields[field].type = MSIFIELD_NULL; 623 rec->fields[field].u.szwVal = NULL; 624 rec->fields[field].len = 0; 625 } 626 return 0; 627 } 628 629 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue ) 630 { 631 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue)); 632 633 return msi_record_set_string( rec, iField, szValue, -1 ); 634 } 635 636 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue ) 637 { 638 MSIRECORD *rec; 639 UINT ret; 640 641 TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue)); 642 643 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 644 if( !rec ) 645 return ERROR_INVALID_HANDLE; 646 647 msiobj_lock( &rec->hdr ); 648 ret = MSI_RecordSetStringW( rec, iField, szValue ); 649 msiobj_unlock( &rec->hdr ); 650 msiobj_release( &rec->hdr ); 651 return ret; 652 } 653 654 /* read the data in a file into an IStream */ 655 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) 656 { 657 DWORD sz, szHighWord = 0, read; 658 HANDLE handle; 659 HGLOBAL hGlob = 0; 660 HRESULT hr; 661 ULARGE_INTEGER ulSize; 662 663 TRACE("reading %s\n", debugstr_w(szFile)); 664 665 /* read the file into memory */ 666 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 667 if( handle == INVALID_HANDLE_VALUE ) 668 return GetLastError(); 669 sz = GetFileSize(handle, &szHighWord); 670 if( sz != INVALID_FILE_SIZE && szHighWord == 0 ) 671 { 672 hGlob = GlobalAlloc(GMEM_FIXED, sz); 673 if( hGlob ) 674 { 675 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz; 676 if( !r ) 677 { 678 GlobalFree(hGlob); 679 hGlob = 0; 680 } 681 } 682 } 683 CloseHandle(handle); 684 if( !hGlob ) 685 return ERROR_FUNCTION_FAILED; 686 687 /* make a stream out of it, and set the correct file size */ 688 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm); 689 if( FAILED( hr ) ) 690 { 691 GlobalFree(hGlob); 692 return ERROR_FUNCTION_FAILED; 693 } 694 695 /* set the correct size - CreateStreamOnHGlobal screws it up */ 696 ulSize.QuadPart = sz; 697 IStream_SetSize(*pstm, ulSize); 698 699 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm); 700 701 return ERROR_SUCCESS; 702 } 703 704 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream) 705 { 706 if ( (iField == 0) || (iField > rec->count) ) 707 return ERROR_INVALID_PARAMETER; 708 709 MSI_FreeField( &rec->fields[iField] ); 710 rec->fields[iField].type = MSIFIELD_STREAM; 711 rec->fields[iField].u.stream = stream; 712 713 return ERROR_SUCCESS; 714 } 715 716 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename) 717 { 718 IStream *stm = NULL; 719 HRESULT hr; 720 UINT ret; 721 722 if( (iField == 0) || (iField > rec->count) ) 723 return ERROR_INVALID_PARAMETER; 724 725 /* no filename means we should seek back to the start of the stream */ 726 if( !szFilename ) 727 { 728 LARGE_INTEGER ofs; 729 ULARGE_INTEGER cur; 730 731 if( rec->fields[iField].type != MSIFIELD_STREAM ) 732 return ERROR_INVALID_FIELD; 733 734 stm = rec->fields[iField].u.stream; 735 if( !stm ) 736 return ERROR_INVALID_FIELD; 737 738 ofs.QuadPart = 0; 739 hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); 740 if (FAILED( hr )) 741 return ERROR_FUNCTION_FAILED; 742 } 743 else 744 { 745 /* read the file into a stream and save the stream in the record */ 746 ret = RECORD_StreamFromFile(szFilename, &stm); 747 if (ret != ERROR_SUCCESS) 748 return ret; 749 750 /* if all's good, store it in the record */ 751 MSI_RecordSetStream(rec, iField, stm); 752 } 753 754 return ERROR_SUCCESS; 755 } 756 757 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename) 758 { 759 LPWSTR wstr = NULL; 760 UINT ret; 761 762 TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename)); 763 764 if( szFilename ) 765 { 766 wstr = strdupAtoW( szFilename ); 767 if( !wstr ) 768 return ERROR_OUTOFMEMORY; 769 } 770 ret = MsiRecordSetStreamW(hRecord, iField, wstr); 771 msi_free(wstr); 772 773 return ret; 774 } 775 776 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename) 777 { 778 MSIRECORD *rec; 779 UINT ret; 780 781 TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename)); 782 783 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 784 if( !rec ) 785 return ERROR_INVALID_HANDLE; 786 787 msiobj_lock( &rec->hdr ); 788 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename ); 789 msiobj_unlock( &rec->hdr ); 790 msiobj_release( &rec->hdr ); 791 return ret; 792 } 793 794 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz) 795 { 796 ULONG count; 797 HRESULT r; 798 IStream *stm; 799 800 TRACE("%p %d %p %p\n", rec, iField, buf, sz); 801 802 if( !sz ) 803 return ERROR_INVALID_PARAMETER; 804 805 if( iField > rec->count) 806 return ERROR_INVALID_PARAMETER; 807 808 if ( rec->fields[iField].type == MSIFIELD_NULL ) 809 { 810 *sz = 0; 811 return ERROR_INVALID_DATA; 812 } 813 814 if( rec->fields[iField].type != MSIFIELD_STREAM ) 815 return ERROR_INVALID_DATATYPE; 816 817 stm = rec->fields[iField].u.stream; 818 if( !stm ) 819 return ERROR_INVALID_PARAMETER; 820 821 /* if there's no buffer pointer, calculate the length to the end */ 822 if( !buf ) 823 { 824 LARGE_INTEGER ofs; 825 ULARGE_INTEGER end, cur; 826 827 ofs.QuadPart = cur.QuadPart = 0; 828 end.QuadPart = 0; 829 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); 830 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end ); 831 ofs.QuadPart = cur.QuadPart; 832 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); 833 *sz = end.QuadPart - cur.QuadPart; 834 835 return ERROR_SUCCESS; 836 } 837 838 /* read the data */ 839 count = 0; 840 r = IStream_Read( stm, buf, *sz, &count ); 841 if( FAILED( r ) ) 842 { 843 *sz = 0; 844 return ERROR_FUNCTION_FAILED; 845 } 846 847 *sz = count; 848 849 return ERROR_SUCCESS; 850 } 851 852 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz) 853 { 854 MSIRECORD *rec; 855 UINT ret; 856 857 TRACE("%d %d %p %p\n", handle, iField, buf, sz); 858 859 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); 860 if( !rec ) 861 return ERROR_INVALID_HANDLE; 862 msiobj_lock( &rec->hdr ); 863 ret = MSI_RecordReadStream( rec, iField, buf, sz ); 864 msiobj_unlock( &rec->hdr ); 865 msiobj_release( &rec->hdr ); 866 return ret; 867 } 868 869 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm ) 870 { 871 TRACE("%p %d %p\n", rec, iField, stm); 872 873 if( iField > rec->count ) 874 return ERROR_INVALID_FIELD; 875 876 MSI_FreeField( &rec->fields[iField] ); 877 878 rec->fields[iField].type = MSIFIELD_STREAM; 879 rec->fields[iField].u.stream = stm; 880 IStream_AddRef( stm ); 881 882 return ERROR_SUCCESS; 883 } 884 885 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm) 886 { 887 TRACE("%p %d %p\n", rec, iField, pstm); 888 889 if( iField > rec->count ) 890 return ERROR_INVALID_FIELD; 891 892 if( rec->fields[iField].type != MSIFIELD_STREAM ) 893 return ERROR_INVALID_FIELD; 894 895 *pstm = rec->fields[iField].u.stream; 896 IStream_AddRef( *pstm ); 897 898 return ERROR_SUCCESS; 899 } 900 901 static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name ) 902 { 903 ULARGE_INTEGER size; 904 LARGE_INTEGER pos; 905 IStream *out; 906 DWORD stgm; 907 HRESULT r; 908 909 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE; 910 r = SHCreateStreamOnFileW( name, stgm, &out ); 911 if( FAILED( r ) ) 912 return ERROR_FUNCTION_FAILED; 913 914 pos.QuadPart = 0; 915 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size ); 916 if( FAILED( r ) ) 917 goto end; 918 919 pos.QuadPart = 0; 920 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL ); 921 if( FAILED( r ) ) 922 goto end; 923 924 r = IStream_CopyTo( stm, out, size, NULL, NULL ); 925 926 end: 927 IStream_Release( out ); 928 if( FAILED( r ) ) 929 return ERROR_FUNCTION_FAILED; 930 return ERROR_SUCCESS; 931 } 932 933 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name ) 934 { 935 IStream *stm = NULL; 936 UINT r; 937 938 TRACE("%p %u %s\n", rec, iField, debugstr_w(name)); 939 940 msiobj_lock( &rec->hdr ); 941 942 r = MSI_RecordGetIStream( rec, iField, &stm ); 943 if( r == ERROR_SUCCESS ) 944 { 945 r = msi_dump_stream_to_file( stm, name ); 946 IStream_Release( stm ); 947 } 948 949 msiobj_unlock( &rec->hdr ); 950 951 return r; 952 } 953 954 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec) 955 { 956 MSIRECORD *clone; 957 UINT r, i, count; 958 959 count = MSI_RecordGetFieldCount(rec); 960 clone = MSI_CreateRecord(count); 961 if (!clone) 962 return NULL; 963 964 for (i = 0; i <= count; i++) 965 { 966 if (rec->fields[i].type == MSIFIELD_STREAM) 967 { 968 if (FAILED(IStream_Clone(rec->fields[i].u.stream, 969 &clone->fields[i].u.stream))) 970 { 971 msiobj_release(&clone->hdr); 972 return NULL; 973 } 974 clone->fields[i].type = MSIFIELD_STREAM; 975 } 976 else 977 { 978 r = MSI_RecordCopyField(rec, i, clone, i); 979 if (r != ERROR_SUCCESS) 980 { 981 msiobj_release(&clone->hdr); 982 return NULL; 983 } 984 } 985 } 986 987 return clone; 988 } 989 990 BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field) 991 { 992 if (a->fields[field].type != b->fields[field].type) 993 return FALSE; 994 995 switch (a->fields[field].type) 996 { 997 case MSIFIELD_NULL: 998 break; 999 1000 case MSIFIELD_INT: 1001 if (a->fields[field].u.iVal != b->fields[field].u.iVal) 1002 return FALSE; 1003 break; 1004 1005 case MSIFIELD_WSTR: 1006 if (a->fields[field].len != b->fields[field].len) return FALSE; 1007 if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal, 1008 a->fields[field].len * sizeof(WCHAR) )) return FALSE; 1009 break; 1010 1011 case MSIFIELD_STREAM: 1012 default: 1013 return FALSE; 1014 } 1015 return TRUE; 1016 } 1017 1018 1019 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b) 1020 { 1021 UINT i; 1022 1023 if (a->count != b->count) 1024 return FALSE; 1025 1026 for (i = 0; i <= a->count; i++) 1027 { 1028 if (!MSI_RecordsAreFieldsEqual( a, b, i )) 1029 return FALSE; 1030 } 1031 1032 return TRUE; 1033 } 1034 1035 WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field ) 1036 { 1037 DWORD sz = 0; 1038 WCHAR *str; 1039 UINT r; 1040 1041 if (MSI_RecordIsNull( rec, field )) return NULL; 1042 1043 r = MSI_RecordGetStringW( rec, field, NULL, &sz ); 1044 if (r != ERROR_SUCCESS) 1045 return NULL; 1046 1047 sz++; 1048 str = msi_alloc( sz * sizeof(WCHAR) ); 1049 if (!str) return NULL; 1050 str[0] = 0; 1051 r = MSI_RecordGetStringW( rec, field, str, &sz ); 1052 if (r != ERROR_SUCCESS) 1053 { 1054 ERR("failed to get string!\n"); 1055 msi_free( str ); 1056 return NULL; 1057 } 1058 return str; 1059 } 1060 1061 void dump_record(MSIRECORD *rec) 1062 { 1063 int i; 1064 if (!rec) 1065 { 1066 TRACE("(null)\n"); 1067 return; 1068 } 1069 1070 TRACE("["); 1071 for (i = 0; i <= rec->count; i++) 1072 { 1073 switch(rec->fields[i].type) 1074 { 1075 case MSIFIELD_NULL: TRACE("(null)"); break; 1076 case MSIFIELD_INT: TRACE("%d", rec->fields[i].u.iVal); break; 1077 case MSIFIELD_WSTR: TRACE("%s", debugstr_w(rec->fields[i].u.szwVal)); break; 1078 case MSIFIELD_INTPTR: TRACE("%ld", rec->fields[i].u.pVal); break; 1079 case MSIFIELD_STREAM: TRACE("%p", rec->fields[i].u.stream); break; 1080 } 1081 if (i < rec->count) TRACE(", "); 1082 } 1083 TRACE("]\n"); 1084 } 1085