[MSI 1/4] add streams table

Andrey Turkin pancha at mail.nnov.ru
Mon Jun 19 11:31:30 CDT 2006


This patch adds virtual _Streams table to MSI because native MSI
maintains such table

ChangeLog:
virtual _Streams table added
-------------- next part --------------
--- wine-0.9.15-orig/dlls/msi/table.c	2006-06-19 19:45:21.000000000 +0400
+++ wine-0.9.15/dlls/msi/table.c	2006-06-19 19:45:36.000000000 +0400
@@ -833,12 +833,14 @@
 
 /* information for default tables */
 static const WCHAR szTables[]  = { '_','T','a','b','l','e','s',0 };
-static const WCHAR szTable[]  = { 'T','a','b','l','e',0 };
+static const WCHAR szTable[]   = { 'T','a','b','l','e',0 };
 static const WCHAR szName[]    = { 'N','a','m','e',0 };
 static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
 static const WCHAR szColumn[]  = { 'C','o','l','u','m','n',0 };
 static const WCHAR szNumber[]  = { 'N','u','m','b','e','r',0 };
 static const WCHAR szType[]    = { 'T','y','p','e',0 };
+static const WCHAR szStreams[] = { '_','S','t','r','e','a','m','s',0 };
+static const WCHAR szData[]    = { 'D','a','t','a',0 };
 
 static const MSICOLUMNINFO _Columns_cols[4] = {
     { szColumns, 1, szTable,  MSITYPE_VALID | MSITYPE_STRING | 64, 0 },
@@ -849,6 +851,10 @@
 static const MSICOLUMNINFO _Tables_cols[1] = {
     { szTables,  1, szName,   MSITYPE_VALID | MSITYPE_STRING | 64, 0 },
 };
+static const MSICOLUMNINFO _Streams_cols[2] = {
+    { szStreams,  1, szName,   MSITYPE_VALID | MSITYPE_STRING | 62, 0 },
+    { szStreams,  2, szData,   MSITYPE_VALID | MSITYPE_STRING | MSITYPE_NULLABLE, 2 },
+};
 
 static UINT get_defaulttablecolumns( LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz)
 {
@@ -867,6 +873,11 @@
         p = _Columns_cols;
         n = 4;
     }
+    else if (!lstrcmpW( name, szStreams ))
+    {
+        p = _Streams_cols;
+        n = 2;
+    }
     else
         return ERROR_FUNCTION_FAILED;
 
@@ -886,6 +897,67 @@
     return ERROR_SUCCESS;
 }
 
+static MSITABLE *create_streams_table(  MSIDATABASE *db )
+{
+    MSITABLE *t;
+    IEnumSTATSTG *stgenum = NULL;
+    HRESULT r;
+    ULONG alloced;
+
+    TRACE("\n");
+
+    t = msi_alloc( sizeof (MSITABLE) + lstrlenW(szStreams)*sizeof (WCHAR) );
+    if( !t )
+        return t;
+
+    lstrcpyW( t->name, szStreams );
+
+    t->row_count = alloced = 0;
+    t->data = NULL;
+
+    r = IStorage_EnumElements( db->storage, 0, NULL, 0, &stgenum );
+    if ( FAILED(r) )
+        goto err;
+
+    while ( 1 )
+    {
+        STATSTG stat;
+        DWORD count = 0;
+        WCHAR name[0x40];
+
+        r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
+        if( FAILED( r ) || !count )
+            break;
+        decode_streamname( stat.pwcsName, name );
+        if ( t->row_count >= alloced)
+        {
+            alloced += 4;
+            if (t->data == NULL)
+                t->data = msi_alloc_zero( alloced * sizeof(WCHAR*) );
+            else
+                t->data = msi_realloc( t->data, alloced * sizeof(WCHAR*) );
+            if (!t->data)
+            {
+                IEnumSTATSTG_Release( stgenum );
+                goto err;
+            }
+        }
+        if ( (t->data[t->row_count] = msi_alloc(2 * sizeof(UINT))) == NULL )
+            goto err;
+        else
+        {
+            t->data[t->row_count][0] = msi_addstringW( db->strings, 0, name, -1, 0 );
+            t->data[t->row_count++][1] = 1;
+        }
+    }
+    IEnumSTATSTG_Release( stgenum );
+
+    return t;
+err:
+    free_table( t );
+    return NULL;
+}
+
 static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count )
 {
     UINT i;
@@ -993,6 +1065,8 @@
         return TRUE;
     if( !lstrcmpW( name, szColumns ) )
         return TRUE;
+    if( !lstrcmpW( name, szStreams ) )
+        return TRUE;
 
     r = msi_string2idW( db->strings, name, &table_id );
     if( r != ERROR_SUCCESS )
@@ -1132,6 +1206,53 @@
 
     return r;
 }
+static UINT STREAMS_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
+{
+    MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
+    UINT ival = 0, refcol = 0, r;
+    LPWSTR sval;
+
+    ERR("\n");
+    if( !view->ops->fetch_int )
+        return ERROR_INVALID_PARAMETER;
+
+    /*
+     * The column marked with the type stream data seems to have a single number
+     * which references the column containing the name of the stream data
+     *
+     * Fetch the column to reference first.
+     */
+    r = view->ops->fetch_int( view, row, col, &ival );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("1: %d\n", r);
+        return r;
+    }
+
+    ERR("fetched %d\n", ival);
+    /* now get the column with the name of the stream */
+    r = view->ops->fetch_int( view, row, ival, &refcol );
+    if( r != ERROR_SUCCESS )
+    {
+        ERR("2: %d\n", r);
+        return r;
+    }
+
+    /* lookup the string value from the string table */
+    sval = MSI_makestring( tv->db, refcol );
+    if( !sval )
+    {
+        ERR("MSI_makestring failed\n");
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    r = db_get_raw_stream( tv->db, sval, stm );
+    if( r )
+        ERR("fetching stream %s, error = %d\n",debugstr_w(sval), r);
+    msi_free( sval );
+
+    return r;
+}
 
 static UINT TABLE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
 {
@@ -1218,6 +1339,25 @@
     return ERROR_SUCCESS;
 }
 
+static UINT STREAMS_execute( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+    MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
+
+    TRACE("(%p, %p)\n", view, record);
+
+    tv->table = find_cached_table( tv->db, szStreams );
+    if( !tv->table )
+    {
+        tv->table = create_streams_table( tv->db );
+        if ( tv->table )
+            list_add_head( &tv->db->tables, &tv->table->entry );
+        else
+            return ERROR_FUNCTION_FAILED;
+    }
+
+    return ERROR_SUCCESS;
+}
+
 static UINT TABLE_close( struct tagMSIVIEW *view )
 {
     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
@@ -1509,6 +1649,21 @@
     TABLE_find_matching_rows
 };
 
+MSIVIEWOPS streams_ops =
+{
+    TABLE_fetch_int,
+    STREAMS_fetch_stream,
+    TABLE_set_int,
+    TABLE_insert_row,
+    STREAMS_execute,
+    TABLE_close,
+    TABLE_get_dimensions,
+    TABLE_get_column_info,
+    TABLE_modify,
+    TABLE_delete,
+    TABLE_find_matching_rows
+};
+
 UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
 {
     MSITABLEVIEW *tv ;
@@ -1521,11 +1676,17 @@
     column_count = 0;
     r = get_tablecolumns( db, name, NULL, &column_count );
     if( r != ERROR_SUCCESS )
+    {
+        TRACE("get_tablecolumns failed: %d\n", r);
         return r;
+    }
 
     /* if there's no columns, there's no table */
     if( column_count == 0 )
+    {
+        TRACE("column_count==0\n");
         return ERROR_INVALID_PARAMETER;
+    }
 
     TRACE("Table found\n");
 
@@ -1552,7 +1713,7 @@
     TRACE("Table has %d columns\n", column_count);
 
     /* fill the structure */
-    tv->view.ops = &table_ops;
+    tv->view.ops = lstrcmpW(name, szStreams)?&table_ops:&streams_ops;
     tv->db = db;
     tv->columns = columns;
     tv->num_cols = column_count;
--- wine-0.9.15-orig/dlls/msi/tests/db.c	2006-06-19 19:45:17.000000000 +0400
+++ wine-0.9.15/dlls/msi/tests/db.c	2006-06-19 19:46:41.000000000 +0400
@@ -743,10 +743,8 @@
     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES );
     ok( rec, "failed to get column info record\n" );
 
-    todo_wine {
     ok( check_record( rec, 1, "s62"), "wrong record type\n");
     ok( check_record( rec, 2, "V0"), "wrong record type\n");
-    }
 
     MsiCloseHandle( rec );
 
@@ -754,10 +752,8 @@
     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_NAMES );
     ok( rec, "failed to get column info record\n" );
 
-    todo_wine {
     ok( check_record( rec, 1, "Name"), "wrong record type\n");
     ok( check_record( rec, 2, "Data"), "wrong record type\n");
-    }
 
     MsiCloseHandle( rec );
     MsiCloseHandle( hdb );


More information about the wine-patches mailing list