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