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