msi: Fix the character count passed into RegSetValueExA in test_MsiQueryFeatureState.
[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, 0, NULL },
109     { szColumns, 2, szNumber, MSITYPE_VALID | MSITYPE_KEY | 2,     2, 0, NULL },
110     { szColumns, 3, szName,   MSITYPE_VALID | MSITYPE_STRING | 64, 4, 0, NULL },
111     { szColumns, 4, szType,   MSITYPE_VALID | 2,                   6, 0, NULL },
112 };
113 static MSICOLUMNINFO _Tables_cols[1] = {
114     { szTables,  1, szName,   MSITYPE_VALID | MSITYPE_STRING | 64, 0, 0, NULL },
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     UINT 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     UINT 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     /* reset the hash tables */
1576     for (i = 0; i < tv->num_cols; i++)
1577     {
1578         msi_free( tv->columns[i].hash_table );
1579         tv->columns[i].hash_table = NULL;
1580     }
1581
1582     if ( row == num_rows - 1 )
1583         return ERROR_SUCCESS;
1584
1585     for (i = row + 1; i < num_rows; i++)
1586         memcpy(data[i - 1], data[i], tv->row_size);
1587
1588     return ERROR_SUCCESS;
1589 }
1590
1591 static UINT msi_table_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row)
1592 {
1593     MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
1594     UINT r, new_row;
1595
1596     /* FIXME: MsiViewFetch should set rec index 0 to some ID that
1597      * sets the fetched record apart from other records
1598      */
1599
1600     if (!tv->table)
1601         return ERROR_INVALID_PARAMETER;
1602
1603     r = msi_table_find_row(tv, rec, &new_row);
1604     if (r != ERROR_SUCCESS)
1605     {
1606         ERR("can't find row to modify\n");
1607         return ERROR_FUNCTION_FAILED;
1608     }
1609
1610     /* the row cannot be changed */
1611     if (row != new_row + 1)
1612         return ERROR_FUNCTION_FAILED;
1613
1614     return TABLE_set_row(view, new_row, rec, (1 << tv->num_cols) - 1);
1615 }
1616
1617 static UINT modify_delete_row( struct tagMSIVIEW *view, MSIRECORD *rec )
1618 {
1619     MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
1620     UINT row, r;
1621
1622     r = msi_table_find_row(tv, rec, &row);
1623     if (r != ERROR_SUCCESS)
1624         return r;
1625
1626     return TABLE_delete_row(view, row);
1627 }
1628
1629 static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
1630                           MSIRECORD *rec, UINT row)
1631 {
1632     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1633     UINT r;
1634
1635     TRACE("%p %d %p\n", view, eModifyMode, rec );
1636
1637     switch (eModifyMode)
1638     {
1639     case MSIMODIFY_DELETE:
1640         r = modify_delete_row( view, rec );
1641         break;
1642     case MSIMODIFY_VALIDATE_NEW:
1643         r = table_validate_new( tv, rec );
1644         break;
1645
1646     case MSIMODIFY_INSERT:
1647         r = table_validate_new( tv, rec );
1648         if (r != ERROR_SUCCESS)
1649             break;
1650         r = TABLE_insert_row( view, rec, FALSE );
1651         break;
1652
1653     case MSIMODIFY_INSERT_TEMPORARY:
1654         r = table_validate_new( tv, rec );
1655         if (r != ERROR_SUCCESS)
1656             break;
1657         r = TABLE_insert_row( view, rec, TRUE );
1658         break;
1659
1660     case MSIMODIFY_UPDATE:
1661         r = msi_table_update( view, rec, row );
1662         break;
1663
1664     case MSIMODIFY_REFRESH:
1665     case MSIMODIFY_ASSIGN:
1666     case MSIMODIFY_REPLACE:
1667     case MSIMODIFY_MERGE:
1668     case MSIMODIFY_VALIDATE:
1669     case MSIMODIFY_VALIDATE_FIELD:
1670     case MSIMODIFY_VALIDATE_DELETE:
1671         FIXME("%p %d %p - mode not implemented\n", view, eModifyMode, rec );
1672         r = ERROR_CALL_NOT_IMPLEMENTED;
1673         break;
1674
1675     default:
1676         r = ERROR_INVALID_DATA;
1677     }
1678
1679     return r;
1680 }
1681
1682 static UINT TABLE_delete( struct tagMSIVIEW *view )
1683 {
1684     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1685
1686     TRACE("%p\n", view );
1687
1688     tv->table = NULL;
1689     tv->columns = NULL;
1690
1691     if (tv->order)
1692     {
1693         msi_free( tv->order->reorder );
1694         msi_free( tv->order );
1695         tv->order = NULL;
1696     }
1697
1698     msi_free( tv );
1699
1700     return ERROR_SUCCESS;
1701 }
1702
1703 static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
1704     UINT val, UINT *row, MSIITERHANDLE *handle )
1705 {
1706     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1707     const MSICOLUMNHASHENTRY *entry;
1708
1709     TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
1710
1711     if( !tv->table )
1712         return ERROR_INVALID_PARAMETER;
1713
1714     if( (col==0) || (col > tv->num_cols) )
1715         return ERROR_INVALID_PARAMETER;
1716
1717     if( !tv->columns[col-1].hash_table )
1718     {
1719         UINT i;
1720         UINT num_rows = tv->table->row_count + tv->table->nonpersistent_row_count;
1721         MSICOLUMNHASHENTRY **hash_table;
1722         MSICOLUMNHASHENTRY *new_entry;
1723
1724         if( tv->columns[col-1].offset >= tv->row_size )
1725         {
1726             ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
1727             ERR("%p %p\n", tv, tv->columns );
1728             return ERROR_FUNCTION_FAILED;
1729         }
1730
1731         /* allocate contiguous memory for the table and its entries so we
1732          * don't have to do an expensive cleanup */
1733         hash_table = msi_alloc(MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*) +
1734             num_rows * sizeof(MSICOLUMNHASHENTRY));
1735         if (!hash_table)
1736             return ERROR_OUTOFMEMORY;
1737
1738         memset(hash_table, 0, MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*));
1739         tv->columns[col-1].hash_table = hash_table;
1740
1741         new_entry = (MSICOLUMNHASHENTRY *)(hash_table + MSITABLE_HASH_TABLE_SIZE);
1742
1743         for (i = 0; i < num_rows; i++, new_entry++)
1744         {
1745             UINT row_value;
1746
1747             if (view->ops->fetch_int( view, i, col, &row_value ) != ERROR_SUCCESS)
1748                 continue;
1749
1750             new_entry->next = NULL;
1751             new_entry->value = row_value;
1752             new_entry->row = i;
1753             if (hash_table[row_value % MSITABLE_HASH_TABLE_SIZE])
1754             {
1755                 MSICOLUMNHASHENTRY *prev_entry = hash_table[row_value % MSITABLE_HASH_TABLE_SIZE];
1756                 while (prev_entry->next)
1757                     prev_entry = prev_entry->next;
1758                 prev_entry->next = new_entry;
1759             }
1760             else
1761                 hash_table[row_value % MSITABLE_HASH_TABLE_SIZE] = new_entry;
1762         }
1763     }
1764
1765     if( !*handle )
1766         entry = tv->columns[col-1].hash_table[val % MSITABLE_HASH_TABLE_SIZE];
1767     else
1768         entry = (*handle)->next;
1769
1770     while (entry && entry->value != val)
1771         entry = entry->next;
1772
1773     *handle = entry;
1774     if (!entry)
1775         return ERROR_NO_MORE_ITEMS;
1776
1777     *row = entry->row;
1778
1779     if (tv->order)
1780         *row = tv->order->reorder[*row];
1781
1782     return ERROR_SUCCESS;
1783 }
1784
1785 static UINT TABLE_add_ref(struct tagMSIVIEW *view)
1786 {
1787     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1788     UINT i;
1789
1790     TRACE("%p %d\n", view, tv->table->ref_count);
1791
1792     for (i = 0; i < tv->table->col_count; i++)
1793     {
1794         if (tv->table->colinfo[i].type & MSITYPE_TEMPORARY)
1795             InterlockedIncrement(&tv->table->colinfo[i].ref_count);
1796     }
1797
1798     return InterlockedIncrement(&tv->table->ref_count);
1799 }
1800
1801 static UINT TABLE_remove_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number)
1802 {
1803     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1804     MSIRECORD *rec = NULL;
1805     MSIVIEW *columns = NULL;
1806     UINT row, r;
1807
1808     rec = MSI_CreateRecord(2);
1809     if (!rec)
1810         return ERROR_OUTOFMEMORY;
1811
1812     MSI_RecordSetStringW(rec, 1, table);
1813     MSI_RecordSetInteger(rec, 2, number);
1814
1815     r = TABLE_CreateView(tv->db, szColumns, &columns);
1816     if (r != ERROR_SUCCESS)
1817         return r;
1818
1819     r = msi_table_find_row((MSITABLEVIEW *)columns, rec, &row);
1820     if (r != ERROR_SUCCESS)
1821         goto done;
1822
1823     r = TABLE_delete_row(columns, row);
1824     if (r != ERROR_SUCCESS)
1825         goto done;
1826
1827     msi_update_table_columns(tv->db, table);
1828
1829 done:
1830     msiobj_release(&rec->hdr);
1831     if (columns) columns->ops->delete(columns);
1832     return r;
1833 }
1834
1835 static UINT TABLE_release(struct tagMSIVIEW *view)
1836 {
1837     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1838     INT ref = tv->table->ref_count;
1839     UINT i, r;
1840
1841     TRACE("%p %d\n", view, ref);
1842
1843     for (i = 0; i < tv->table->col_count; i++)
1844     {
1845         if (tv->table->colinfo[i].type & MSITYPE_TEMPORARY)
1846         {
1847             ref = InterlockedDecrement(&tv->table->colinfo[i].ref_count);
1848             if (ref == 0)
1849             {
1850                 r = TABLE_remove_column(view, tv->table->colinfo[i].tablename,
1851                                         tv->table->colinfo[i].number);
1852                 if (r != ERROR_SUCCESS)
1853                     break;
1854             }
1855         }
1856     }
1857
1858     ref = InterlockedDecrement(&tv->table->ref_count);
1859     if (ref == 0)
1860     {
1861         if (!tv->table->row_count)
1862         {
1863             list_remove(&tv->table->entry);
1864             free_table(tv->table);
1865             TABLE_delete(view);
1866         }
1867     }
1868
1869     return ref;
1870 }
1871
1872 static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number,
1873                              LPCWSTR column, UINT type, BOOL hold)
1874 {
1875     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1876     MSITABLE *msitable;
1877     MSIRECORD *rec;
1878     UINT r, i;
1879
1880     rec = MSI_CreateRecord(4);
1881     if (!rec)
1882         return ERROR_OUTOFMEMORY;
1883
1884     MSI_RecordSetStringW(rec, 1, table);
1885     MSI_RecordSetInteger(rec, 2, number);
1886     MSI_RecordSetStringW(rec, 3, column);
1887     MSI_RecordSetInteger(rec, 4, type);
1888
1889     r = TABLE_insert_row(&tv->view, rec, FALSE);
1890     if (r != ERROR_SUCCESS)
1891         goto done;
1892
1893     msi_update_table_columns(tv->db, table);
1894
1895     if (!hold)
1896         goto done;
1897
1898     msitable = find_cached_table(tv->db, table);
1899     for (i = 0; i < msitable->col_count; i++)
1900     {
1901         if (!lstrcmpW(msitable->colinfo[i].colname, column))
1902         {
1903             InterlockedIncrement(&msitable->colinfo[i].ref_count);
1904             break;
1905         }
1906     }
1907
1908 done:
1909     msiobj_release(&rec->hdr);
1910     return r;
1911 }
1912
1913 static UINT order_add_column(struct tagMSIVIEW *view, MSIORDERINFO *order, LPCWSTR name)
1914 {
1915     UINT n, r, count;
1916
1917     r = TABLE_get_dimensions(view, NULL, &count);
1918     if (r != ERROR_SUCCESS)
1919         return r;
1920
1921     if (order->num_cols >= count)
1922         return ERROR_FUNCTION_FAILED;
1923
1924     r = VIEW_find_column(view, name, &n);
1925     if (r != ERROR_SUCCESS)
1926         return r;
1927
1928     order->cols[order->num_cols] = n;
1929     TRACE("Ordering by column %s (%d)\n", debugstr_w(name), n);
1930
1931     order->num_cols++;
1932
1933     return ERROR_SUCCESS;
1934 }
1935
1936 static UINT order_compare(struct tagMSIVIEW *view, MSIORDERINFO *order,
1937                           UINT a, UINT b, UINT *swap)
1938 {
1939     UINT r, i, a_val = 0, b_val = 0;
1940
1941     *swap = 0;
1942     for (i = 0; i < order->num_cols; i++)
1943     {
1944         r = TABLE_fetch_int(view, a, order->cols[i], &a_val);
1945         if (r != ERROR_SUCCESS)
1946             return r;
1947
1948         r = TABLE_fetch_int(view, b, order->cols[i], &b_val);
1949         if (r != ERROR_SUCCESS)
1950             return r;
1951
1952         if (a_val != b_val)
1953         {
1954             if (a_val > b_val)
1955                 *swap = 1;
1956             break;
1957         }
1958     }
1959
1960     return ERROR_SUCCESS;
1961 }
1962
1963 static UINT order_mergesort(struct tagMSIVIEW *view, MSIORDERINFO *order,
1964                             UINT left, UINT right)
1965 {
1966     UINT r, i, j, temp;
1967     UINT swap = 0, center = (left + right) / 2;
1968     UINT *array = order->reorder;
1969
1970     if (left == right)
1971         return ERROR_SUCCESS;
1972
1973     /* sort the left half */
1974     r = order_mergesort(view, order, left, center);
1975     if (r != ERROR_SUCCESS)
1976         return r;
1977
1978     /* sort the right half */
1979     r = order_mergesort(view, order, center + 1, right);
1980     if (r != ERROR_SUCCESS)
1981         return r;
1982
1983     for (i = left, j = center + 1; (i <= center) && (j <= right); i++)
1984     {
1985         r = order_compare(view, order, array[i], array[j], &swap);
1986         if (r != ERROR_SUCCESS)
1987             return r;
1988
1989         if (swap)
1990         {
1991             temp = array[j];
1992             memmove(&array[i + 1], &array[i], (j - i) * sizeof(UINT));
1993             array[i] = temp;
1994             j++;
1995             center++;
1996         }
1997     }
1998
1999     return ERROR_SUCCESS;
2000 }
2001
2002 static UINT order_verify(struct tagMSIVIEW *view, MSIORDERINFO *order, UINT num_rows)
2003 {
2004     UINT i, swap, r;
2005
2006     for (i = 1; i < num_rows; i++)
2007     {
2008         r = order_compare(view, order, order->reorder[i - 1],
2009                           order->reorder[i], &swap);
2010         if (r != ERROR_SUCCESS)
2011             return r;
2012
2013         if (!swap)
2014             continue;
2015
2016         ERR("Bad order! %d\n", i);
2017         return ERROR_FUNCTION_FAILED;
2018     }
2019
2020     return ERROR_SUCCESS;
2021 }
2022
2023 static UINT TABLE_sort(struct tagMSIVIEW *view, column_info *columns)
2024 {
2025     MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
2026     MSIORDERINFO *order;
2027     column_info *ptr;
2028     UINT r, i;
2029     UINT rows, cols;
2030
2031     TRACE("sorting table %s\n", debugstr_w(tv->name));
2032
2033     r = TABLE_get_dimensions(view, &rows, &cols);
2034     if (r != ERROR_SUCCESS)
2035         return r;
2036
2037     order = msi_alloc_zero(sizeof(MSIORDERINFO) + sizeof(UINT) * cols);
2038     if (!order)
2039         return ERROR_OUTOFMEMORY;
2040
2041     for (ptr = columns; ptr; ptr = ptr->next)
2042         order_add_column(view, order, ptr->column);
2043
2044     order->reorder = msi_alloc(rows * sizeof(UINT));
2045     if (!order->reorder)
2046         return ERROR_OUTOFMEMORY;
2047
2048     for (i = 0; i < rows; i++)
2049         order->reorder[i] = i;
2050
2051     r = order_mergesort(view, order, 0, rows - 1);
2052     if (r != ERROR_SUCCESS)
2053         return r;
2054
2055     r = order_verify(view, order, rows);
2056     if (r != ERROR_SUCCESS)
2057         return r;
2058
2059     tv->order = order;
2060
2061     return ERROR_SUCCESS;
2062 }
2063
2064 static const MSIVIEWOPS table_ops =
2065 {
2066     TABLE_fetch_int,
2067     TABLE_fetch_stream,
2068     TABLE_get_row,
2069     TABLE_set_row,
2070     TABLE_insert_row,
2071     TABLE_delete_row,
2072     TABLE_execute,
2073     TABLE_close,
2074     TABLE_get_dimensions,
2075     TABLE_get_column_info,
2076     TABLE_modify,
2077     TABLE_delete,
2078     TABLE_find_matching_rows,
2079     TABLE_add_ref,
2080     TABLE_release,
2081     TABLE_add_column,
2082     TABLE_remove_column,
2083     TABLE_sort,
2084 };
2085
2086 UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
2087 {
2088     MSITABLEVIEW *tv ;
2089     UINT r, sz;
2090
2091     static const WCHAR Streams[] = {'_','S','t','r','e','a','m','s',0};
2092
2093     TRACE("%p %s %p\n", db, debugstr_w(name), view );
2094
2095     if ( !lstrcmpW( name, Streams ) )
2096         return STREAMS_CreateView( db, view );
2097
2098     sz = sizeof *tv + lstrlenW(name)*sizeof name[0] ;
2099     tv = msi_alloc_zero( sz );
2100     if( !tv )
2101         return ERROR_FUNCTION_FAILED;
2102
2103     r = get_table( db, name, &tv->table );
2104     if( r != ERROR_SUCCESS )
2105     {
2106         msi_free( tv );
2107         WARN("table not found\n");
2108         return r;
2109     }
2110
2111     TRACE("table %p found with %d columns\n", tv->table, tv->table->col_count);
2112
2113     /* fill the structure */
2114     tv->view.ops = &table_ops;
2115     tv->db = db;
2116     tv->columns = tv->table->colinfo;
2117     tv->num_cols = tv->table->col_count;
2118     tv->row_size = msi_table_get_row_size( tv->table->colinfo, tv->table->col_count );
2119
2120     TRACE("%s one row is %d bytes\n", debugstr_w(name), tv->row_size );
2121
2122     *view = (MSIVIEW*) tv;
2123     lstrcpyW( tv->name, name );
2124
2125     return ERROR_SUCCESS;
2126 }
2127
2128 UINT MSI_CommitTables( MSIDATABASE *db )
2129 {
2130     UINT r;
2131     MSITABLE *table = NULL;
2132
2133     TRACE("%p\n",db);
2134
2135     r = msi_save_string_table( db->strings, db->storage );
2136     if( r != ERROR_SUCCESS )
2137     {
2138         WARN("failed to save string table r=%08x\n",r);
2139         return r;
2140     }
2141
2142     LIST_FOR_EACH_ENTRY( table, &db->tables, MSITABLE, entry )
2143     {
2144         r = save_table( db, table );
2145         if( r != ERROR_SUCCESS )
2146         {
2147             WARN("failed to save table %s (r=%08x)\n",
2148                   debugstr_w(table->name), r);
2149             return r;
2150         }
2151     }
2152
2153     /* force everything to reload next time */
2154     free_cached_tables( db );
2155
2156     return ERROR_SUCCESS;
2157 }
2158
2159 MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table )
2160 {
2161     MSITABLE *t;
2162     UINT r;
2163
2164     TRACE("%p %s\n", db, debugstr_w(table));
2165
2166     if (!table)
2167         return MSICONDITION_ERROR;
2168
2169     r = get_table( db, table, &t );
2170     if (r != ERROR_SUCCESS)
2171         return MSICONDITION_NONE;
2172
2173     if (t->persistent)
2174         return MSICONDITION_TRUE;
2175     else
2176         return MSICONDITION_FALSE;
2177 }
2178
2179 static UINT read_raw_int(const BYTE *data, UINT col, UINT bytes)
2180 {
2181     UINT ret = 0, i;
2182
2183     for (i = 0; i < bytes; i++)
2184         ret += (data[col + i] << i * 8);
2185
2186     return ret;
2187 }
2188
2189 static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string_table *st,
2190                                             const BYTE *rawdata, UINT bytes_per_strref )
2191 {
2192     UINT i, val, ofs = 0;
2193     USHORT mask;
2194     MSICOLUMNINFO *columns = tv->columns;
2195     MSIRECORD *rec;
2196
2197     mask = rawdata[0] | (rawdata[1] << 8);
2198     rawdata += 2;
2199
2200     rec = MSI_CreateRecord( tv->num_cols );
2201     if( !rec )
2202         return rec;
2203
2204     TRACE("row ->\n");
2205     for( i=0; i<tv->num_cols; i++ )
2206     {
2207         if ( (mask&1) && (i>=(mask>>8)) )
2208             break;
2209         /* all keys must be present */
2210         if ( (~mask&1) && (~columns[i].type & MSITYPE_KEY) && ((1<<i) & ~mask) )
2211             continue;
2212
2213         if( (columns[i].type & MSITYPE_STRING) &&
2214             ! MSITYPE_IS_BINARY(tv->columns[i].type) )
2215         {
2216             LPCWSTR sval;
2217
2218             val = read_raw_int(rawdata, ofs, bytes_per_strref);
2219             sval = msi_string_lookup_id( st, val );
2220             MSI_RecordSetStringW( rec, i+1, sval );
2221             TRACE(" field %d [%s]\n", i+1, debugstr_w(sval));
2222             ofs += bytes_per_strref;
2223         }
2224         else
2225         {
2226             UINT n = bytes_per_column( &columns[i] );
2227             switch( n )
2228             {
2229             case 2:
2230                 val = read_raw_int(rawdata, ofs, n);
2231                 if (val)
2232                     MSI_RecordSetInteger( rec, i+1, val^0x8000 );
2233                 TRACE(" field %d [0x%04x]\n", i+1, val );
2234                 break;
2235             case 4:
2236                 val = read_raw_int(rawdata, ofs, n);
2237                 if (val)
2238                     MSI_RecordSetInteger( rec, i+1, val^0x80000000 );
2239                 TRACE(" field %d [0x%08x]\n", i+1, val );
2240                 break;
2241             default:
2242                 ERR("oops - unknown column width %d\n", n);
2243                 break;
2244             }
2245             ofs += n;
2246         }
2247     }
2248     return rec;
2249 }
2250
2251 static void dump_record( MSIRECORD *rec )
2252 {
2253     UINT i, n;
2254
2255     n = MSI_RecordGetFieldCount( rec );
2256     for( i=1; i<=n; i++ )
2257     {
2258         LPCWSTR sval = MSI_RecordGetString( rec, i );
2259
2260         if( MSI_RecordIsNull( rec, i ) )
2261             TRACE("row -> []\n");
2262         else if( (sval = MSI_RecordGetString( rec, i )) )
2263             TRACE("row -> [%s]\n", debugstr_w(sval));
2264         else
2265             TRACE("row -> [0x%08x]\n", MSI_RecordGetInteger( rec, i ) );
2266     }
2267 }
2268
2269 static void dump_table( const string_table *st, const USHORT *rawdata, UINT rawsize )
2270 {
2271     LPCWSTR sval;
2272     UINT i;
2273
2274     for( i=0; i<(rawsize/2); i++ )
2275     {
2276         sval = msi_string_lookup_id( st, rawdata[i] );
2277         MESSAGE(" %04x %s\n", rawdata[i], debugstr_w(sval) );
2278     }
2279 }
2280
2281 static UINT* msi_record_to_row( const MSITABLEVIEW *tv, MSIRECORD *rec )
2282 {
2283     LPCWSTR str;
2284     UINT i, r, *data;
2285
2286     data = msi_alloc( tv->num_cols *sizeof (UINT) );
2287     for( i=0; i<tv->num_cols; i++ )
2288     {
2289         data[i] = 0;
2290
2291         if ( ~tv->columns[i].type & MSITYPE_KEY )
2292             continue;
2293
2294         /* turn the transform column value into a row value */
2295         if ( ( tv->columns[i].type & MSITYPE_STRING ) &&
2296              ! MSITYPE_IS_BINARY(tv->columns[i].type) )
2297         {
2298             str = MSI_RecordGetString( rec, i+1 );
2299             r = msi_string2idW( tv->db->strings, str, &data[i] );
2300
2301             /* if there's no matching string in the string table,
2302                these keys can't match any record, so fail now. */
2303             if( ERROR_SUCCESS != r )
2304             {
2305                 msi_free( data );
2306                 return NULL;
2307             }
2308         }
2309         else
2310         {
2311             data[i] = MSI_RecordGetInteger( rec, i+1 );
2312             if ((tv->columns[i].type&0xff) == 2)
2313                 data[i] += 0x8000;
2314             else
2315                 data[i] += 0x80000000;
2316         }
2317     }
2318     return data;
2319 }
2320
2321 static UINT msi_row_matches( MSITABLEVIEW *tv, UINT row, const UINT *data )
2322 {
2323     UINT i, r, x, ret = ERROR_FUNCTION_FAILED;
2324
2325     for( i=0; i<tv->num_cols; i++ )
2326     {
2327         if ( ~tv->columns[i].type & MSITYPE_KEY )
2328             continue;
2329
2330         /* turn the transform column value into a row value */
2331         r = TABLE_fetch_int( &tv->view, row, i+1, &x );
2332         if ( r != ERROR_SUCCESS )
2333         {
2334             ERR("TABLE_fetch_int shouldn't fail here\n");
2335             break;
2336         }
2337
2338         /* if this key matches, move to the next column */
2339         if ( x != data[i] )
2340         {
2341             ret = ERROR_FUNCTION_FAILED;
2342             break;
2343         }
2344
2345         ret = ERROR_SUCCESS;
2346     }
2347
2348     return ret;
2349 }
2350
2351 static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
2352 {
2353     UINT i, r = ERROR_FUNCTION_FAILED, *data;
2354
2355     data = msi_record_to_row( tv, rec );
2356     if( !data )
2357         return r;
2358     for( i = 0; i < tv->table->row_count + tv->table->nonpersistent_row_count; i++ )
2359     {
2360         r = msi_row_matches( tv, i, data );
2361         if( r == ERROR_SUCCESS )
2362         {
2363             *row = i;
2364             break;
2365         }
2366     }
2367     msi_free( data );
2368     return r;
2369 }
2370
2371 typedef struct
2372 {
2373     struct list entry;
2374     LPWSTR name;
2375 } TRANSFORMDATA;
2376
2377 static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
2378                                       string_table *st, TRANSFORMDATA *transform,
2379                                       UINT bytes_per_strref )
2380 {
2381     UINT rawsize = 0;
2382     BYTE *rawdata = NULL;
2383     MSITABLEVIEW *tv = NULL;
2384     UINT r, n, sz, i, mask;
2385     MSIRECORD *rec = NULL;
2386     UINT colcol = 0;
2387     WCHAR coltable[32];
2388     LPWSTR name;
2389
2390     if (!transform)
2391         return ERROR_SUCCESS;
2392
2393     name = transform->name;
2394
2395     coltable[0] = 0;
2396     TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) );
2397
2398     /* read the transform data */
2399     read_stream_data( stg, name, TRUE, &rawdata, &rawsize );
2400     if ( !rawdata )
2401     {
2402         TRACE("table %s empty\n", debugstr_w(name) );
2403         return ERROR_INVALID_TABLE;
2404     }
2405
2406     /* create a table view */
2407     r = TABLE_CreateView( db, name, (MSIVIEW**) &tv );
2408     if( r != ERROR_SUCCESS )
2409         goto err;
2410
2411     r = tv->view.ops->execute( &tv->view, NULL );
2412     if( r != ERROR_SUCCESS )
2413         goto err;
2414
2415     TRACE("name = %s columns = %u row_size = %u raw size = %u\n",
2416           debugstr_w(name), tv->num_cols, tv->row_size, rawsize );
2417
2418     /* interpret the data */
2419     r = ERROR_SUCCESS;
2420     for( n=0; n < rawsize;  )
2421     {
2422         mask = rawdata[n] | (rawdata[n+1] << 8);
2423
2424         if (mask&1)
2425         {
2426             /*
2427              * if the low bit is set, columns are continuous and
2428              * the number of columns is specified in the high byte
2429              */
2430             sz = 2;
2431             for( i=0; i<tv->num_cols; i++ )
2432             {
2433                 if( (tv->columns[i].type & MSITYPE_STRING) &&
2434                     ! MSITYPE_IS_BINARY(tv->columns[i].type) )
2435                     sz += bytes_per_strref;
2436                 else
2437                     sz += bytes_per_column( &tv->columns[i] );
2438             }
2439         }
2440         else
2441         {
2442             /*
2443              * If the low bit is not set, mask is a bitmask.
2444              * Excepting for key fields, which are always present,
2445              *  each bit indicates that a field is present in the transform record.
2446              *
2447              * mask == 0 is a special case ... only the keys will be present
2448              * and it means that this row should be deleted.
2449              */
2450             sz = 2;
2451             for( i=0; i<tv->num_cols; i++ )
2452             {
2453                 if( (tv->columns[i].type & MSITYPE_KEY) || ((1<<i)&mask))
2454                 {
2455                     if( (tv->columns[i].type & MSITYPE_STRING) &&
2456                         ! MSITYPE_IS_BINARY(tv->columns[i].type) )
2457                         sz += bytes_per_strref;
2458                     else
2459                         sz += bytes_per_column( &tv->columns[i] );
2460                 }
2461             }
2462         }
2463
2464         /* check we didn't run of the end of the table */
2465         if ( (n+sz) > rawsize )
2466         {
2467             ERR("borked.\n");
2468             dump_table( st, (USHORT *)rawdata, rawsize );
2469             break;
2470         }
2471
2472         rec = msi_get_transform_record( tv, st, &rawdata[n], bytes_per_strref );
2473         if (rec)
2474         {
2475             if ( mask & 1 )
2476             {
2477                 WCHAR table[32];
2478                 DWORD sz = 32;
2479                 UINT number = MSI_NULL_INTEGER;
2480
2481                 TRACE("inserting record\n");
2482
2483                 if (!lstrcmpW(name, szColumns))
2484                 {
2485                     MSI_RecordGetStringW( rec, 1, table, &sz );
2486                     number = MSI_RecordGetInteger( rec, 2 );
2487
2488                     /*
2489                      * Native msi seems writes nul into the Number (2nd) column of
2490                      * the _Columns table, only when the columns are from a new table
2491                      */
2492                     if ( number == MSI_NULL_INTEGER )
2493                     {
2494                         /* reset the column number on a new table */
2495                         if ( lstrcmpW(coltable, table) )
2496                         {
2497                             colcol = 0;
2498                             lstrcpyW( coltable, table );
2499                         }
2500
2501                         /* fix nul column numbers */
2502                         MSI_RecordSetInteger( rec, 2, ++colcol );
2503                     }
2504                 }
2505
2506                 r = TABLE_insert_row( &tv->view, rec, FALSE );
2507                 if (r != ERROR_SUCCESS)
2508                     ERR("insert row failed\n");
2509
2510                 if ( number != MSI_NULL_INTEGER && !lstrcmpW(name, szColumns) )
2511                     msi_update_table_columns( db, table );
2512             }
2513             else
2514             {
2515                 UINT row = 0;
2516
2517                 r = msi_table_find_row( tv, rec, &row );
2518                 if (r != ERROR_SUCCESS)
2519                     ERR("no matching row to transform\n");
2520                 else if ( mask )
2521                 {
2522                     TRACE("modifying row [%d]:\n", row);
2523                     TABLE_set_row( &tv->view, row, rec, mask );
2524                 }
2525                 else
2526                 {
2527                     TRACE("deleting row [%d]:\n", row);
2528                     TABLE_delete_row( &tv->view, row );
2529                 }
2530             }
2531             if( TRACE_ON(msidb) ) dump_record( rec );
2532             msiobj_release( &rec->hdr );
2533         }
2534
2535         n += sz;
2536     }
2537
2538 err:
2539     /* no need to free the table, it's associated with the database */
2540     msi_free( rawdata );
2541     if( tv )
2542         tv->view.ops->delete( &tv->view );
2543
2544     return ERROR_SUCCESS;
2545 }
2546
2547 /*
2548  * msi_table_apply_transform
2549  *
2550  * Enumerate the table transforms in a transform storage and apply each one.
2551  */
2552 UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
2553 {
2554     struct list transforms;
2555     IEnumSTATSTG *stgenum = NULL;
2556     TRANSFORMDATA *transform;
2557     TRANSFORMDATA *tables = NULL, *columns = NULL;
2558     HRESULT r;
2559     STATSTG stat;
2560     string_table *strings;
2561     UINT ret = ERROR_FUNCTION_FAILED;
2562     UINT bytes_per_strref;
2563
2564     TRACE("%p %p\n", db, stg );
2565
2566     strings = msi_load_string_table( stg, &bytes_per_strref );
2567     if( !strings )
2568         goto end;
2569
2570     r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum );
2571     if( FAILED( r ) )
2572         goto end;
2573
2574     list_init(&transforms);
2575
2576     while ( TRUE )
2577     {
2578         MSITABLEVIEW *tv = NULL;
2579         WCHAR name[0x40];
2580         ULONG count = 0;
2581
2582         r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
2583         if ( FAILED( r ) || !count )
2584             break;
2585
2586         decode_streamname( stat.pwcsName, name );
2587         CoTaskMemFree( stat.pwcsName );
2588         if ( name[0] != 0x4840 )
2589             continue;
2590
2591         if ( !lstrcmpW( name+1, szStringPool ) ||
2592              !lstrcmpW( name+1, szStringData ) )
2593             continue;
2594
2595         transform = msi_alloc_zero( sizeof(TRANSFORMDATA) );
2596         if ( !transform )
2597             break;
2598
2599         list_add_tail( &transforms, &transform->entry );
2600
2601         transform->name = strdupW( name + 1 );
2602
2603         if ( !lstrcmpW( transform->name, szTables ) )
2604             tables = transform;
2605         else if (!lstrcmpW( transform->name, szColumns ) )
2606             columns = transform;
2607
2608         TRACE("transform contains stream %s\n", debugstr_w(name));
2609
2610         /* load the table */
2611         r = TABLE_CreateView( db, transform->name, (MSIVIEW**) &tv );
2612         if( r != ERROR_SUCCESS )
2613             continue;
2614
2615         r = tv->view.ops->execute( &tv->view, NULL );
2616         if( r != ERROR_SUCCESS )
2617         {
2618             tv->view.ops->delete( &tv->view );
2619             continue;
2620         }
2621
2622         tv->view.ops->delete( &tv->view );
2623     }
2624
2625     /*
2626      * Apply _Tables and _Columns transforms first so that
2627      * the table metadata is correct, and empty tables exist.
2628      */
2629     ret = msi_table_load_transform( db, stg, strings, tables, bytes_per_strref );
2630     if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
2631         goto end;
2632
2633     ret = msi_table_load_transform( db, stg, strings, columns, bytes_per_strref );
2634     if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
2635         goto end;
2636
2637     ret = ERROR_SUCCESS;
2638
2639     while ( !list_empty( &transforms ) )
2640     {
2641         transform = LIST_ENTRY( list_head( &transforms ), TRANSFORMDATA, entry );
2642
2643         if ( lstrcmpW( transform->name, szColumns ) &&
2644              lstrcmpW( transform->name, szTables ) &&
2645              ret == ERROR_SUCCESS )
2646         {
2647             ret = msi_table_load_transform( db, stg, strings, transform, bytes_per_strref );
2648         }
2649
2650         list_remove( &transform->entry );
2651         msi_free( transform->name );
2652         msi_free( transform );
2653     }
2654
2655     if ( ret == ERROR_SUCCESS )
2656         append_storage_to_db( db, stg );
2657
2658 end:
2659     if ( stgenum )
2660         IEnumSTATSTG_Release( stgenum );
2661     if ( strings )
2662         msi_destroy_stringtable( strings );
2663
2664     return ret;
2665 }
2666
2667 void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
2668 {
2669     MSITRANSFORM *t;
2670
2671     t = msi_alloc( sizeof *t );
2672     t->stg = stg;
2673     IStorage_AddRef( stg );
2674     list_add_tail( &db->transforms, &t->entry );
2675 }
2676
2677 void msi_free_transforms( MSIDATABASE *db )
2678 {
2679     while( !list_empty( &db->transforms ) )
2680     {
2681         MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
2682                                       MSITRANSFORM, entry );
2683         list_remove( &t->entry );
2684         IStorage_Release( t->stg );
2685         msi_free( t );
2686     }
2687 }