1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2002-2005 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 <stdarg.h> 22 #include <assert.h> 23 24 #define COBJMACROS 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "winerror.h" 29 #include "msi.h" 30 #include "msiquery.h" 31 #include "objbase.h" 32 #include "objidl.h" 33 #include "winnls.h" 34 #include "msipriv.h" 35 #include "query.h" 36 37 #include "wine/debug.h" 38 #include "wine/unicode.h" 39 40 WINE_DEFAULT_DEBUG_CHANNEL(msidb); 41 42 #define MSITABLE_HASH_TABLE_SIZE 37 43 44 typedef struct tagMSICOLUMNHASHENTRY 45 { 46 struct tagMSICOLUMNHASHENTRY *next; 47 UINT value; 48 UINT row; 49 } MSICOLUMNHASHENTRY; 50 51 typedef struct tagMSICOLUMNINFO 52 { 53 LPCWSTR tablename; 54 UINT number; 55 LPCWSTR colname; 56 UINT type; 57 UINT offset; 58 INT ref_count; 59 BOOL temporary; 60 MSICOLUMNHASHENTRY **hash_table; 61 } MSICOLUMNINFO; 62 63 struct tagMSITABLE 64 { 65 BYTE **data; 66 BOOL *data_persistent; 67 UINT row_count; 68 struct list entry; 69 MSICOLUMNINFO *colinfo; 70 UINT col_count; 71 MSICONDITION persistent; 72 INT ref_count; 73 WCHAR name[1]; 74 }; 75 76 /* information for default tables */ 77 static const WCHAR szTables[] = {'_','T','a','b','l','e','s',0}; 78 static const WCHAR szTable[] = {'T','a','b','l','e',0}; 79 static const WCHAR szColumns[] = {'_','C','o','l','u','m','n','s',0}; 80 static const WCHAR szNumber[] = {'N','u','m','b','e','r',0}; 81 static const WCHAR szType[] = {'T','y','p','e',0}; 82 83 static const MSICOLUMNINFO _Columns_cols[4] = { 84 { szColumns, 1, szTable, MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, 0, NULL }, 85 { szColumns, 2, szNumber, MSITYPE_VALID | MSITYPE_KEY | 2, 2, 0, 0, NULL }, 86 { szColumns, 3, szName, MSITYPE_VALID | MSITYPE_STRING | 64, 4, 0, 0, NULL }, 87 { szColumns, 4, szType, MSITYPE_VALID | 2, 6, 0, 0, NULL }, 88 }; 89 90 static const MSICOLUMNINFO _Tables_cols[1] = { 91 { szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, 0, NULL }, 92 }; 93 94 #define MAX_STREAM_NAME 0x1f 95 96 static inline UINT bytes_per_column( MSIDATABASE *db, const MSICOLUMNINFO *col, UINT bytes_per_strref ) 97 { 98 if( MSITYPE_IS_BINARY(col->type) ) 99 return 2; 100 101 if( col->type & MSITYPE_STRING ) 102 return bytes_per_strref; 103 104 if( (col->type & 0xff) <= 2) 105 return 2; 106 107 if( (col->type & 0xff) != 4 ) 108 ERR("Invalid column size %u\n", col->type & 0xff); 109 110 return 4; 111 } 112 113 static int utf2mime(int x) 114 { 115 if( (x>='0') && (x<='9') ) 116 return x-'0'; 117 if( (x>='A') && (x<='Z') ) 118 return x-'A'+10; 119 if( (x>='a') && (x<='z') ) 120 return x-'a'+10+26; 121 if( x=='.' ) 122 return 10+26+26; 123 if( x=='_' ) 124 return 10+26+26+1; 125 return -1; 126 } 127 128 LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) 129 { 130 DWORD count = MAX_STREAM_NAME; 131 DWORD ch, next; 132 LPWSTR out, p; 133 134 if( !bTable ) 135 count = lstrlenW( in )+2; 136 if (!(out = msi_alloc( count*sizeof(WCHAR) ))) return NULL; 137 p = out; 138 139 if( bTable ) 140 { 141 *p++ = 0x4840; 142 count --; 143 } 144 while( count -- ) 145 { 146 ch = *in++; 147 if( !ch ) 148 { 149 *p = ch; 150 return out; 151 } 152 if( ( ch < 0x80 ) && ( utf2mime(ch) >= 0 ) ) 153 { 154 ch = utf2mime(ch) + 0x4800; 155 next = *in; 156 if( next && (next<0x80) ) 157 { 158 next = utf2mime(next); 159 if( next != -1 ) 160 { 161 next += 0x3ffffc0; 162 ch += (next<<6); 163 in++; 164 } 165 } 166 } 167 *p++ = ch; 168 } 169 ERR("Failed to encode stream name (%s)\n",debugstr_w(in)); 170 msi_free( out ); 171 return NULL; 172 } 173 174 static int mime2utf(int x) 175 { 176 if( x<10 ) 177 return x + '0'; 178 if( x<(10+26)) 179 return x - 10 + 'A'; 180 if( x<(10+26+26)) 181 return x - 10 - 26 + 'a'; 182 if( x == (10+26+26) ) 183 return '.'; 184 return '_'; 185 } 186 187 BOOL decode_streamname(LPCWSTR in, LPWSTR out) 188 { 189 WCHAR ch; 190 DWORD count = 0; 191 192 while ( (ch = *in++) ) 193 { 194 if( (ch >= 0x3800 ) && (ch < 0x4840 ) ) 195 { 196 if( ch >= 0x4800 ) 197 ch = mime2utf(ch-0x4800); 198 else 199 { 200 ch -= 0x3800; 201 *out++ = mime2utf(ch&0x3f); 202 count++; 203 ch = mime2utf((ch>>6)&0x3f); 204 } 205 } 206 *out++ = ch; 207 count++; 208 } 209 *out = 0; 210 return count; 211 } 212 213 void enum_stream_names( IStorage *stg ) 214 { 215 IEnumSTATSTG *stgenum = NULL; 216 HRESULT r; 217 STATSTG stat; 218 ULONG n, count; 219 WCHAR name[0x40]; 220 221 r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum ); 222 if( FAILED( r ) ) 223 return; 224 225 n = 0; 226 while( 1 ) 227 { 228 count = 0; 229 r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count ); 230 if( FAILED( r ) || !count ) 231 break; 232 decode_streamname( stat.pwcsName, name ); 233 TRACE("stream %2d -> %s %s\n", n, 234 debugstr_w(stat.pwcsName), debugstr_w(name) ); 235 CoTaskMemFree( stat.pwcsName ); 236 n++; 237 } 238 239 IEnumSTATSTG_Release( stgenum ); 240 } 241 242 UINT read_stream_data( IStorage *stg, LPCWSTR stname, BOOL table, 243 BYTE **pdata, UINT *psz ) 244 { 245 HRESULT r; 246 UINT ret = ERROR_FUNCTION_FAILED; 247 VOID *data; 248 ULONG sz, count; 249 IStream *stm = NULL; 250 STATSTG stat; 251 LPWSTR encname; 252 253 encname = encode_streamname(table, stname); 254 255 TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname)); 256 257 r = IStorage_OpenStream(stg, encname, NULL, 258 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm); 259 msi_free( encname ); 260 if( FAILED( r ) ) 261 { 262 WARN("open stream failed r = %08x - empty table?\n", r); 263 return ret; 264 } 265 266 r = IStream_Stat(stm, &stat, STATFLAG_NONAME ); 267 if( FAILED( r ) ) 268 { 269 WARN("open stream failed r = %08x!\n", r); 270 goto end; 271 } 272 273 if( stat.cbSize.QuadPart >> 32 ) 274 { 275 WARN("Too big!\n"); 276 goto end; 277 } 278 279 sz = stat.cbSize.QuadPart; 280 data = msi_alloc( sz ); 281 if( !data ) 282 { 283 WARN("couldn't allocate memory r=%08x!\n", r); 284 ret = ERROR_NOT_ENOUGH_MEMORY; 285 goto end; 286 } 287 288 r = IStream_Read(stm, data, sz, &count ); 289 if( FAILED( r ) || ( count != sz ) ) 290 { 291 msi_free( data ); 292 WARN("read stream failed r = %08x!\n", r); 293 goto end; 294 } 295 296 *pdata = data; 297 *psz = sz; 298 ret = ERROR_SUCCESS; 299 300 end: 301 IStream_Release( stm ); 302 303 return ret; 304 } 305 306 UINT write_stream_data( IStorage *stg, LPCWSTR stname, 307 LPCVOID data, UINT sz, BOOL bTable ) 308 { 309 HRESULT r; 310 UINT ret = ERROR_FUNCTION_FAILED; 311 ULONG count; 312 IStream *stm = NULL; 313 ULARGE_INTEGER size; 314 LARGE_INTEGER pos; 315 LPWSTR encname; 316 317 encname = encode_streamname(bTable, stname ); 318 r = IStorage_OpenStream( stg, encname, NULL, 319 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm); 320 if( FAILED(r) ) 321 { 322 r = IStorage_CreateStream( stg, encname, 323 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); 324 } 325 msi_free( encname ); 326 if( FAILED( r ) ) 327 { 328 WARN("open stream failed r = %08x\n", r); 329 return ret; 330 } 331 332 size.QuadPart = sz; 333 r = IStream_SetSize( stm, size ); 334 if( FAILED( r ) ) 335 { 336 WARN("Failed to SetSize\n"); 337 goto end; 338 } 339 340 pos.QuadPart = 0; 341 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL ); 342 if( FAILED( r ) ) 343 { 344 WARN("Failed to Seek\n"); 345 goto end; 346 } 347 348 if (sz) 349 { 350 r = IStream_Write(stm, data, sz, &count ); 351 if( FAILED( r ) || ( count != sz ) ) 352 { 353 WARN("Failed to Write\n"); 354 goto end; 355 } 356 } 357 358 ret = ERROR_SUCCESS; 359 360 end: 361 IStream_Release( stm ); 362 363 return ret; 364 } 365 366 static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count ) 367 { 368 UINT i; 369 for (i = 0; i < count; i++) msi_free( colinfo[i].hash_table ); 370 } 371 372 static void free_table( MSITABLE *table ) 373 { 374 UINT i; 375 for( i=0; i<table->row_count; i++ ) 376 msi_free( table->data[i] ); 377 msi_free( table->data ); 378 msi_free( table->data_persistent ); 379 msi_free_colinfo( table->colinfo, table->col_count ); 380 msi_free( table->colinfo ); 381 msi_free( table ); 382 } 383 384 static UINT msi_table_get_row_size( MSIDATABASE *db, const MSICOLUMNINFO *cols, UINT count, UINT bytes_per_strref ) 385 { 386 const MSICOLUMNINFO *last_col; 387 388 if (!count) 389 return 0; 390 391 if (bytes_per_strref != LONG_STR_BYTES) 392 { 393 UINT i, size = 0; 394 for (i = 0; i < count; i++) size += bytes_per_column( db, &cols[i], bytes_per_strref ); 395 return size; 396 } 397 last_col = &cols[count - 1]; 398 return last_col->offset + bytes_per_column( db, last_col, bytes_per_strref ); 399 } 400 401 /* add this table to the list of cached tables in the database */ 402 static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg ) 403 { 404 BYTE *rawdata = NULL; 405 UINT rawsize = 0, i, j, row_size, row_size_mem; 406 407 TRACE("%s\n",debugstr_w(t->name)); 408 409 row_size = msi_table_get_row_size( db, t->colinfo, t->col_count, db->bytes_per_strref ); 410 row_size_mem = msi_table_get_row_size( db, t->colinfo, t->col_count, LONG_STR_BYTES ); 411 412 /* if we can't read the table, just assume that it's empty */ 413 read_stream_data( stg, t->name, TRUE, &rawdata, &rawsize ); 414 if( !rawdata ) 415 return ERROR_SUCCESS; 416 417 TRACE("Read %d bytes\n", rawsize ); 418 419 if( rawsize % row_size ) 420 { 421 WARN("Table size is invalid %d/%d\n", rawsize, row_size ); 422 goto err; 423 } 424 425 if ((t->row_count = rawsize / row_size)) 426 { 427 if (!(t->data = msi_alloc_zero( t->row_count * sizeof(USHORT *) ))) goto err; 428 if (!(t->data_persistent = msi_alloc_zero( t->row_count * sizeof(BOOL) ))) goto err; 429 } 430 431 /* transpose all the data */ 432 TRACE("Transposing data from %d rows\n", t->row_count ); 433 for (i = 0; i < t->row_count; i++) 434 { 435 UINT ofs = 0, ofs_mem = 0; 436 437 t->data[i] = msi_alloc( row_size_mem ); 438 if( !t->data[i] ) 439 goto err; 440 t->data_persistent[i] = TRUE; 441 442 for (j = 0; j < t->col_count; j++) 443 { 444 UINT m = bytes_per_column( db, &t->colinfo[j], LONG_STR_BYTES ); 445 UINT n = bytes_per_column( db, &t->colinfo[j], db->bytes_per_strref ); 446 UINT k; 447 448 if ( n != 2 && n != 3 && n != 4 ) 449 { 450 ERR("oops - unknown column width %d\n", n); 451 goto err; 452 } 453 if (t->colinfo[j].type & MSITYPE_STRING && n < m) 454 { 455 for (k = 0; k < m; k++) 456 { 457 if (k < n) 458 t->data[i][ofs_mem + k] = rawdata[ofs * t->row_count + i * n + k]; 459 else 460 t->data[i][ofs_mem + k] = 0; 461 } 462 } 463 else 464 { 465 for (k = 0; k < n; k++) 466 t->data[i][ofs_mem + k] = rawdata[ofs * t->row_count + i * n + k]; 467 } 468 ofs_mem += m; 469 ofs += n; 470 } 471 } 472 473 msi_free( rawdata ); 474 return ERROR_SUCCESS; 475 err: 476 msi_free( rawdata ); 477 return ERROR_FUNCTION_FAILED; 478 } 479 480 void free_cached_tables( MSIDATABASE *db ) 481 { 482 while( !list_empty( &db->tables ) ) 483 { 484 MSITABLE *t = LIST_ENTRY( list_head( &db->tables ), MSITABLE, entry ); 485 486 list_remove( &t->entry ); 487 free_table( t ); 488 } 489 } 490 491 static MSITABLE *find_cached_table( MSIDATABASE *db, LPCWSTR name ) 492 { 493 MSITABLE *t; 494 495 LIST_FOR_EACH_ENTRY( t, &db->tables, MSITABLE, entry ) 496 if( !strcmpW( name, t->name ) ) 497 return t; 498 499 return NULL; 500 } 501 502 static void table_calc_column_offsets( MSIDATABASE *db, MSICOLUMNINFO *colinfo, DWORD count ) 503 { 504 DWORD i; 505 506 for (i = 0; colinfo && i < count; i++) 507 { 508 assert( i + 1 == colinfo[i].number ); 509 if (i) colinfo[i].offset = colinfo[i - 1].offset + 510 bytes_per_column( db, &colinfo[i - 1], LONG_STR_BYTES ); 511 else colinfo[i].offset = 0; 512 513 TRACE("column %d is [%s] with type %08x ofs %d\n", 514 colinfo[i].number, debugstr_w(colinfo[i].colname), 515 colinfo[i].type, colinfo[i].offset); 516 } 517 } 518 519 static UINT get_defaulttablecolumns( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz ) 520 { 521 const MSICOLUMNINFO *p; 522 DWORD i, n; 523 524 TRACE("%s\n", debugstr_w(name)); 525 526 if (!strcmpW( name, szTables )) 527 { 528 p = _Tables_cols; 529 n = 1; 530 } 531 else if (!strcmpW( name, szColumns )) 532 { 533 p = _Columns_cols; 534 n = 4; 535 } 536 else return ERROR_FUNCTION_FAILED; 537 538 for (i = 0; i < n; i++) 539 { 540 if (colinfo && i < *sz) colinfo[i] = p[i]; 541 if (colinfo && i >= *sz) break; 542 } 543 table_calc_column_offsets( db, colinfo, n ); 544 *sz = n; 545 return ERROR_SUCCESS; 546 } 547 548 static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz ); 549 550 static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount ) 551 { 552 UINT r, column_count = 0; 553 MSICOLUMNINFO *columns; 554 555 /* get the number of columns in this table */ 556 column_count = 0; 557 r = get_tablecolumns( db, name, NULL, &column_count ); 558 if (r != ERROR_SUCCESS) 559 return r; 560 561 *pcount = column_count; 562 563 /* if there are no columns, there's no table */ 564 if (!column_count) 565 return ERROR_INVALID_PARAMETER; 566 567 TRACE("table %s found\n", debugstr_w(name)); 568 569 columns = msi_alloc( column_count * sizeof(MSICOLUMNINFO) ); 570 if (!columns) 571 return ERROR_FUNCTION_FAILED; 572 573 r = get_tablecolumns( db, name, columns, &column_count ); 574 if (r != ERROR_SUCCESS) 575 { 576 msi_free( columns ); 577 return ERROR_FUNCTION_FAILED; 578 } 579 *pcols = columns; 580 return r; 581 } 582 583 static UINT get_table( MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret ) 584 { 585 MSITABLE *table; 586 UINT r; 587 588 /* first, see if the table is cached */ 589 table = find_cached_table( db, name ); 590 if (table) 591 { 592 *table_ret = table; 593 return ERROR_SUCCESS; 594 } 595 596 /* nonexistent tables should be interpreted as empty tables */ 597 table = msi_alloc( sizeof(MSITABLE) + lstrlenW( name ) * sizeof(WCHAR) ); 598 if (!table) 599 return ERROR_FUNCTION_FAILED; 600 601 table->row_count = 0; 602 table->data = NULL; 603 table->data_persistent = NULL; 604 table->colinfo = NULL; 605 table->col_count = 0; 606 table->persistent = MSICONDITION_TRUE; 607 lstrcpyW( table->name, name ); 608 609 if (!strcmpW( name, szTables ) || !strcmpW( name, szColumns )) 610 table->persistent = MSICONDITION_NONE; 611 612 r = table_get_column_info( db, name, &table->colinfo, &table->col_count ); 613 if (r != ERROR_SUCCESS) 614 { 615 free_table( table ); 616 return r; 617 } 618 r = read_table_from_storage( db, table, db->storage ); 619 if (r != ERROR_SUCCESS) 620 { 621 free_table( table ); 622 return r; 623 } 624 list_add_head( &db->tables, &table->entry ); 625 *table_ret = table; 626 return ERROR_SUCCESS; 627 } 628 629 static UINT read_table_int( BYTE *const *data, UINT row, UINT col, UINT bytes ) 630 { 631 UINT ret = 0, i; 632 633 for (i = 0; i < bytes; i++) 634 ret += data[row][col + i] << i * 8; 635 636 return ret; 637 } 638 639 static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz ) 640 { 641 UINT r, i, n = 0, table_id, count, maxcount = *sz; 642 MSITABLE *table = NULL; 643 644 TRACE("%s\n", debugstr_w(szTableName)); 645 646 /* first check if there is a default table with that name */ 647 r = get_defaulttablecolumns( db, szTableName, colinfo, sz ); 648 if (r == ERROR_SUCCESS && *sz) 649 return r; 650 651 r = get_table( db, szColumns, &table ); 652 if (r != ERROR_SUCCESS) 653 { 654 ERR("couldn't load _Columns table\n"); 655 return ERROR_FUNCTION_FAILED; 656 } 657 658 /* convert table and column names to IDs from the string table */ 659 r = msi_string2id( db->strings, szTableName, -1, &table_id ); 660 if (r != ERROR_SUCCESS) 661 { 662 WARN("Couldn't find id for %s\n", debugstr_w(szTableName)); 663 return r; 664 } 665 TRACE("Table id is %d, row count is %d\n", table_id, table->row_count); 666 667 /* Note: _Columns table doesn't have non-persistent data */ 668 669 /* if maxcount is non-zero, assume it's exactly right for this table */ 670 if (colinfo) memset( colinfo, 0, maxcount * sizeof(*colinfo) ); 671 count = table->row_count; 672 for (i = 0; i < count; i++) 673 { 674 if (read_table_int( table->data, i, 0, LONG_STR_BYTES) != table_id) continue; 675 if (colinfo) 676 { 677 UINT id = read_table_int( table->data, i, table->colinfo[2].offset, LONG_STR_BYTES ); 678 UINT col = read_table_int( table->data, i, table->colinfo[1].offset, sizeof(USHORT) ) - (1 << 15); 679 680 /* check the column number is in range */ 681 if (col < 1 || col > maxcount) 682 { 683 ERR("column %d out of range (maxcount: %d)\n", col, maxcount); 684 continue; 685 } 686 /* check if this column was already set */ 687 if (colinfo[col - 1].number) 688 { 689 ERR("duplicate column %d\n", col); 690 continue; 691 } 692 colinfo[col - 1].tablename = msi_string_lookup( db->strings, table_id, NULL ); 693 colinfo[col - 1].number = col; 694 colinfo[col - 1].colname = msi_string_lookup( db->strings, id, NULL ); 695 colinfo[col - 1].type = read_table_int( table->data, i, table->colinfo[3].offset, 696 sizeof(USHORT) ) - (1 << 15); 697 colinfo[col - 1].offset = 0; 698 colinfo[col - 1].ref_count = 0; 699 colinfo[col - 1].hash_table = NULL; 700 } 701 n++; 702 } 703 TRACE("%s has %d columns\n", debugstr_w(szTableName), n); 704 705 if (colinfo && n != maxcount) 706 { 707 ERR("missing column in table %s\n", debugstr_w(szTableName)); 708 msi_free_colinfo( colinfo, maxcount ); 709 return ERROR_FUNCTION_FAILED; 710 } 711 table_calc_column_offsets( db, colinfo, n ); 712 *sz = n; 713 return ERROR_SUCCESS; 714 } 715 716 UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info, 717 MSICONDITION persistent ) 718 { 719 enum StringPersistence string_persistence = (persistent) ? StringPersistent : StringNonPersistent; 720 UINT r, nField; 721 MSIVIEW *tv = NULL; 722 MSIRECORD *rec = NULL; 723 column_info *col; 724 MSITABLE *table; 725 UINT i; 726 727 /* only add tables that don't exist already */ 728 if( TABLE_Exists(db, name ) ) 729 { 730 WARN("table %s exists\n", debugstr_w(name)); 731 return ERROR_BAD_QUERY_SYNTAX; 732 } 733 734 table = msi_alloc( sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) ); 735 if( !table ) 736 return ERROR_FUNCTION_FAILED; 737 738 table->ref_count = 1; 739 table->row_count = 0; 740 table->data = NULL; 741 table->data_persistent = NULL; 742 table->colinfo = NULL; 743 table->col_count = 0; 744 table->persistent = persistent; 745 lstrcpyW( table->name, name ); 746 747 for( col = col_info; col; col = col->next ) 748 table->col_count++; 749 750 table->colinfo = msi_alloc( table->col_count * sizeof(MSICOLUMNINFO) ); 751 if (!table->colinfo) 752 { 753 free_table( table ); 754 return ERROR_FUNCTION_FAILED; 755 } 756 757 for( i = 0, col = col_info; col; i++, col = col->next ) 758 { 759 UINT table_id = msi_add_string( db->strings, col->table, -1, string_persistence ); 760 UINT col_id = msi_add_string( db->strings, col->column, -1, string_persistence ); 761 762 table->colinfo[ i ].tablename = msi_string_lookup( db->strings, table_id, NULL ); 763 table->colinfo[ i ].number = i + 1; 764 table->colinfo[ i ].colname = msi_string_lookup( db->strings, col_id, NULL ); 765 table->colinfo[ i ].type = col->type; 766 table->colinfo[ i ].offset = 0; 767 table->colinfo[ i ].ref_count = 0; 768 table->colinfo[ i ].hash_table = NULL; 769 table->colinfo[ i ].temporary = col->temporary; 770 } 771 table_calc_column_offsets( db, table->colinfo, table->col_count); 772 773 r = TABLE_CreateView( db, szTables, &tv ); 774 TRACE("CreateView returned %x\n", r); 775 if( r ) 776 { 777 free_table( table ); 778 return r; 779 } 780 781 r = tv->ops->execute( tv, 0 ); 782 TRACE("tv execute returned %x\n", r); 783 if( r ) 784 goto err; 785 786 rec = MSI_CreateRecord( 1 ); 787 if( !rec ) 788 goto err; 789 790 r = MSI_RecordSetStringW( rec, 1, name ); 791 if( r ) 792 goto err; 793 794 r = tv->ops->insert_row( tv, rec, -1, persistent == MSICONDITION_FALSE ); 795 TRACE("insert_row returned %x\n", r); 796 if( r ) 797 goto err; 798 799 tv->ops->delete( tv ); 800 tv = NULL; 801 802 msiobj_release( &rec->hdr ); 803 rec = NULL; 804 805 if( persistent != MSICONDITION_FALSE ) 806 { 807 /* add each column to the _Columns table */ 808 r = TABLE_CreateView( db, szColumns, &tv ); 809 if( r ) 810 goto err; 811 812 r = tv->ops->execute( tv, 0 ); 813 TRACE("tv execute returned %x\n", r); 814 if( r ) 815 goto err; 816 817 rec = MSI_CreateRecord( 4 ); 818 if( !rec ) 819 goto err; 820 821 r = MSI_RecordSetStringW( rec, 1, name ); 822 if( r ) 823 goto err; 824 825 /* 826 * need to set the table, column number, col name and type 827 * for each column we enter in the table 828 */ 829 nField = 1; 830 for( col = col_info; col; col = col->next ) 831 { 832 r = MSI_RecordSetInteger( rec, 2, nField ); 833 if( r ) 834 goto err; 835 836 r = MSI_RecordSetStringW( rec, 3, col->column ); 837 if( r ) 838 goto err; 839 840 r = MSI_RecordSetInteger( rec, 4, col->type ); 841 if( r ) 842 goto err; 843 844 r = tv->ops->insert_row( tv, rec, -1, FALSE ); 845 if( r ) 846 goto err; 847 848 nField++; 849 } 850 if( !col ) 851 r = ERROR_SUCCESS; 852 } 853 854 err: 855 if (rec) 856 msiobj_release( &rec->hdr ); 857 /* FIXME: remove values from the string table on error */ 858 if( tv ) 859 tv->ops->delete( tv ); 860 861 if (r == ERROR_SUCCESS) 862 list_add_head( &db->tables, &table->entry ); 863 else 864 free_table( table ); 865 866 return r; 867 } 868 869 static UINT save_table( MSIDATABASE *db, const MSITABLE *t, UINT bytes_per_strref ) 870 { 871 BYTE *rawdata = NULL; 872 UINT rawsize, i, j, row_size, row_count; 873 UINT r = ERROR_FUNCTION_FAILED; 874 875 /* Nothing to do for non-persistent tables */ 876 if( t->persistent == MSICONDITION_FALSE ) 877 return ERROR_SUCCESS; 878 879 TRACE("Saving %s\n", debugstr_w( t->name ) ); 880 881 row_size = msi_table_get_row_size( db, t->colinfo, t->col_count, bytes_per_strref ); 882 row_count = t->row_count; 883 for (i = 0; i < t->row_count; i++) 884 { 885 if (!t->data_persistent[i]) 886 { 887 row_count = 1; /* yes, this is bizarre */ 888 break; 889 } 890 } 891 rawsize = row_count * row_size; 892 rawdata = msi_alloc_zero( rawsize ); 893 if( !rawdata ) 894 { 895 r = ERROR_NOT_ENOUGH_MEMORY; 896 goto err; 897 } 898 899 rawsize = 0; 900 for (i = 0; i < row_count; i++) 901 { 902 UINT ofs = 0, ofs_mem = 0; 903 904 if (!t->data_persistent[i]) break; 905 906 for (j = 0; j < t->col_count; j++) 907 { 908 UINT m = bytes_per_column( db, &t->colinfo[j], LONG_STR_BYTES ); 909 UINT n = bytes_per_column( db, &t->colinfo[j], bytes_per_strref ); 910 UINT k; 911 912 if (n != 2 && n != 3 && n != 4) 913 { 914 ERR("oops - unknown column width %d\n", n); 915 goto err; 916 } 917 if (t->colinfo[j].type & MSITYPE_STRING && n < m) 918 { 919 UINT id = read_table_int( t->data, i, ofs_mem, LONG_STR_BYTES ); 920 if (id > 1 << bytes_per_strref * 8) 921 { 922 ERR("string id %u out of range\n", id); 923 goto err; 924 } 925 } 926 for (k = 0; k < n; k++) 927 { 928 rawdata[ofs * row_count + i * n + k] = t->data[i][ofs_mem + k]; 929 } 930 ofs_mem += m; 931 ofs += n; 932 } 933 rawsize += row_size; 934 } 935 936 TRACE("writing %d bytes\n", rawsize); 937 r = write_stream_data( db->storage, t->name, rawdata, rawsize, TRUE ); 938 939 err: 940 msi_free( rawdata ); 941 return r; 942 } 943 944 static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR name ) 945 { 946 MSITABLE *table; 947 UINT size, offset, old_count; 948 UINT n; 949 950 if (!(table = find_cached_table( db, name ))) return; 951 old_count = table->col_count; 952 msi_free_colinfo( table->colinfo, table->col_count ); 953 msi_free( table->colinfo ); 954 table->colinfo = NULL; 955 956 table_get_column_info( db, name, &table->colinfo, &table->col_count ); 957 if (!table->col_count) return; 958 959 size = msi_table_get_row_size( db, table->colinfo, table->col_count, LONG_STR_BYTES ); 960 offset = table->colinfo[table->col_count - 1].offset; 961 962 for ( n = 0; n < table->row_count; n++ ) 963 { 964 table->data[n] = msi_realloc( table->data[n], size ); 965 if (old_count < table->col_count) 966 memset( &table->data[n][offset], 0, size - offset ); 967 } 968 } 969 970 /* try to find the table name in the _Tables table */ 971 BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name ) 972 { 973 UINT r, table_id, i; 974 MSITABLE *table; 975 976 if( !strcmpW( name, szTables ) || !strcmpW( name, szColumns ) || 977 !strcmpW( name, szStreams ) || !strcmpW( name, szStorages ) ) 978 return TRUE; 979 980 r = msi_string2id( db->strings, name, -1, &table_id ); 981 if( r != ERROR_SUCCESS ) 982 { 983 TRACE("Couldn't find id for %s\n", debugstr_w(name)); 984 return FALSE; 985 } 986 987 r = get_table( db, szTables, &table ); 988 if( r != ERROR_SUCCESS ) 989 { 990 ERR("table %s not available\n", debugstr_w(szTables)); 991 return FALSE; 992 } 993 994 for( i = 0; i < table->row_count; i++ ) 995 { 996 if( read_table_int( table->data, i, 0, LONG_STR_BYTES ) == table_id ) 997 return TRUE; 998 } 999 1000 return FALSE; 1001 } 1002 1003 /* below is the query interface to a table */ 1004 1005 typedef struct tagMSITABLEVIEW 1006 { 1007 MSIVIEW view; 1008 MSIDATABASE *db; 1009 MSITABLE *table; 1010 MSICOLUMNINFO *columns; 1011 UINT num_cols; 1012 UINT row_size; 1013 WCHAR name[1]; 1014 } MSITABLEVIEW; 1015 1016 static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) 1017 { 1018 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1019 UINT offset, n; 1020 1021 if( !tv->table ) 1022 return ERROR_INVALID_PARAMETER; 1023 1024 if( (col==0) || (col>tv->num_cols) ) 1025 return ERROR_INVALID_PARAMETER; 1026 1027 /* how many rows are there ? */ 1028 if( row >= tv->table->row_count ) 1029 return ERROR_NO_MORE_ITEMS; 1030 1031 if( tv->columns[col-1].offset >= tv->row_size ) 1032 { 1033 ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size ); 1034 ERR("%p %p\n", tv, tv->columns ); 1035 return ERROR_FUNCTION_FAILED; 1036 } 1037 1038 n = bytes_per_column( tv->db, &tv->columns[col - 1], LONG_STR_BYTES ); 1039 if (n != 2 && n != 3 && n != 4) 1040 { 1041 ERR("oops! what is %d bytes per column?\n", n ); 1042 return ERROR_FUNCTION_FAILED; 1043 } 1044 1045 offset = tv->columns[col-1].offset; 1046 *val = read_table_int(tv->table->data, row, offset, n); 1047 1048 /* TRACE("Data [%d][%d] = %d\n", row, col, *val ); */ 1049 1050 return ERROR_SUCCESS; 1051 } 1052 1053 static UINT get_stream_name( const MSITABLEVIEW *tv, UINT row, WCHAR **pstname ) 1054 { 1055 LPWSTR p, stname = NULL; 1056 UINT i, r, type, ival; 1057 DWORD len; 1058 LPCWSTR sval; 1059 MSIVIEW *view = (MSIVIEW *) tv; 1060 1061 TRACE("%p %d\n", tv, row); 1062 1063 len = lstrlenW( tv->name ) + 1; 1064 stname = msi_alloc( len*sizeof(WCHAR) ); 1065 if ( !stname ) 1066 { 1067 r = ERROR_OUTOFMEMORY; 1068 goto err; 1069 } 1070 1071 lstrcpyW( stname, tv->name ); 1072 1073 for ( i = 0; i < tv->num_cols; i++ ) 1074 { 1075 type = tv->columns[i].type; 1076 if ( type & MSITYPE_KEY ) 1077 { 1078 WCHAR number[0x20]; 1079 1080 r = TABLE_fetch_int( view, row, i+1, &ival ); 1081 if ( r != ERROR_SUCCESS ) 1082 goto err; 1083 1084 if ( tv->columns[i].type & MSITYPE_STRING ) 1085 { 1086 sval = msi_string_lookup( tv->db->strings, ival, NULL ); 1087 if ( !sval ) 1088 { 1089 r = ERROR_INVALID_PARAMETER; 1090 goto err; 1091 } 1092 } 1093 else 1094 { 1095 static const WCHAR fmt[] = { '%','d',0 }; 1096 UINT n = bytes_per_column( tv->db, &tv->columns[i], LONG_STR_BYTES ); 1097 1098 switch( n ) 1099 { 1100 case 2: 1101 sprintfW( number, fmt, ival-0x8000 ); 1102 break; 1103 case 4: 1104 sprintfW( number, fmt, ival^0x80000000 ); 1105 break; 1106 default: 1107 ERR( "oops - unknown column width %d\n", n ); 1108 r = ERROR_FUNCTION_FAILED; 1109 goto err; 1110 } 1111 sval = number; 1112 } 1113 1114 len += lstrlenW( szDot ) + lstrlenW( sval ); 1115 p = msi_realloc ( stname, len*sizeof(WCHAR) ); 1116 if ( !p ) 1117 { 1118 r = ERROR_OUTOFMEMORY; 1119 goto err; 1120 } 1121 stname = p; 1122 1123 lstrcatW( stname, szDot ); 1124 lstrcatW( stname, sval ); 1125 } 1126 else 1127 continue; 1128 } 1129 1130 *pstname = stname; 1131 return ERROR_SUCCESS; 1132 1133 err: 1134 msi_free( stname ); 1135 *pstname = NULL; 1136 return r; 1137 } 1138 1139 /* 1140 * We need a special case for streams, as we need to reference column with 1141 * the name of the stream in the same table, and the table name 1142 * which may not be available at higher levels of the query 1143 */ 1144 static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm ) 1145 { 1146 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1147 UINT r; 1148 WCHAR *name; 1149 1150 if( !view->ops->fetch_int ) 1151 return ERROR_INVALID_PARAMETER; 1152 1153 r = get_stream_name( tv, row, &name ); 1154 if (r != ERROR_SUCCESS) 1155 { 1156 ERR("fetching stream, error = %u\n", r); 1157 return r; 1158 } 1159 1160 r = msi_get_stream( tv->db, name, stm ); 1161 if (r != ERROR_SUCCESS) 1162 ERR("fetching stream %s, error = %u\n", debugstr_w(name), r); 1163 1164 msi_free( name ); 1165 return r; 1166 } 1167 1168 static UINT TABLE_set_int( MSITABLEVIEW *tv, UINT row, UINT col, UINT val ) 1169 { 1170 UINT offset, n, i; 1171 1172 if( !tv->table ) 1173 return ERROR_INVALID_PARAMETER; 1174 1175 if( (col==0) || (col>tv->num_cols) ) 1176 return ERROR_INVALID_PARAMETER; 1177 1178 if( row >= tv->table->row_count ) 1179 return ERROR_INVALID_PARAMETER; 1180 1181 if( tv->columns[col-1].offset >= tv->row_size ) 1182 { 1183 ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size ); 1184 ERR("%p %p\n", tv, tv->columns ); 1185 return ERROR_FUNCTION_FAILED; 1186 } 1187 1188 msi_free( tv->columns[col-1].hash_table ); 1189 tv->columns[col-1].hash_table = NULL; 1190 1191 n = bytes_per_column( tv->db, &tv->columns[col - 1], LONG_STR_BYTES ); 1192 if ( n != 2 && n != 3 && n != 4 ) 1193 { 1194 ERR("oops! what is %d bytes per column?\n", n ); 1195 return ERROR_FUNCTION_FAILED; 1196 } 1197 1198 offset = tv->columns[col-1].offset; 1199 for ( i = 0; i < n; i++ ) 1200 tv->table->data[row][offset + i] = (val >> i * 8) & 0xff; 1201 1202 return ERROR_SUCCESS; 1203 } 1204 1205 static UINT TABLE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec ) 1206 { 1207 MSITABLEVIEW *tv = (MSITABLEVIEW *)view; 1208 1209 if (!tv->table) 1210 return ERROR_INVALID_PARAMETER; 1211 1212 return msi_view_get_row(tv->db, view, row, rec); 1213 } 1214 1215 static UINT add_stream( MSIDATABASE *db, const WCHAR *name, IStream *data ) 1216 { 1217 static const WCHAR insert[] = { 1218 'I','N','S','E','R','T',' ','I','N','T','O',' ', 1219 '`','_','S','t','r','e','a','m','s','`',' ', 1220 '(','`','N','a','m','e','`',',','`','D','a','t','a','`',')',' ', 1221 'V','A','L','U','E','S',' ','(','?',',','?',')',0}; 1222 static const WCHAR update[] = { 1223 'U','P','D','A','T','E',' ','`','_','S','t','r','e','a','m','s','`',' ', 1224 'S','E','T',' ','`','D','a','t','a','`',' ','=',' ','?',' ', 1225 'W','H','E','R','E',' ','`','N','a','m','e','`',' ','=',' ','?',0}; 1226 MSIQUERY *query; 1227 MSIRECORD *rec; 1228 UINT r; 1229 1230 TRACE("%p %s %p\n", db, debugstr_w(name), data); 1231 1232 if (!(rec = MSI_CreateRecord( 2 ))) 1233 return ERROR_OUTOFMEMORY; 1234 1235 r = MSI_RecordSetStringW( rec, 1, name ); 1236 if (r != ERROR_SUCCESS) 1237 goto done; 1238 1239 r = MSI_RecordSetIStream( rec, 2, data ); 1240 if (r != ERROR_SUCCESS) 1241 goto done; 1242 1243 r = MSI_DatabaseOpenViewW( db, insert, &query ); 1244 if (r != ERROR_SUCCESS) 1245 goto done; 1246 1247 r = MSI_ViewExecute( query, rec ); 1248 msiobj_release( &query->hdr ); 1249 if (r == ERROR_SUCCESS) 1250 goto done; 1251 1252 msiobj_release( &rec->hdr ); 1253 if (!(rec = MSI_CreateRecord( 2 ))) 1254 return ERROR_OUTOFMEMORY; 1255 1256 r = MSI_RecordSetIStream( rec, 1, data ); 1257 if (r != ERROR_SUCCESS) 1258 goto done; 1259 1260 r = MSI_RecordSetStringW( rec, 2, name ); 1261 if (r != ERROR_SUCCESS) 1262 goto done; 1263 1264 r = MSI_DatabaseOpenViewW( db, update, &query ); 1265 if (r != ERROR_SUCCESS) 1266 goto done; 1267 1268 r = MSI_ViewExecute( query, rec ); 1269 msiobj_release( &query->hdr ); 1270 1271 done: 1272 msiobj_release( &rec->hdr ); 1273 return r; 1274 } 1275 1276 static UINT get_table_value_from_record( MSITABLEVIEW *tv, MSIRECORD *rec, UINT iField, UINT *pvalue ) 1277 { 1278 MSICOLUMNINFO columninfo; 1279 UINT r; 1280 int ival; 1281 1282 if ( (iField <= 0) || 1283 (iField > tv->num_cols) || 1284 MSI_RecordIsNull( rec, iField ) ) 1285 return ERROR_FUNCTION_FAILED; 1286 1287 columninfo = tv->columns[ iField - 1 ]; 1288 1289 if ( MSITYPE_IS_BINARY(columninfo.type) ) 1290 { 1291 *pvalue = 1; /* refers to the first key column */ 1292 } 1293 else if ( columninfo.type & MSITYPE_STRING ) 1294 { 1295 int len; 1296 const WCHAR *sval = msi_record_get_string( rec, iField, &len ); 1297 if (sval) 1298 { 1299 r = msi_string2id( tv->db->strings, sval, len, pvalue ); 1300 if (r != ERROR_SUCCESS) 1301 return ERROR_NOT_FOUND; 1302 } 1303 else *pvalue = 0; 1304 } 1305 else if ( bytes_per_column( tv->db, &columninfo, LONG_STR_BYTES ) == 2 ) 1306 { 1307 ival = MSI_RecordGetInteger( rec, iField ); 1308 if (ival == 0x80000000) *pvalue = 0x8000; 1309 else 1310 { 1311 *pvalue = 0x8000 + MSI_RecordGetInteger( rec, iField ); 1312 if (*pvalue & 0xffff0000) 1313 { 1314 ERR("field %u value %d out of range\n", iField, *pvalue - 0x8000); 1315 return ERROR_FUNCTION_FAILED; 1316 } 1317 } 1318 } 1319 else 1320 { 1321 ival = MSI_RecordGetInteger( rec, iField ); 1322 *pvalue = ival ^ 0x80000000; 1323 } 1324 1325 return ERROR_SUCCESS; 1326 } 1327 1328 static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask ) 1329 { 1330 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1331 UINT i, val, r = ERROR_SUCCESS; 1332 1333 if ( !tv->table ) 1334 return ERROR_INVALID_PARAMETER; 1335 1336 /* test if any of the mask bits are invalid */ 1337 if ( mask >= (1<<tv->num_cols) ) 1338 return ERROR_INVALID_PARAMETER; 1339 1340 for ( i = 0; i < tv->num_cols; i++ ) 1341 { 1342 BOOL persistent; 1343 1344 /* only update the fields specified in the mask */ 1345 if ( !(mask&(1<<i)) ) 1346 continue; 1347 1348 persistent = (tv->table->persistent != MSICONDITION_FALSE) && 1349 (tv->table->data_persistent[row]); 1350 /* FIXME: should we allow updating keys? */ 1351 1352 val = 0; 1353 if ( !MSI_RecordIsNull( rec, i + 1 ) ) 1354 { 1355 r = get_table_value_from_record (tv, rec, i + 1, &val); 1356 if ( MSITYPE_IS_BINARY(tv->columns[ i ].type) ) 1357 { 1358 IStream *stm; 1359 LPWSTR stname; 1360 1361 if ( r != ERROR_SUCCESS ) 1362 return ERROR_FUNCTION_FAILED; 1363 1364 r = MSI_RecordGetIStream( rec, i + 1, &stm ); 1365 if ( r != ERROR_SUCCESS ) 1366 return r; 1367 1368 r = get_stream_name( tv, row, &stname ); 1369 if ( r != ERROR_SUCCESS ) 1370 { 1371 IStream_Release( stm ); 1372 return r; 1373 } 1374 1375 r = add_stream( tv->db, stname, stm ); 1376 IStream_Release( stm ); 1377 msi_free ( stname ); 1378 1379 if ( r != ERROR_SUCCESS ) 1380 return r; 1381 } 1382 else if ( tv->columns[i].type & MSITYPE_STRING ) 1383 { 1384 UINT x; 1385 1386 if ( r != ERROR_SUCCESS ) 1387 { 1388 int len; 1389 const WCHAR *sval = msi_record_get_string( rec, i + 1, &len ); 1390 val = msi_add_string( tv->db->strings, sval, len, 1391 persistent ? StringPersistent : StringNonPersistent ); 1392 } 1393 else 1394 { 1395 TABLE_fetch_int(&tv->view, row, i + 1, &x); 1396 if (val == x) 1397 continue; 1398 } 1399 } 1400 else 1401 { 1402 if ( r != ERROR_SUCCESS ) 1403 return ERROR_FUNCTION_FAILED; 1404 } 1405 } 1406 1407 r = TABLE_set_int( tv, row, i+1, val ); 1408 if ( r != ERROR_SUCCESS ) 1409 break; 1410 } 1411 return r; 1412 } 1413 1414 static UINT table_create_new_row( struct tagMSIVIEW *view, UINT *num, BOOL temporary ) 1415 { 1416 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1417 BYTE **p, *row; 1418 BOOL *b; 1419 UINT sz; 1420 BYTE ***data_ptr; 1421 BOOL **data_persist_ptr; 1422 UINT *row_count; 1423 1424 TRACE("%p %s\n", view, temporary ? "TRUE" : "FALSE"); 1425 1426 if( !tv->table ) 1427 return ERROR_INVALID_PARAMETER; 1428 1429 row = msi_alloc_zero( tv->row_size ); 1430 if( !row ) 1431 return ERROR_NOT_ENOUGH_MEMORY; 1432 1433 row_count = &tv->table->row_count; 1434 data_ptr = &tv->table->data; 1435 data_persist_ptr = &tv->table->data_persistent; 1436 if (*num == -1) 1437 *num = tv->table->row_count; 1438 1439 sz = (*row_count + 1) * sizeof (BYTE*); 1440 if( *data_ptr ) 1441 p = msi_realloc( *data_ptr, sz ); 1442 else 1443 p = msi_alloc( sz ); 1444 if( !p ) 1445 { 1446 msi_free( row ); 1447 return ERROR_NOT_ENOUGH_MEMORY; 1448 } 1449 1450 sz = (*row_count + 1) * sizeof (BOOL); 1451 if( *data_persist_ptr ) 1452 b = msi_realloc( *data_persist_ptr, sz ); 1453 else 1454 b = msi_alloc( sz ); 1455 if( !b ) 1456 { 1457 msi_free( row ); 1458 msi_free( p ); 1459 return ERROR_NOT_ENOUGH_MEMORY; 1460 } 1461 1462 *data_ptr = p; 1463 (*data_ptr)[*row_count] = row; 1464 1465 *data_persist_ptr = b; 1466 (*data_persist_ptr)[*row_count] = !temporary; 1467 1468 (*row_count)++; 1469 1470 return ERROR_SUCCESS; 1471 } 1472 1473 static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) 1474 { 1475 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1476 1477 TRACE("%p %p\n", tv, record); 1478 1479 TRACE("There are %d columns\n", tv->num_cols ); 1480 1481 return ERROR_SUCCESS; 1482 } 1483 1484 static UINT TABLE_close( struct tagMSIVIEW *view ) 1485 { 1486 TRACE("%p\n", view ); 1487 1488 return ERROR_SUCCESS; 1489 } 1490 1491 static UINT TABLE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols) 1492 { 1493 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1494 1495 TRACE("%p %p %p\n", view, rows, cols ); 1496 1497 if( cols ) 1498 *cols = tv->num_cols; 1499 if( rows ) 1500 { 1501 if( !tv->table ) 1502 return ERROR_INVALID_PARAMETER; 1503 *rows = tv->table->row_count; 1504 } 1505 1506 return ERROR_SUCCESS; 1507 } 1508 1509 static UINT TABLE_get_column_info( struct tagMSIVIEW *view, 1510 UINT n, LPCWSTR *name, UINT *type, BOOL *temporary, 1511 LPCWSTR *table_name ) 1512 { 1513 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1514 1515 TRACE("%p %d %p %p\n", tv, n, name, type ); 1516 1517 if( ( n == 0 ) || ( n > tv->num_cols ) ) 1518 return ERROR_INVALID_PARAMETER; 1519 1520 if( name ) 1521 { 1522 *name = tv->columns[n-1].colname; 1523 if( !*name ) 1524 return ERROR_FUNCTION_FAILED; 1525 } 1526 1527 if( table_name ) 1528 { 1529 *table_name = tv->columns[n-1].tablename; 1530 if( !*table_name ) 1531 return ERROR_FUNCTION_FAILED; 1532 } 1533 1534 if( type ) 1535 *type = tv->columns[n-1].type; 1536 1537 if( temporary ) 1538 *temporary = tv->columns[n-1].temporary; 1539 1540 return ERROR_SUCCESS; 1541 } 1542 1543 static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row, UINT *column ); 1544 1545 static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *column ) 1546 { 1547 UINT r, row, i; 1548 1549 /* check there are no null values where they're not allowed */ 1550 for( i = 0; i < tv->num_cols; i++ ) 1551 { 1552 if ( tv->columns[i].type & MSITYPE_NULLABLE ) 1553 continue; 1554 1555 if ( MSITYPE_IS_BINARY(tv->columns[i].type) ) 1556 TRACE("skipping binary column\n"); 1557 else if ( tv->columns[i].type & MSITYPE_STRING ) 1558 { 1559 int len; 1560 const WCHAR *str = msi_record_get_string( rec, i+1, &len ); 1561 1562 if (!str || (!str[0] && !len)) 1563 { 1564 if (column) *column = i; 1565 return ERROR_INVALID_DATA; 1566 } 1567 } 1568 else 1569 { 1570 UINT n; 1571 1572 n = MSI_RecordGetInteger( rec, i+1 ); 1573 if (n == MSI_NULL_INTEGER) 1574 { 1575 if (column) *column = i; 1576 return ERROR_INVALID_DATA; 1577 } 1578 } 1579 } 1580 1581 /* check there are no duplicate keys */ 1582 r = msi_table_find_row( tv, rec, &row, column ); 1583 if (r == ERROR_SUCCESS) 1584 return ERROR_FUNCTION_FAILED; 1585 1586 return ERROR_SUCCESS; 1587 } 1588 1589 static int compare_record( MSITABLEVIEW *tv, UINT row, MSIRECORD *rec ) 1590 { 1591 UINT r, i, ivalue, x; 1592 1593 for (i = 0; i < tv->num_cols; i++ ) 1594 { 1595 if (!(tv->columns[i].type & MSITYPE_KEY)) continue; 1596 1597 r = get_table_value_from_record( tv, rec, i + 1, &ivalue ); 1598 if (r != ERROR_SUCCESS) 1599 return 1; 1600 1601 r = TABLE_fetch_int( &tv->view, row, i + 1, &x ); 1602 if (r != ERROR_SUCCESS) 1603 { 1604 WARN("TABLE_fetch_int should not fail here %u\n", r); 1605 return -1; 1606 } 1607 if (ivalue > x) 1608 { 1609 return 1; 1610 } 1611 else if (ivalue == x) 1612 { 1613 if (i < tv->num_cols - 1) continue; 1614 return 0; 1615 } 1616 else 1617 return -1; 1618 } 1619 return 1; 1620 } 1621 1622 static int find_insert_index( MSITABLEVIEW *tv, MSIRECORD *rec ) 1623 { 1624 int idx, c, low = 0, high = tv->table->row_count - 1; 1625 1626 TRACE("%p %p\n", tv, rec); 1627 1628 while (low <= high) 1629 { 1630 idx = (low + high) / 2; 1631 c = compare_record( tv, idx, rec ); 1632 1633 if (c < 0) 1634 high = idx - 1; 1635 else if (c > 0) 1636 low = idx + 1; 1637 else 1638 { 1639 TRACE("found %u\n", idx); 1640 return idx; 1641 } 1642 } 1643 TRACE("found %u\n", high + 1); 1644 return high + 1; 1645 } 1646 1647 static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary ) 1648 { 1649 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1650 UINT i, r; 1651 1652 TRACE("%p %p %s\n", tv, rec, temporary ? "TRUE" : "FALSE" ); 1653 1654 /* check that the key is unique - can we find a matching row? */ 1655 r = table_validate_new( tv, rec, NULL ); 1656 if( r != ERROR_SUCCESS ) 1657 return ERROR_FUNCTION_FAILED; 1658 1659 if (row == -1) 1660 row = find_insert_index( tv, rec ); 1661 1662 r = table_create_new_row( view, &row, temporary ); 1663 TRACE("insert_row returned %08x\n", r); 1664 if( r != ERROR_SUCCESS ) 1665 return r; 1666 1667 /* shift the rows to make room for the new row */ 1668 for (i = tv->table->row_count - 1; i > row; i--) 1669 { 1670 memmove(&(tv->table->data[i][0]), 1671 &(tv->table->data[i - 1][0]), tv->row_size); 1672 tv->table->data_persistent[i] = tv->table->data_persistent[i - 1]; 1673 } 1674 1675 /* Re-set the persistence flag */ 1676 tv->table->data_persistent[row] = !temporary; 1677 return TABLE_set_row( view, row, rec, (1<<tv->num_cols) - 1 ); 1678 } 1679 1680 static UINT TABLE_delete_row( struct tagMSIVIEW *view, UINT row ) 1681 { 1682 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1683 UINT r, num_rows, num_cols, i; 1684 1685 TRACE("%p %d\n", tv, row); 1686 1687 if ( !tv->table ) 1688 return ERROR_INVALID_PARAMETER; 1689 1690 r = TABLE_get_dimensions( view, &num_rows, &num_cols ); 1691 if ( r != ERROR_SUCCESS ) 1692 return r; 1693 1694 if ( row >= num_rows ) 1695 return ERROR_FUNCTION_FAILED; 1696 1697 num_rows = tv->table->row_count; 1698 tv->table->row_count--; 1699 1700 /* reset the hash tables */ 1701 for (i = 0; i < tv->num_cols; i++) 1702 { 1703 msi_free( tv->columns[i].hash_table ); 1704 tv->columns[i].hash_table = NULL; 1705 } 1706 1707 for (i = row + 1; i < num_rows; i++) 1708 { 1709 memcpy(tv->table->data[i - 1], tv->table->data[i], tv->row_size); 1710 tv->table->data_persistent[i - 1] = tv->table->data_persistent[i]; 1711 } 1712 1713 msi_free(tv->table->data[num_rows - 1]); 1714 1715 return ERROR_SUCCESS; 1716 } 1717 1718 static UINT msi_table_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row) 1719 { 1720 MSITABLEVIEW *tv = (MSITABLEVIEW *)view; 1721 UINT r, new_row; 1722 1723 /* FIXME: MsiViewFetch should set rec index 0 to some ID that 1724 * sets the fetched record apart from other records 1725 */ 1726 1727 if (!tv->table) 1728 return ERROR_INVALID_PARAMETER; 1729 1730 r = msi_table_find_row(tv, rec, &new_row, NULL); 1731 if (r != ERROR_SUCCESS) 1732 { 1733 ERR("can't find row to modify\n"); 1734 return ERROR_FUNCTION_FAILED; 1735 } 1736 1737 /* the row cannot be changed */ 1738 if (row != new_row + 1) 1739 return ERROR_FUNCTION_FAILED; 1740 1741 return TABLE_set_row(view, new_row, rec, (1 << tv->num_cols) - 1); 1742 } 1743 1744 static UINT msi_table_assign(struct tagMSIVIEW *view, MSIRECORD *rec) 1745 { 1746 MSITABLEVIEW *tv = (MSITABLEVIEW *)view; 1747 UINT r, row; 1748 1749 if (!tv->table) 1750 return ERROR_INVALID_PARAMETER; 1751 1752 r = msi_table_find_row(tv, rec, &row, NULL); 1753 if (r == ERROR_SUCCESS) 1754 return TABLE_set_row(view, row, rec, (1 << tv->num_cols) - 1); 1755 else 1756 return TABLE_insert_row( view, rec, -1, FALSE ); 1757 } 1758 1759 static UINT modify_delete_row( struct tagMSIVIEW *view, MSIRECORD *rec ) 1760 { 1761 MSITABLEVIEW *tv = (MSITABLEVIEW *)view; 1762 UINT row, r; 1763 1764 r = msi_table_find_row(tv, rec, &row, NULL); 1765 if (r != ERROR_SUCCESS) 1766 return r; 1767 1768 return TABLE_delete_row(view, row); 1769 } 1770 1771 static UINT msi_refresh_record( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row ) 1772 { 1773 MSIRECORD *curr; 1774 UINT r, i, count; 1775 1776 r = TABLE_get_row(view, row - 1, &curr); 1777 if (r != ERROR_SUCCESS) 1778 return r; 1779 1780 /* Close the original record */ 1781 MSI_CloseRecord(&rec->hdr); 1782 1783 count = MSI_RecordGetFieldCount(rec); 1784 for (i = 0; i < count; i++) 1785 MSI_RecordCopyField(curr, i + 1, rec, i + 1); 1786 1787 msiobj_release(&curr->hdr); 1788 return ERROR_SUCCESS; 1789 } 1790 1791 static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, 1792 MSIRECORD *rec, UINT row) 1793 { 1794 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1795 UINT r, frow, column; 1796 1797 TRACE("%p %d %p\n", view, eModifyMode, rec ); 1798 1799 switch (eModifyMode) 1800 { 1801 case MSIMODIFY_DELETE: 1802 r = modify_delete_row( view, rec ); 1803 break; 1804 case MSIMODIFY_VALIDATE_NEW: 1805 r = table_validate_new( tv, rec, &column ); 1806 if (r != ERROR_SUCCESS) 1807 { 1808 tv->view.error = MSIDBERROR_DUPLICATEKEY; 1809 tv->view.error_column = tv->columns[column].colname; 1810 r = ERROR_INVALID_DATA; 1811 } 1812 break; 1813 1814 case MSIMODIFY_INSERT: 1815 r = table_validate_new( tv, rec, NULL ); 1816 if (r != ERROR_SUCCESS) 1817 break; 1818 r = TABLE_insert_row( view, rec, -1, FALSE ); 1819 break; 1820 1821 case MSIMODIFY_INSERT_TEMPORARY: 1822 r = table_validate_new( tv, rec, NULL ); 1823 if (r != ERROR_SUCCESS) 1824 break; 1825 r = TABLE_insert_row( view, rec, -1, TRUE ); 1826 break; 1827 1828 case MSIMODIFY_REFRESH: 1829 r = msi_refresh_record( view, rec, row ); 1830 break; 1831 1832 case MSIMODIFY_UPDATE: 1833 r = msi_table_update( view, rec, row ); 1834 break; 1835 1836 case MSIMODIFY_ASSIGN: 1837 r = msi_table_assign( view, rec ); 1838 break; 1839 1840 case MSIMODIFY_MERGE: 1841 /* check row that matches this record */ 1842 r = msi_table_find_row( tv, rec, &frow, &column ); 1843 if (r != ERROR_SUCCESS) 1844 { 1845 r = table_validate_new( tv, rec, NULL ); 1846 if (r == ERROR_SUCCESS) 1847 r = TABLE_insert_row( view, rec, -1, FALSE ); 1848 } 1849 break; 1850 1851 case MSIMODIFY_REPLACE: 1852 case MSIMODIFY_VALIDATE: 1853 case MSIMODIFY_VALIDATE_FIELD: 1854 case MSIMODIFY_VALIDATE_DELETE: 1855 FIXME("%p %d %p - mode not implemented\n", view, eModifyMode, rec ); 1856 r = ERROR_CALL_NOT_IMPLEMENTED; 1857 break; 1858 1859 default: 1860 r = ERROR_INVALID_DATA; 1861 } 1862 1863 return r; 1864 } 1865 1866 static UINT TABLE_delete( struct tagMSIVIEW *view ) 1867 { 1868 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1869 1870 TRACE("%p\n", view ); 1871 1872 tv->table = NULL; 1873 tv->columns = NULL; 1874 1875 msi_free( tv ); 1876 1877 return ERROR_SUCCESS; 1878 } 1879 1880 static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col, 1881 UINT val, UINT *row, MSIITERHANDLE *handle ) 1882 { 1883 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1884 const MSICOLUMNHASHENTRY *entry; 1885 1886 TRACE("%p, %d, %u, %p\n", view, col, val, *handle); 1887 1888 if( !tv->table ) 1889 return ERROR_INVALID_PARAMETER; 1890 1891 if( (col==0) || (col > tv->num_cols) ) 1892 return ERROR_INVALID_PARAMETER; 1893 1894 if( !tv->columns[col-1].hash_table ) 1895 { 1896 UINT i; 1897 UINT num_rows = tv->table->row_count; 1898 MSICOLUMNHASHENTRY **hash_table; 1899 MSICOLUMNHASHENTRY *new_entry; 1900 1901 if( tv->columns[col-1].offset >= tv->row_size ) 1902 { 1903 ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size ); 1904 ERR("%p %p\n", tv, tv->columns ); 1905 return ERROR_FUNCTION_FAILED; 1906 } 1907 1908 /* allocate contiguous memory for the table and its entries so we 1909 * don't have to do an expensive cleanup */ 1910 hash_table = msi_alloc(MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*) + 1911 num_rows * sizeof(MSICOLUMNHASHENTRY)); 1912 if (!hash_table) 1913 return ERROR_OUTOFMEMORY; 1914 1915 memset(hash_table, 0, MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*)); 1916 tv->columns[col-1].hash_table = hash_table; 1917 1918 new_entry = (MSICOLUMNHASHENTRY *)(hash_table + MSITABLE_HASH_TABLE_SIZE); 1919 1920 for (i = 0; i < num_rows; i++, new_entry++) 1921 { 1922 UINT row_value; 1923 1924 if (view->ops->fetch_int( view, i, col, &row_value ) != ERROR_SUCCESS) 1925 continue; 1926 1927 new_entry->next = NULL; 1928 new_entry->value = row_value; 1929 new_entry->row = i; 1930 if (hash_table[row_value % MSITABLE_HASH_TABLE_SIZE]) 1931 { 1932 MSICOLUMNHASHENTRY *prev_entry = hash_table[row_value % MSITABLE_HASH_TABLE_SIZE]; 1933 while (prev_entry->next) 1934 prev_entry = prev_entry->next; 1935 prev_entry->next = new_entry; 1936 } 1937 else 1938 hash_table[row_value % MSITABLE_HASH_TABLE_SIZE] = new_entry; 1939 } 1940 } 1941 1942 if( !*handle ) 1943 entry = tv->columns[col-1].hash_table[val % MSITABLE_HASH_TABLE_SIZE]; 1944 else 1945 entry = (*handle)->next; 1946 1947 while (entry && entry->value != val) 1948 entry = entry->next; 1949 1950 *handle = entry; 1951 if (!entry) 1952 return ERROR_NO_MORE_ITEMS; 1953 1954 *row = entry->row; 1955 1956 return ERROR_SUCCESS; 1957 } 1958 1959 static UINT TABLE_add_ref(struct tagMSIVIEW *view) 1960 { 1961 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1962 UINT i; 1963 1964 TRACE("%p %d\n", view, tv->table->ref_count); 1965 1966 for (i = 0; i < tv->table->col_count; i++) 1967 { 1968 if (tv->table->colinfo[i].type & MSITYPE_TEMPORARY) 1969 InterlockedIncrement(&tv->table->colinfo[i].ref_count); 1970 } 1971 1972 return InterlockedIncrement(&tv->table->ref_count); 1973 } 1974 1975 static UINT TABLE_remove_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number) 1976 { 1977 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 1978 MSIRECORD *rec = NULL; 1979 MSIVIEW *columns = NULL; 1980 UINT row, r; 1981 1982 rec = MSI_CreateRecord(2); 1983 if (!rec) 1984 return ERROR_OUTOFMEMORY; 1985 1986 MSI_RecordSetStringW(rec, 1, table); 1987 MSI_RecordSetInteger(rec, 2, number); 1988 1989 r = TABLE_CreateView(tv->db, szColumns, &columns); 1990 if (r != ERROR_SUCCESS) 1991 { 1992 msiobj_release(&rec->hdr); 1993 return r; 1994 } 1995 1996 r = msi_table_find_row((MSITABLEVIEW *)columns, rec, &row, NULL); 1997 if (r != ERROR_SUCCESS) 1998 goto done; 1999 2000 r = TABLE_delete_row(columns, row); 2001 if (r != ERROR_SUCCESS) 2002 goto done; 2003 2004 msi_update_table_columns(tv->db, table); 2005 2006 done: 2007 msiobj_release(&rec->hdr); 2008 columns->ops->delete(columns); 2009 return r; 2010 } 2011 2012 static UINT TABLE_release(struct tagMSIVIEW *view) 2013 { 2014 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 2015 INT ref = tv->table->ref_count; 2016 UINT i, r; 2017 2018 TRACE("%p %d\n", view, ref); 2019 2020 for (i = 0; i < tv->table->col_count; i++) 2021 { 2022 if (tv->table->colinfo[i].type & MSITYPE_TEMPORARY) 2023 { 2024 ref = InterlockedDecrement(&tv->table->colinfo[i].ref_count); 2025 if (ref == 0) 2026 { 2027 r = TABLE_remove_column(view, tv->table->colinfo[i].tablename, 2028 tv->table->colinfo[i].number); 2029 if (r != ERROR_SUCCESS) 2030 break; 2031 } 2032 } 2033 } 2034 2035 ref = InterlockedDecrement(&tv->table->ref_count); 2036 if (ref == 0) 2037 { 2038 if (!tv->table->row_count) 2039 { 2040 list_remove(&tv->table->entry); 2041 free_table(tv->table); 2042 TABLE_delete(view); 2043 } 2044 } 2045 2046 return ref; 2047 } 2048 2049 static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number, 2050 LPCWSTR column, UINT type, BOOL hold) 2051 { 2052 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 2053 MSITABLE *msitable; 2054 MSIRECORD *rec; 2055 UINT r, i; 2056 2057 rec = MSI_CreateRecord(4); 2058 if (!rec) 2059 return ERROR_OUTOFMEMORY; 2060 2061 MSI_RecordSetStringW(rec, 1, table); 2062 MSI_RecordSetInteger(rec, 2, number); 2063 MSI_RecordSetStringW(rec, 3, column); 2064 MSI_RecordSetInteger(rec, 4, type); 2065 2066 r = TABLE_insert_row(&tv->view, rec, -1, FALSE); 2067 if (r != ERROR_SUCCESS) 2068 goto done; 2069 2070 msi_update_table_columns(tv->db, table); 2071 2072 if (!hold) 2073 goto done; 2074 2075 msitable = find_cached_table(tv->db, table); 2076 for (i = 0; i < msitable->col_count; i++) 2077 { 2078 if (!strcmpW( msitable->colinfo[i].colname, column )) 2079 { 2080 InterlockedIncrement(&msitable->colinfo[i].ref_count); 2081 break; 2082 } 2083 } 2084 2085 done: 2086 msiobj_release(&rec->hdr); 2087 return r; 2088 } 2089 2090 static UINT TABLE_drop(struct tagMSIVIEW *view) 2091 { 2092 MSITABLEVIEW *tv = (MSITABLEVIEW*)view; 2093 MSIVIEW *tables = NULL; 2094 MSIRECORD *rec = NULL; 2095 UINT r, row; 2096 INT i; 2097 2098 TRACE("dropping table %s\n", debugstr_w(tv->name)); 2099 2100 for (i = tv->table->col_count - 1; i >= 0; i--) 2101 { 2102 r = TABLE_remove_column(view, tv->table->colinfo[i].tablename, 2103 tv->table->colinfo[i].number); 2104 if (r != ERROR_SUCCESS) 2105 return r; 2106 } 2107 2108 rec = MSI_CreateRecord(1); 2109 if (!rec) 2110 return ERROR_OUTOFMEMORY; 2111 2112 MSI_RecordSetStringW(rec, 1, tv->name); 2113 2114 r = TABLE_CreateView(tv->db, szTables, &tables); 2115 if (r != ERROR_SUCCESS) 2116 { 2117 msiobj_release(&rec->hdr); 2118 return r; 2119 } 2120 2121 r = msi_table_find_row((MSITABLEVIEW *)tables, rec, &row, NULL); 2122 if (r != ERROR_SUCCESS) 2123 goto done; 2124 2125 r = TABLE_delete_row(tables, row); 2126 if (r != ERROR_SUCCESS) 2127 goto done; 2128 2129 list_remove(&tv->table->entry); 2130 free_table(tv->table); 2131 2132 done: 2133 msiobj_release(&rec->hdr); 2134 tables->ops->delete(tables); 2135 2136 return r; 2137 } 2138 2139 static const MSIVIEWOPS table_ops = 2140 { 2141 TABLE_fetch_int, 2142 TABLE_fetch_stream, 2143 TABLE_get_row, 2144 TABLE_set_row, 2145 TABLE_insert_row, 2146 TABLE_delete_row, 2147 TABLE_execute, 2148 TABLE_close, 2149 TABLE_get_dimensions, 2150 TABLE_get_column_info, 2151 TABLE_modify, 2152 TABLE_delete, 2153 TABLE_find_matching_rows, 2154 TABLE_add_ref, 2155 TABLE_release, 2156 TABLE_add_column, 2157 TABLE_remove_column, 2158 NULL, 2159 TABLE_drop, 2160 }; 2161 2162 UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ) 2163 { 2164 MSITABLEVIEW *tv ; 2165 UINT r, sz; 2166 2167 TRACE("%p %s %p\n", db, debugstr_w(name), view ); 2168 2169 if ( !strcmpW( name, szStreams ) ) 2170 return STREAMS_CreateView( db, view ); 2171 else if ( !strcmpW( name, szStorages ) ) 2172 return STORAGES_CreateView( db, view ); 2173 2174 sz = FIELD_OFFSET( MSITABLEVIEW, name[lstrlenW( name ) + 1] ); 2175 tv = msi_alloc_zero( sz ); 2176 if( !tv ) 2177 return ERROR_FUNCTION_FAILED; 2178 2179 r = get_table( db, name, &tv->table ); 2180 if( r != ERROR_SUCCESS ) 2181 { 2182 msi_free( tv ); 2183 WARN("table not found\n"); 2184 return r; 2185 } 2186 2187 TRACE("table %p found with %d columns\n", tv->table, tv->table->col_count); 2188 2189 /* fill the structure */ 2190 tv->view.ops = &table_ops; 2191 tv->db = db; 2192 tv->columns = tv->table->colinfo; 2193 tv->num_cols = tv->table->col_count; 2194 tv->row_size = msi_table_get_row_size( db, tv->table->colinfo, tv->table->col_count, LONG_STR_BYTES ); 2195 2196 TRACE("%s one row is %d bytes\n", debugstr_w(name), tv->row_size ); 2197 2198 *view = (MSIVIEW*) tv; 2199 lstrcpyW( tv->name, name ); 2200 2201 return ERROR_SUCCESS; 2202 } 2203 2204 UINT MSI_CommitTables( MSIDATABASE *db ) 2205 { 2206 UINT r, bytes_per_strref; 2207 HRESULT hr; 2208 MSITABLE *table = NULL; 2209 2210 TRACE("%p\n",db); 2211 2212 r = msi_save_string_table( db->strings, db->storage, &bytes_per_strref ); 2213 if( r != ERROR_SUCCESS ) 2214 { 2215 WARN("failed to save string table r=%08x\n",r); 2216 return r; 2217 } 2218 2219 LIST_FOR_EACH_ENTRY( table, &db->tables, MSITABLE, entry ) 2220 { 2221 r = save_table( db, table, bytes_per_strref ); 2222 if( r != ERROR_SUCCESS ) 2223 { 2224 WARN("failed to save table %s (r=%08x)\n", 2225 debugstr_w(table->name), r); 2226 return r; 2227 } 2228 } 2229 2230 hr = IStorage_Commit( db->storage, 0 ); 2231 if (FAILED( hr )) 2232 { 2233 WARN("failed to commit changes 0x%08x\n", hr); 2234 r = ERROR_FUNCTION_FAILED; 2235 } 2236 return r; 2237 } 2238 2239 MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table ) 2240 { 2241 MSITABLE *t; 2242 UINT r; 2243 2244 TRACE("%p %s\n", db, debugstr_w(table)); 2245 2246 if (!table) 2247 return MSICONDITION_ERROR; 2248 2249 r = get_table( db, table, &t ); 2250 if (r != ERROR_SUCCESS) 2251 return MSICONDITION_NONE; 2252 2253 return t->persistent; 2254 } 2255 2256 static UINT read_raw_int(const BYTE *data, UINT col, UINT bytes) 2257 { 2258 UINT ret = 0, i; 2259 2260 for (i = 0; i < bytes; i++) 2261 ret += (data[col + i] << i * 8); 2262 2263 return ret; 2264 } 2265 2266 static UINT msi_record_encoded_stream_name( const MSITABLEVIEW *tv, MSIRECORD *rec, LPWSTR *pstname ) 2267 { 2268 LPWSTR stname = NULL, sval, p; 2269 DWORD len; 2270 UINT i, r; 2271 2272 TRACE("%p %p\n", tv, rec); 2273 2274 len = lstrlenW( tv->name ) + 1; 2275 stname = msi_alloc( len*sizeof(WCHAR) ); 2276 if ( !stname ) 2277 { 2278 r = ERROR_OUTOFMEMORY; 2279 goto err; 2280 } 2281 2282 lstrcpyW( stname, tv->name ); 2283 2284 for ( i = 0; i < tv->num_cols; i++ ) 2285 { 2286 if ( tv->columns[i].type & MSITYPE_KEY ) 2287 { 2288 sval = msi_dup_record_field( rec, i + 1 ); 2289 if ( !sval ) 2290 { 2291 r = ERROR_OUTOFMEMORY; 2292 goto err; 2293 } 2294 2295 len += lstrlenW( szDot ) + lstrlenW ( sval ); 2296 p = msi_realloc ( stname, len*sizeof(WCHAR) ); 2297 if ( !p ) 2298 { 2299 r = ERROR_OUTOFMEMORY; 2300 msi_free(sval); 2301 goto err; 2302 } 2303 stname = p; 2304 2305 lstrcatW( stname, szDot ); 2306 lstrcatW( stname, sval ); 2307 2308 msi_free( sval ); 2309 } 2310 else 2311 continue; 2312 } 2313 2314 *pstname = encode_streamname( FALSE, stname ); 2315 msi_free( stname ); 2316 2317 return ERROR_SUCCESS; 2318 2319 err: 2320 msi_free ( stname ); 2321 *pstname = NULL; 2322 return r; 2323 } 2324 2325 static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string_table *st, 2326 IStorage *stg, const BYTE *rawdata, UINT bytes_per_strref ) 2327 { 2328 UINT i, val, ofs = 0; 2329 USHORT mask; 2330 MSICOLUMNINFO *columns = tv->columns; 2331 MSIRECORD *rec; 2332 2333 mask = rawdata[0] | (rawdata[1] << 8); 2334 rawdata += 2; 2335 2336 rec = MSI_CreateRecord( tv->num_cols ); 2337 if( !rec ) 2338 return rec; 2339 2340 TRACE("row ->\n"); 2341 for( i=0; i<tv->num_cols; i++ ) 2342 { 2343 if ( (mask&1) && (i>=(mask>>8)) ) 2344 break; 2345 /* all keys must be present */ 2346 if ( (~mask&1) && (~columns[i].type & MSITYPE_KEY) && ((1<<i) & ~mask) ) 2347 continue; 2348 2349 if( MSITYPE_IS_BINARY(tv->columns[i].type) ) 2350 { 2351 LPWSTR encname; 2352 IStream *stm = NULL; 2353 UINT r; 2354 2355 ofs += bytes_per_column( tv->db, &columns[i], bytes_per_strref ); 2356 2357 r = msi_record_encoded_stream_name( tv, rec, &encname ); 2358 if ( r != ERROR_SUCCESS ) 2359 { 2360 msiobj_release( &rec->hdr ); 2361 return NULL; 2362 } 2363 r = IStorage_OpenStream( stg, encname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm ); 2364 if ( r != ERROR_SUCCESS ) 2365 { 2366 msiobj_release( &rec->hdr ); 2367 msi_free( encname ); 2368 return NULL; 2369 } 2370 2371 MSI_RecordSetStream( rec, i+1, stm ); 2372 TRACE(" field %d [%s]\n", i+1, debugstr_w(encname)); 2373 msi_free( encname ); 2374 } 2375 else if( columns[i].type & MSITYPE_STRING ) 2376 { 2377 int len; 2378 const WCHAR *sval; 2379 2380 val = read_raw_int(rawdata, ofs, bytes_per_strref); 2381 sval = msi_string_lookup( st, val, &len ); 2382 msi_record_set_string( rec, i+1, sval, len ); 2383 TRACE(" field %d [%s]\n", i+1, debugstr_wn(sval, len)); 2384 ofs += bytes_per_strref; 2385 } 2386 else 2387 { 2388 UINT n = bytes_per_column( tv->db, &columns[i], bytes_per_strref ); 2389 switch( n ) 2390 { 2391 case 2: 2392 val = read_raw_int(rawdata, ofs, n); 2393 if (val) 2394 MSI_RecordSetInteger( rec, i+1, val-0x8000 ); 2395 TRACE(" field %d [0x%04x]\n", i+1, val ); 2396 break; 2397 case 4: 2398 val = read_raw_int(rawdata, ofs, n); 2399 if (val) 2400 MSI_RecordSetInteger( rec, i+1, val^0x80000000 ); 2401 TRACE(" field %d [0x%08x]\n", i+1, val ); 2402 break; 2403 default: 2404 ERR("oops - unknown column width %d\n", n); 2405 break; 2406 } 2407 ofs += n; 2408 } 2409 } 2410 return rec; 2411 } 2412 2413 static void dump_table( const string_table *st, const USHORT *rawdata, UINT rawsize ) 2414 { 2415 UINT i; 2416 for (i = 0; i < rawsize / 2; i++) 2417 { 2418 int len; 2419 const WCHAR *sval = msi_string_lookup( st, rawdata[i], &len ); 2420 MESSAGE(" %04x %s\n", rawdata[i], debugstr_wn(sval, len) ); 2421 } 2422 } 2423 2424 static UINT* msi_record_to_row( const MSITABLEVIEW *tv, MSIRECORD *rec ) 2425 { 2426 UINT i, r, *data; 2427 2428 data = msi_alloc( tv->num_cols *sizeof (UINT) ); 2429 for( i=0; i<tv->num_cols; i++ ) 2430 { 2431 data[i] = 0; 2432 2433 if ( ~tv->columns[i].type & MSITYPE_KEY ) 2434 continue; 2435 2436 /* turn the transform column value into a row value */ 2437 if ( ( tv->columns[i].type & MSITYPE_STRING ) && 2438 ! MSITYPE_IS_BINARY(tv->columns[i].type) ) 2439 { 2440 int len; 2441 const WCHAR *str = msi_record_get_string( rec, i+1, &len ); 2442 if (str) 2443 { 2444 r = msi_string2id( tv->db->strings, str, len, &data[i] ); 2445 2446 /* if there's no matching string in the string table, 2447 these keys can't match any record, so fail now. */ 2448 if (r != ERROR_SUCCESS) 2449 { 2450 msi_free( data ); 2451 return NULL; 2452 } 2453 } 2454 else data[i] = 0; 2455 } 2456 else 2457 { 2458 data[i] = MSI_RecordGetInteger( rec, i+1 ); 2459 2460 if (data[i] == MSI_NULL_INTEGER) 2461 data[i] = 0; 2462 else if ((tv->columns[i].type&0xff) == 2) 2463 data[i] += 0x8000; 2464 else 2465 data[i] += 0x80000000; 2466 } 2467 } 2468 return data; 2469 } 2470 2471 static UINT msi_row_matches( MSITABLEVIEW *tv, UINT row, const UINT *data, UINT *column ) 2472 { 2473 UINT i, r, x, ret = ERROR_FUNCTION_FAILED; 2474 2475 for( i=0; i<tv->num_cols; i++ ) 2476 { 2477 if ( ~tv->columns[i].type & MSITYPE_KEY ) 2478 continue; 2479 2480 /* turn the transform column value into a row value */ 2481 r = TABLE_fetch_int( &tv->view, row, i+1, &x ); 2482 if ( r != ERROR_SUCCESS ) 2483 { 2484 ERR("TABLE_fetch_int shouldn't fail here\n"); 2485 break; 2486 } 2487 2488 /* if this key matches, move to the next column */ 2489 if ( x != data[i] ) 2490 { 2491 ret = ERROR_FUNCTION_FAILED; 2492 break; 2493 } 2494 if (column) *column = i; 2495 ret = ERROR_SUCCESS; 2496 } 2497 return ret; 2498 } 2499 2500 static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row, UINT *column ) 2501 { 2502 UINT i, r = ERROR_FUNCTION_FAILED, *data; 2503 2504 data = msi_record_to_row( tv, rec ); 2505 if( !data ) 2506 return r; 2507 for( i = 0; i < tv->table->row_count; i++ ) 2508 { 2509 r = msi_row_matches( tv, i, data, column ); 2510 if( r == ERROR_SUCCESS ) 2511 { 2512 *row = i; 2513 break; 2514 } 2515 } 2516 msi_free( data ); 2517 return r; 2518 } 2519 2520 typedef struct 2521 { 2522 struct list entry; 2523 LPWSTR name; 2524 } TRANSFORMDATA; 2525 2526 static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, 2527 string_table *st, TRANSFORMDATA *transform, 2528 UINT bytes_per_strref ) 2529 { 2530 BYTE *rawdata = NULL; 2531 MSITABLEVIEW *tv = NULL; 2532 UINT r, n, sz, i, mask, num_cols, colcol = 0, rawsize = 0; 2533 MSIRECORD *rec = NULL; 2534 WCHAR coltable[32]; 2535 const WCHAR *name; 2536 2537 if (!transform) 2538 return ERROR_SUCCESS; 2539 2540 name = transform->name; 2541 2542 coltable[0] = 0; 2543 TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) ); 2544 2545 /* read the transform data */ 2546 read_stream_data( stg, name, TRUE, &rawdata, &rawsize ); 2547 if ( !rawdata ) 2548 { 2549 TRACE("table %s empty\n", debugstr_w(name) ); 2550 return ERROR_INVALID_TABLE; 2551 } 2552 2553 /* create a table view */ 2554 r = TABLE_CreateView( db, name, (MSIVIEW**) &tv ); 2555 if( r != ERROR_SUCCESS ) 2556 goto err; 2557 2558 r = tv->view.ops->execute( &tv->view, NULL ); 2559 if( r != ERROR_SUCCESS ) 2560 goto err; 2561 2562 TRACE("name = %s columns = %u row_size = %u raw size = %u\n", 2563 debugstr_w(name), tv->num_cols, tv->row_size, rawsize ); 2564 2565 /* interpret the data */ 2566 for (n = 0; n < rawsize;) 2567 { 2568 mask = rawdata[n] | (rawdata[n + 1] << 8); 2569 if (mask & 1) 2570 { 2571 /* 2572 * if the low bit is set, columns are continuous and 2573 * the number of columns is specified in the high byte 2574 */ 2575 sz = 2; 2576 num_cols = mask >> 8; 2577 if (num_cols > tv->num_cols) 2578 { 2579 ERR("excess columns in transform: %u > %u\n", num_cols, tv->num_cols); 2580 break; 2581 } 2582 2583 for (i = 0; i < num_cols; i++) 2584 { 2585 if( (tv->columns[i].type & MSITYPE_STRING) && 2586 ! MSITYPE_IS_BINARY(tv->columns[i].type) ) 2587 sz += bytes_per_strref; 2588 else 2589 sz += bytes_per_column( tv->db, &tv->columns[i], bytes_per_strref ); 2590 } 2591 } 2592 else 2593 { 2594 /* 2595 * If the low bit is not set, mask is a bitmask. 2596 * Excepting for key fields, which are always present, 2597 * each bit indicates that a field is present in the transform record. 2598 * 2599 * mask == 0 is a special case ... only the keys will be present 2600 * and it means that this row should be deleted. 2601 */ 2602 sz = 2; 2603 num_cols = tv->num_cols; 2604 for (i = 0; i < num_cols; i++) 2605 { 2606 if ((tv->columns[i].type & MSITYPE_KEY) || ((1 << i) & mask)) 2607 { 2608 if ((tv->columns[i].type & MSITYPE_STRING) && 2609 !MSITYPE_IS_BINARY(tv->columns[i].type)) 2610 sz += bytes_per_strref; 2611 else 2612 sz += bytes_per_column( tv->db, &tv->columns[i], bytes_per_strref ); 2613 } 2614 } 2615 } 2616 2617 /* check we didn't run of the end of the table */ 2618 if (n + sz > rawsize) 2619 { 2620 ERR("borked.\n"); 2621 dump_table( st, (USHORT *)rawdata, rawsize ); 2622 break; 2623 } 2624 2625 rec = msi_get_transform_record( tv, st, stg, &rawdata[n], bytes_per_strref ); 2626 if (rec) 2627 { 2628 WCHAR table[32]; 2629 DWORD sz = 32; 2630 UINT number = MSI_NULL_INTEGER; 2631 UINT row = 0; 2632 2633 if (!strcmpW( name, szColumns )) 2634 { 2635 MSI_RecordGetStringW( rec, 1, table, &sz ); 2636 number = MSI_RecordGetInteger( rec, 2 ); 2637 2638 /* 2639 * Native msi seems writes nul into the Number (2nd) column of 2640 * the _Columns table when there are new columns 2641 */ 2642 if ( number == MSI_NULL_INTEGER ) 2643 { 2644 /* reset the column number on a new table */ 2645 if (strcmpW( coltable, table )) 2646 { 2647 colcol = 0; 2648 lstrcpyW( coltable, table ); 2649 } 2650 2651 /* fix nul column numbers */ 2652 MSI_RecordSetInteger( rec, 2, ++colcol ); 2653 } 2654 } 2655 2656 if (TRACE_ON(msidb)) dump_record( rec ); 2657 2658 r = msi_table_find_row( tv, rec, &row, NULL ); 2659 if (r == ERROR_SUCCESS) 2660 { 2661 if (!mask) 2662 { 2663 TRACE("deleting row [%d]:\n", row); 2664 r = TABLE_delete_row( &tv->view, row ); 2665 if (r != ERROR_SUCCESS) 2666 WARN("failed to delete row %u\n", r); 2667 } 2668 else if (mask & 1) 2669 { 2670 TRACE("modifying full row [%d]:\n", row); 2671 r = TABLE_set_row( &tv->view, row, rec, (1 << tv->num_cols) - 1 ); 2672 if (r != ERROR_SUCCESS) 2673 WARN("failed to modify row %u\n", r); 2674 } 2675 else 2676 { 2677 TRACE("modifying masked row [%d]:\n", row); 2678 r = TABLE_set_row( &tv->view, row, rec, mask ); 2679 if (r != ERROR_SUCCESS) 2680 WARN("failed to modify row %u\n", r); 2681 } 2682 } 2683 else 2684 { 2685 TRACE("inserting row\n"); 2686 r = TABLE_insert_row( &tv->view, rec, -1, FALSE ); 2687 if (r != ERROR_SUCCESS) 2688 WARN("failed to insert row %u\n", r); 2689 } 2690 2691 if (!strcmpW( name, szColumns )) 2692 msi_update_table_columns( db, table ); 2693 2694 msiobj_release( &rec->hdr ); 2695 } 2696 2697 n += sz; 2698 } 2699 2700 err: 2701 /* no need to free the table, it's associated with the database */ 2702 msi_free( rawdata ); 2703 if( tv ) 2704 tv->view.ops->delete( &tv->view ); 2705 2706 return ERROR_SUCCESS; 2707 } 2708 2709 /* 2710 * msi_table_apply_transform 2711 * 2712 * Enumerate the table transforms in a transform storage and apply each one. 2713 */ 2714 UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg ) 2715 { 2716 struct list transforms; 2717 IEnumSTATSTG *stgenum = NULL; 2718 TRANSFORMDATA *transform; 2719 TRANSFORMDATA *tables = NULL, *columns = NULL; 2720 HRESULT hr; 2721 STATSTG stat; 2722 string_table *strings; 2723 UINT ret = ERROR_FUNCTION_FAILED; 2724 UINT bytes_per_strref; 2725 BOOL property_update = FALSE; 2726 2727 TRACE("%p %p\n", db, stg ); 2728 2729 strings = msi_load_string_table( stg, &bytes_per_strref ); 2730 if( !strings ) 2731 goto end; 2732 2733 hr = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum ); 2734 if (FAILED( hr )) 2735 goto end; 2736 2737 list_init(&transforms); 2738 2739 while ( TRUE ) 2740 { 2741 MSITABLEVIEW *tv = NULL; 2742 WCHAR name[0x40]; 2743 ULONG count = 0; 2744 2745 hr = IEnumSTATSTG_Next( stgenum, 1, &stat, &count ); 2746 if (FAILED( hr ) || !count) 2747 break; 2748 2749 decode_streamname( stat.pwcsName, name ); 2750 CoTaskMemFree( stat.pwcsName ); 2751 if ( name[0] != 0x4840 ) 2752 continue; 2753 2754 if ( !strcmpW( name+1, szStringPool ) || 2755 !strcmpW( name+1, szStringData ) ) 2756 continue; 2757 2758 transform = msi_alloc_zero( sizeof(TRANSFORMDATA) ); 2759 if ( !transform ) 2760 break; 2761 2762 list_add_tail( &transforms, &transform->entry ); 2763 2764 transform->name = strdupW( name + 1 ); 2765 2766 if ( !strcmpW( transform->name, szTables ) ) 2767 tables = transform; 2768 else if (!strcmpW( transform->name, szColumns ) ) 2769 columns = transform; 2770 else if (!strcmpW( transform->name, szProperty )) 2771 property_update = TRUE; 2772 2773 TRACE("transform contains stream %s\n", debugstr_w(name)); 2774 2775 /* load the table */ 2776 if (TABLE_CreateView( db, transform->name, (MSIVIEW**) &tv ) != ERROR_SUCCESS) 2777 continue; 2778 2779 if (tv->view.ops->execute( &tv->view, NULL ) != ERROR_SUCCESS) 2780 { 2781 tv->view.ops->delete( &tv->view ); 2782 continue; 2783 } 2784 2785 tv->view.ops->delete( &tv->view ); 2786 } 2787 2788 /* 2789 * Apply _Tables and _Columns transforms first so that 2790 * the table metadata is correct, and empty tables exist. 2791 */ 2792 ret = msi_table_load_transform( db, stg, strings, tables, bytes_per_strref ); 2793 if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE) 2794 goto end; 2795 2796 ret = msi_table_load_transform( db, stg, strings, columns, bytes_per_strref ); 2797 if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE) 2798 goto end; 2799 2800 ret = ERROR_SUCCESS; 2801 2802 while ( !list_empty( &transforms ) ) 2803 { 2804 transform = LIST_ENTRY( list_head( &transforms ), TRANSFORMDATA, entry ); 2805 2806 if ( strcmpW( transform->name, szColumns ) && 2807 strcmpW( transform->name, szTables ) && 2808 ret == ERROR_SUCCESS ) 2809 { 2810 ret = msi_table_load_transform( db, stg, strings, transform, bytes_per_strref ); 2811 } 2812 2813 list_remove( &transform->entry ); 2814 msi_free( transform->name ); 2815 msi_free( transform ); 2816 } 2817 2818 if ( ret == ERROR_SUCCESS ) 2819 { 2820 append_storage_to_db( db, stg ); 2821 if (property_update) msi_clone_properties( db ); 2822 } 2823 2824 end: 2825 if ( stgenum ) 2826 IEnumSTATSTG_Release( stgenum ); 2827 if ( strings ) 2828 msi_destroy_stringtable( strings ); 2829 2830 return ret; 2831 } 2832