ReactOS  0.4.14-dev-50-g13bb5e2
table.c
Go to the documentation of this file.
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 
41 
42 #define MSITABLE_HASH_TABLE_SIZE 37
43 
44 typedef struct tagMSICOLUMNHASHENTRY
45 {
50 
51 typedef struct tagMSICOLUMNINFO
52 {
62 
64 {
68  struct list entry;
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 
129 {
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 
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 
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 
243  BYTE **pdata, UINT *psz )
244 {
245  HRESULT r;
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);
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 
307  LPCVOID data, UINT sz, BOOL bTable )
308 {
309  HRESULT r;
311  ULONG count;
312  IStream *stm = NULL;
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 */
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 
481 {
482  while( !list_empty( &db->tables ) )
483  {
485 
486  list_remove( &t->entry );
487  free_table( t );
488  }
489 }
490 
492 {
493  MSITABLE *t;
494 
496  if( !strcmpW( name, t->name ) )
497  return t;
498 
499  return NULL;
500 }
501 
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 
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 
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)
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 
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;
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  {
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 
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 */
972 {
973  UINT r, table_id, i;
974  MSITABLE *table;
975 
976  if( !strcmpW( name, szTables ) || !strcmpW( name, szColumns ) ||
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 {
1014 } MSITABLEVIEW;
1015 
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  {
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 );
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 
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 
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 
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 {
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 
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 
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 
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 
1544 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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;
1805  r = table_validate_new( tv, rec, &column );
1806  if (r != ERROR_SUCCESS)
1807  {
1809  tv->view.error_column = tv->columns[column].colname;
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 
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:
1855  FIXME("%p %d %p - mode not implemented\n", view, eModifyMode, rec );
1857  break;
1858 
1859  default:
1861  }
1862 
1863  return r;
1864 }
1865 
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 
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;
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 */
1911  num_rows * sizeof(MSICOLUMNHASHENTRY));
1912  if (!hash_table)
1913  return ERROR_OUTOFMEMORY;
1914 
1916  tv->columns[col-1].hash_table = hash_table;
1917 
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 )
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 
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)
1970  }
1971 
1972  return InterlockedIncrement(&tv->table->ref_count);
1973 }
1974 
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 
2005 
2006 done:
2007  msiobj_release(&rec->hdr);
2008  columns->ops->delete(columns);
2009  return r;
2010 }
2011 
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  {
2025  if (ref == 0)
2026  {
2028  tv->table->colinfo[i].number);
2029  if (r != ERROR_SUCCESS)
2030  break;
2031  }
2032  }
2033  }
2034 
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 
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 
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 
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  {
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 
2122  if (r != ERROR_SUCCESS)
2123  goto done;
2124 
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 {
2143  TABLE_get_row,
2144  TABLE_set_row,
2147  TABLE_execute,
2148  TABLE_close,
2151  TABLE_modify,
2152  TABLE_delete,
2154  TABLE_add_ref,
2155  TABLE_release,
2158  NULL,
2159  TABLE_drop,
2160 };
2161 
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;
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 
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 
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);
2235  }
2236  return r;
2237 }
2238 
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 
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 
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 
2472 {
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  {
2492  break;
2493  }
2494  if (column) *column = i;
2495  ret = ERROR_SUCCESS;
2496  }
2497  return ret;
2498 }
2499 
2501 {
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;
2524 } TRANSFORMDATA;
2525 
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;
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 ))
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  */
2715 {
2716  struct list transforms;
2717  IEnumSTATSTG *stgenum = NULL;
2719  TRANSFORMDATA *tables = NULL, *columns = NULL;
2720  HRESULT hr;
2721  STATSTG stat;
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 );
2794  goto end;
2795 
2796  ret = msi_table_load_transform( db, stg, strings, columns, bytes_per_strref );
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 )
2829 
2830  return ret;
2831 }
static int mime2utf(int x)
Definition: table.c:174
const WCHAR * msi_string_lookup(const string_table *st, UINT id, int *len) DECLSPEC_HIDDEN
Definition: string.c:347
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
StringPersistence
Definition: msipriv.h:757
static UINT TABLE_execute(struct tagMSIVIEW *view, MSIRECORD *record)
Definition: table.c:1473
static UINT TABLE_get_row(struct tagMSIVIEW *view, UINT row, MSIRECORD **rec)
Definition: table.c:1205
LPCWSTR tablename
Definition: table.c:53
static UINT TABLE_find_matching_rows(struct tagMSIVIEW *view, UINT col, UINT val, UINT *row, MSIITERHANDLE *handle)
Definition: table.c:1880
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
UINT msi_get_stream(MSIDATABASE *, const WCHAR *, IStream **) DECLSPEC_HIDDEN
Definition: streams.c:518
UINT number
Definition: table.c:54
#define TRUE
Definition: types.h:120
MSICOLUMNINFO * colinfo
Definition: table.c:69
void MSI_CloseRecord(MSIOBJECTHDR *) DECLSPEC_HIDDEN
Definition: record.c:70
UINT MSI_RecordSetStringW(MSIRECORD *, UINT, LPCWSTR) DECLSPEC_HIDDEN
Definition: record.c:649
static UINT get_tablecolumns(MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz)
Definition: table.c:639
static UINT * msi_record_to_row(const MSITABLEVIEW *tv, MSIRECORD *rec)
Definition: table.c:2424
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:422
UINT MSI_RecordCopyField(MSIRECORD *, UINT, MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:169
static UINT TABLE_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary)
Definition: table.c:1647
#define ERROR_SUCCESS
Definition: deptool.c:10
const WCHAR * name
static UINT TABLE_remove_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number)
Definition: table.c:1975
HRESULT hr
Definition: shlfolder.c:183
#define MESSAGE
Definition: options.h:86
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
UINT MSI_CommitTables(MSIDATABASE *db)
Definition: table.c:2204
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:95
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:922
struct tagMSICOLUMNHASHENTRY * next
Definition: table.c:46
static UINT get_stream_name(const MSITABLEVIEW *tv, UINT row, WCHAR **pstname)
Definition: table.c:1053
static WCHAR * strdupW(const WCHAR *src)
Definition: main.c:92
static UINT msi_table_get_row_size(MSIDATABASE *db, const MSICOLUMNINFO *cols, UINT count, UINT bytes_per_strref)
Definition: table.c:384
static MSIRECORD * msi_get_transform_record(const MSITABLEVIEW *tv, const string_table *st, IStorage *stg, const BYTE *rawdata, UINT bytes_per_strref)
Definition: table.c:2325
MSIOBJECTHDR hdr
Definition: msipriv.h:141
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
LPWSTR name
Definition: table.c:2523
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define WARN(fmt,...)
Definition: debug.h:111
UINT MSI_RecordGetStringW(MSIRECORD *, UINT, LPWSTR, LPDWORD) DECLSPEC_HIDDEN
Definition: record.c:487
static UINT msi_refresh_record(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row)
Definition: table.c:1771
UINT MSI_ViewExecute(MSIQUERY *, MSIRECORD *) DECLSPEC_HIDDEN
Definition: msiquery.c:443
static UINT TABLE_get_column_info(struct tagMSIVIEW *view, UINT n, LPCWSTR *name, UINT *type, BOOL *temporary, LPCWSTR *table_name)
Definition: table.c:1509
GLintptr offset
Definition: glext.h:5920
UINT msi_create_table(MSIDATABASE *db, LPCWSTR name, column_info *col_info, MSICONDITION persistent)
Definition: table.c:716
__WINE_SERVER_LIST_INLINE void list_add_head(struct list *list, struct list *elem)
Definition: list.h:96
static UINT read_table_from_storage(MSIDATABASE *db, MSITABLE *t, IStorage *stg)
Definition: table.c:402
UINT MSI_RecordGetIStream(MSIRECORD *, UINT, IStream **) DECLSPEC_HIDDEN
Definition: record.c:905
GLdouble n
Definition: glext.h:7729
static const MSICOLUMNINFO _Columns_cols[4]
Definition: table.c:83
GLdouble GLdouble t
Definition: gl.h:2047
static const WCHAR szNumber[]
Definition: table.c:80
static const MSICOLUMNINFO _Tables_cols[1]
Definition: table.c:90
#define MSITABLE_HASH_TABLE_SIZE
Definition: table.c:42
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define assert(x)
Definition: debug.h:53
#define MSITYPE_IS_BINARY(type)
Definition: msipriv.h:59
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glext.h:5644
#define LONG_STR_BYTES
Definition: msipriv.h:54
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
MSIDATABASE * db
Definition: table.c:1008
struct tagMSICOLUMNHASHENTRY MSICOLUMNHASHENTRY
static UINT TABLE_delete(struct tagMSIVIEW *view)
Definition: table.c:1866
MSITABLE * table
Definition: table.c:1009
#define MSI_NULL_INTEGER
Definition: msiquery.h:32
struct _column_info * next
Definition: msipriv.h:216
UINT col_count
Definition: table.c:70
BOOL msi_add_string(string_table *st, const WCHAR *data, int len, enum StringPersistence persistence) DECLSPEC_HIDDEN
Definition: string.c:307
static UINT msi_row_matches(MSITABLEVIEW *tv, UINT row, const UINT *data, UINT *column)
Definition: table.c:2471
GLuint GLuint end
Definition: gl.h:1545
static int insert
Definition: xmllint.c:144
string_table * msi_load_string_table(IStorage *stg, UINT *bytes_per_strref) DECLSPEC_HIDDEN
Definition: string.c:482
UINT(* execute)(struct tagMSIVIEW *view, MSIRECORD *record)
Definition: msipriv.h:268
#define MSITYPE_STRING
Definition: msipriv.h:47
struct tagMSITABLEVIEW MSITABLEVIEW
static UINT get_defaulttablecolumns(MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz)
Definition: table.c:519
#define lstrlenW
Definition: compat.h:407
int32_t INT
Definition: typedefs.h:56
static void * msi_realloc(void *mem, size_t len) __WINE_ALLOC_SIZE(2)
Definition: msipriv.h:1216
Definition: send.c:47
#define MAX_STREAM_NAME
Definition: table.c:94
const GLfloat * m
Definition: glext.h:10848
static UINT TABLE_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *cols)
Definition: table.c:1491
static void * msi_alloc_zero(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1210
static UINT get_table_value_from_record(MSITABLEVIEW *tv, MSIRECORD *rec, UINT iField, UINT *pvalue)
Definition: table.c:1276
static UINT msi_table_find_row(MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row, UINT *column)
Definition: table.c:2500
__WINE_SERVER_LIST_INLINE struct list * list_head(const struct list *list)
Definition: list.h:131
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
BYTE ** data
Definition: table.c:65
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
UINT MSI_RecordSetInteger(MSIRECORD *, UINT, int) DECLSPEC_HIDDEN
Definition: record.c:328
VOID msi_destroy_stringtable(string_table *st) DECLSPEC_HIDDEN
Definition: string.c:108
GLenum GLint GLuint mask
Definition: glext.h:6028
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:985
UINT STORAGES_CreateView(MSIDATABASE *db, MSIVIEW **view) DECLSPEC_HIDDEN
Definition: storages.c:528
static unsigned char bytes[4]
Definition: adnsresfilter.c:74
BOOL * data_persistent
Definition: table.c:66
void free_cached_tables(MSIDATABASE *db)
Definition: table.c:480
unsigned int BOOL
Definition: ntddk_ex.h:94
string_table * strings
Definition: msipriv.h:99
static struct file_hash * hash_table[NR_HASH]
Definition: hash.c:60
BOOL MSI_RecordIsNull(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:369
static size_t double number
Definition: printf.c:64
static UINT table_get_column_info(MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount)
Definition: table.c:550
UINT read_stream_data(IStorage *stg, LPCWSTR stname, BOOL table, BYTE **pdata, UINT *psz)
Definition: table.c:242
BOOL temporary
Definition: table.c:59
static void dump_table(const string_table *st, const USHORT *rawdata, UINT rawsize)
Definition: table.c:2413
#define debugstr_w
Definition: kernel32.h:32
GLenum GLint ref
Definition: glext.h:6028
#define FIXME(fmt,...)
Definition: debug.h:110
struct list entry
unsigned int idx
Definition: utils.c:41
const WCHAR * str
static UINT bytes_per_column(MSIDATABASE *db, const MSICOLUMNINFO *col, UINT bytes_per_strref)
Definition: table.c:96
struct list tables
Definition: msipriv.h:107
UINT msi_clone_properties(MSIDATABASE *) DECLSPEC_HIDDEN
Definition: package.c:377
smooth NULL
Definition: ftsmooth.c:416
#define STGM_WRITE
Definition: objbase.h:917
UINT row_count
Definition: table.c:67
#define MSITYPE_NULLABLE
Definition: msipriv.h:48
static UINT table_create_new_row(struct tagMSIVIEW *view, UINT *num, BOOL temporary)
Definition: table.c:1414
static const MSIVIEWOPS table_ops
Definition: table.c:2139
static UINT msi_table_load_transform(MSIDATABASE *db, IStorage *stg, string_table *st, TRANSFORMDATA *transform, UINT bytes_per_strref)
Definition: table.c:2526
INT ref_count
Definition: table.c:72
MSIVIEW view
Definition: table.c:1007
static PROTOCOLDATA * pdata
Definition: protocol.c:157
#define b
Definition: ke_i.h:79
GLuint GLfloat * val
Definition: glext.h:7180
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
void append_storage_to_db(MSIDATABASE *db, IStorage *stg)
Definition: database.c:84
#define STGM_READ
Definition: objbase.h:916
static UINT msi_record_encoded_stream_name(const MSITABLEVIEW *tv, MSIRECORD *rec, LPWSTR *pstname)
Definition: table.c:2266
static UINT TABLE_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask)
Definition: table.c:1328
MSICOLUMNINFO * columns
Definition: table.c:1010
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
void dump_record(MSIRECORD *) DECLSPEC_HIDDEN
Definition: record.c:1081
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
#define TRACE(s)
Definition: solgame.cpp:4
struct list entry
Definition: table.c:68
static UINT TABLE_drop(struct tagMSIVIEW *view)
Definition: table.c:2090
UINT bytes_per_strref
Definition: msipriv.h:100
GLsizeiptr size
Definition: glext.h:5919
WCHAR name[1]
Definition: table.c:1013
static UINT read_raw_int(const BYTE *data, UINT col, UINT bytes)
Definition: table.c:2256
__wchar_t WCHAR
Definition: xmlstorage.h:180
const MSIVIEWOPS * ops
Definition: msipriv.h:348
LONG HRESULT
Definition: typedefs.h:77
static UINT TABLE_fetch_stream(struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
Definition: table.c:1144
UINT msi_string2id(const string_table *st, const WCHAR *data, int len, UINT *id) DECLSPEC_HIDDEN
Definition: string.c:404
LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
Definition: table.c:128
static UINT msi_table_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row)
Definition: table.c:1718
static const WCHAR szStorages[]
Definition: msipriv.h:1179
static const WCHAR szColumns[]
Definition: table.c:79
const GLubyte * c
Definition: glext.h:8905
UINT TABLE_CreateView(MSIDATABASE *db, LPCWSTR name, MSIVIEW **view)
Definition: table.c:2162
int JSAMPARRAY int int num_rows
Definition: jpegint.h:412
static FILE * out
Definition: regtests2xml.c:44
static UINT modify_delete_row(struct tagMSIVIEW *view, MSIRECORD *rec)
Definition: table.c:1759
unsigned long DWORD
Definition: ntddk_ex.h:95
static int find_insert_index(MSITABLEVIEW *tv, MSIRECORD *rec)
Definition: table.c:1622
GLuint GLuint num
Definition: glext.h:9618
UINT write_stream_data(IStorage *stg, LPCWSTR stname, LPCVOID data, UINT sz, BOOL bTable)
Definition: table.c:306
int JSAMPARRAY int int JDIMENSION num_cols
Definition: jpegint.h:412
static int utf2mime(int x)
Definition: table.c:113
#define MSITYPE_KEY
Definition: msipriv.h:49
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
int msiobj_release(MSIOBJECTHDR *info)
Definition: handle.c:242
static void table_calc_column_offsets(MSIDATABASE *db, MSICOLUMNINFO *colinfo, DWORD count)
Definition: table.c:502
static UINT TABLE_add_ref(struct tagMSIVIEW *view)
Definition: table.c:1959
int ret
void enum_stream_names(IStorage *stg)
Definition: table.c:213
MSIRECORD * MSI_CreateRecord(UINT) DECLSPEC_HIDDEN
Definition: record.c:79
GLsizei const GLchar *const * strings
Definition: glext.h:7622
static const WCHAR szStringPool[]
Definition: msipriv.h:1189
static const WCHAR szTables[]
Definition: table.c:77
UINT MSI_RecordSetStream(MSIRECORD *, UINT, IStream *) DECLSPEC_HIDDEN
Definition: record.c:724
#define InterlockedDecrement
Definition: armddk.h:52
static UINT add_stream(MSIDATABASE *db, const WCHAR *name, IStream *data)
Definition: table.c:1215
static UINT read_table_int(BYTE *const *data, UINT row, UINT col, UINT bytes)
Definition: table.c:629
static UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret)
Definition: table.c:583
static const WCHAR szDot[]
Definition: msipriv.h:1113
Definition: stat.h:55
uint32_t entry
Definition: isohybrid.c:63
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
unsigned char BYTE
Definition: mem.h:68
int MSICONDITION
Definition: msiserver.idl:33
Definition: _list.h:228
UINT row_size
Definition: table.c:1012
#define err(...)
UINT msi_save_string_table(const string_table *st, IStorage *storage, UINT *bytes_per_strref) DECLSPEC_HIDDEN
Definition: string.c:568
#define debugstr_wn
Definition: kernel32.h:33
static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number, LPCWSTR column, UINT type, BOOL hold)
Definition: table.c:2049
static UINT TABLE_modify(struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRECORD *rec, UINT row)
Definition: table.c:1791
static UINT msi_table_assign(struct tagMSIVIEW *view, MSIRECORD *rec)
Definition: table.c:1744
UINT MSI_RecordSetIStream(MSIRECORD *, UINT, IStream *) DECLSPEC_HIDDEN
Definition: record.c:889
MSICONDITION persistent
Definition: table.c:71
#define ERROR_INVALID_DATA
Definition: winerror.h:116
static void msi_free_colinfo(MSICOLUMNINFO *colinfo, UINT count)
Definition: table.c:366
int MSI_RecordGetInteger(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:245
const WCHAR * msi_record_get_string(const MSIRECORD *, UINT, int *) DECLSPEC_HIDDEN
Definition: record.c:469
#define ERR(fmt,...)
Definition: debug.h:109
static UINT TABLE_set_int(MSITABLEVIEW *tv, UINT row, UINT col, UINT val)
Definition: table.c:1168
#define ERROR_INVALID_TABLE
Definition: winerror.h:986
static void free_table(MSITABLE *table)
Definition: table.c:372
UINT(* delete)(struct tagMSIVIEW *)
Definition: msipriv.h:299
__WINE_SERVER_LIST_INLINE int list_empty(const struct list *list)
Definition: list.h:143
_CRTIMP int __cdecl stat(const char *_Filename, struct stat *_Stat)
Definition: stat.h:345
UINT offset
Definition: table.c:57
static unsigned __int64 next
Definition: rand_nt.c:6
#define InterlockedIncrement
Definition: armddk.h:53
static UINT TABLE_delete_row(struct tagMSIVIEW *view, UINT row)
Definition: table.c:1680
static UINT TABLE_close(struct tagMSIVIEW *view)
Definition: table.c:1484
#define lstrcpyW
Definition: compat.h:406
GLuint in
Definition: glext.h:9616
const WCHAR * error_column
Definition: msipriv.h:350
#define MSITYPE_TEMPORARY
Definition: msipriv.h:50
unsigned short USHORT
Definition: pedump.c:61
BYTE * data
WCHAR * msi_dup_record_field(MSIRECORD *row, INT index) DECLSPEC_HIDDEN
Definition: record.c:1055
MSICOLUMNHASHENTRY ** hash_table
Definition: table.c:60
static const WCHAR szProperty[]
Definition: msipriv.h:1198
#define sprintfW
Definition: unicode.h:58
UINT STREAMS_CreateView(MSIDATABASE *db, MSIVIEW **view) DECLSPEC_HIDDEN
Definition: streams.c:558
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
BOOL decode_streamname(LPCWSTR in, LPWSTR out)
Definition: table.c:187
UINT msi_table_apply_transform(MSIDATABASE *db, IStorage *stg)
Definition: table.c:2714
enum tagMSIMODIFY MSIMODIFY
unsigned int UINT
Definition: ndis.h:50
UINT msi_record_set_string(MSIRECORD *, UINT, const WCHAR *, int) DECLSPEC_HIDDEN
Definition: record.c:625
#define MSITYPE_VALID
Definition: msipriv.h:45
static const WCHAR szStreams[]
Definition: msipriv.h:1178
UINT msi_view_get_row(MSIDATABASE *, MSIVIEW *, UINT, MSIRECORD **) DECLSPEC_HIDDEN
Definition: msiquery.c:287
#define ERROR_NOT_FOUND
Definition: winerror.h:690
static UINT TABLE_release(struct tagMSIVIEW *view)
Definition: table.c:2012
static const WCHAR szStringData[]
Definition: msipriv.h:1188
CONST void * LPCVOID
Definition: windef.h:191
static BOOL msi_free(void *mem)
Definition: msipriv.h:1227
Definition: name.c:36
static const WCHAR szName[]
Definition: msipriv.h:1194
WINE_UNICODE_INLINE int strcmpW(const WCHAR *str1, const WCHAR *str2)
Definition: unicode.h:229
static UINT TABLE_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT *val)
Definition: table.c:1016
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
#define c
Definition: ke_i.h:80
static void * msi_alloc(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1204
unsigned int ULONG
Definition: retypes.h:1
INT ref_count
Definition: table.c:58
struct nls_table * tables
Definition: nls_base.c:22
#define ERROR_CALL_NOT_IMPLEMENTED
Definition: compat.h:92
GLuint GLenum GLenum transform
Definition: glext.h:9407
static UINT save_table(MSIDATABASE *db, const MSITABLE *t, UINT bytes_per_strref)
Definition: table.c:869
static UINT table_validate_new(MSITABLEVIEW *tv, MSIRECORD *rec, UINT *column)
Definition: table.c:1545
LPCWSTR colname
Definition: table.c:55
IStorage * storage
Definition: msipriv.h:98
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
GLenum GLenum GLvoid GLvoid * column
Definition: glext.h:5664
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
UINT num_cols
Definition: table.c:1011
#define LIST_ENTRY(type)
Definition: queue.h:175
struct tagMSICOLUMNINFO MSICOLUMNINFO
#define memset(x, y, z)
Definition: compat.h:39
#define TRACE_ON(x)
Definition: compat.h:65
WINE_DEFAULT_DEBUG_CHANNEL(msidb)
int k
Definition: mpi.c:3369
GLenum query
Definition: glext.h:7781
Definition: dsound.c:943
static const WCHAR szType[]
Definition: table.c:81
#define ERROR_BAD_QUERY_SYNTAX
Definition: winerror.h:973
static MSITABLE * find_cached_table(MSIDATABASE *db, LPCWSTR name)
Definition: table.c:491
BOOL TABLE_Exists(MSIDATABASE *db, LPCWSTR name)
Definition: table.c:971
static const WCHAR szTable[]
Definition: table.c:78
MSIDBERROR error
Definition: msipriv.h:349
UINT MSI_RecordGetFieldCount(const MSIRECORD *rec) DECLSPEC_HIDDEN
Definition: record.c:111
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
struct png_info_def *typedef unsigned char **typedef struct png_info_def *typedef struct png_info_def *typedef struct png_info_def *typedef unsigned char ** row
Definition: typeof.h:78
WCHAR * name
Definition: name.c:40
UINT(* insert_row)(struct tagMSIVIEW *view, MSIRECORD *record, UINT row, BOOL temporary)
Definition: msipriv.h:258
static void msi_update_table_columns(MSIDATABASE *db, LPCWSTR name)
Definition: table.c:944
static int compare_record(MSITABLEVIEW *tv, UINT row, MSIRECORD *rec)
Definition: table.c:1589
MSICONDITION MSI_DatabaseIsTablePersistent(MSIDATABASE *db, LPCWSTR table)
Definition: table.c:2239
UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY **) DECLSPEC_HIDDEN
Definition: msiquery.c:111
GLuint const GLchar * name
Definition: glext.h:6031