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