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