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