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