MSI: Allow reading records containing streams

Mike McCormack mike at codeweavers.com
Mon Jun 28 18:30:35 CDT 2004


ChangeLog:
* Allow reading records containing streams
-------------- next part --------------
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.13
diff -u -r1.13 msipriv.h
--- dlls/msi/msipriv.h	28 Jun 2004 20:34:35 -0000	1.13
+++ dlls/msi/msipriv.h	29 Jun 2004 00:27:03 -0000
@@ -206,4 +206,10 @@
 UINT ACTION_DoTopLevelINSTALL(MSIHANDLE hPackage, LPCWSTR szPackagePath,
                               LPCWSTR szCommandLine);
 
+extern UINT WINAPI MSI_RecordSetIStream( MSIHANDLE handle, 
+              unsigned int iField, IStream *stm );
+extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
+extern UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm );
+
+
 #endif /* __WINE_MSI_PRIVATE__ */
Index: dlls/msi/msiquery.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/msiquery.c,v
retrieving revision 1.7
diff -u -r1.7 msiquery.c
--- dlls/msi/msiquery.c	19 Mar 2004 19:14:12 -0000	1.7
+++ dlls/msi/msiquery.c	29 Jun 2004 00:27:03 -0000
@@ -24,6 +24,7 @@
 #include "winbase.h"
 #include "winerror.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
 #include "msi.h"
 #include "msiquery.h"
 #include "objbase.h"
@@ -208,9 +209,38 @@
 
         if( type & MSITYPE_STRING )
         {
-            LPWSTR sval = MSI_makestring( query->db, ival );
-            MsiRecordSetStringW( handle, i, sval );
-            HeapFree( GetProcessHeap(), 0, sval );
+            LPWSTR sval;
+
+            if( type & MSI_DATASIZEMASK )
+            {
+                sval = MSI_makestring( query->db, ival );
+                MsiRecordSetStringW( handle, i, sval );
+                HeapFree( GetProcessHeap(), 0, sval );
+            }
+            else
+            {
+                UINT refcol = 0;
+                IStream *stm = NULL;
+                WCHAR full_name[0x40];
+                static const WCHAR szBinary[] = { 'B','i','n','a','r','y','.', 0};
+                const int maxlen = (sizeof full_name - sizeof szBinary)/sizeof(WCHAR);
+
+                ret = view->ops->fetch_int( view, query->row, ival, &refcol );
+                sval = MSI_makestring( query->db, refcol );
+
+                if( sval && ( strlenW( sval ) < maxlen ) )
+                {
+                    strcpyW( full_name, szBinary );
+                    strcatW( full_name, sval );
+
+                    db_get_raw_stream( query->db, full_name, &stm );
+                    if( stm )
+                        MSI_RecordSetIStream( handle, i, stm );
+                    else
+                        ERR("failed to get stream\n");
+                    HeapFree( GetProcessHeap(), 0, sval );
+                }
+            }
         }
         else
         {
Index: dlls/msi/record.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/record.c,v
retrieving revision 1.5
diff -u -r1.5 record.c
--- dlls/msi/record.c	19 Apr 2004 20:12:14 -0000	1.5
+++ dlls/msi/record.c	29 Jun 2004 00:27:03 -0000
@@ -434,6 +434,73 @@
 
 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz)
 {
-    FIXME("%ld %d %p %p\n",handle,iField,buf,sz);
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    MSIRECORD *rec;
+    ULONG count;
+    HRESULT r;
+    IStream *stm;
+
+    TRACE("%ld %d %p %p\n", handle, iField, buf, sz);
+
+    rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+    if( !rec )
+        return ERROR_INVALID_HANDLE;
+
+    if( iField > rec->count )
+        return ERROR_INVALID_FIELD;
+
+    if( rec->fields[iField].type != MSIFIELD_STREAM )
+        return ERROR_INVALID_FIELD;
+
+    stm = rec->fields[iField].u.stream;
+    if( !stm )
+        return ERROR_INVALID_FIELD;
+
+    /* if there's no buffer pointer, calculate the length to the end */
+    if( !buf )
+    {
+        LARGE_INTEGER ofs;
+        ULARGE_INTEGER end, cur;
+
+        ofs.QuadPart = cur.QuadPart = 0;
+        end.QuadPart = 0;
+        r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
+        IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
+        ofs.QuadPart = cur.QuadPart;
+        IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
+        *sz = end.QuadPart - cur.QuadPart;
+
+        return ERROR_SUCCESS;
+    }
+
+    /* read the data */
+    count = 0;
+    r = IStream_Read( stm, buf, *sz, &count );
+    if( FAILED( r ) )
+        return ERROR_FUNCTION_FAILED;
+
+    *sz = count;
+
+    return ERROR_SUCCESS;
+}
+
+UINT WINAPI MSI_RecordSetIStream( MSIHANDLE handle, unsigned int iField, IStream *stm )
+{
+    MSIRECORD *rec;
+
+    TRACE("%ld %d %p\n", handle, iField, stm);
+
+    rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+    if( !rec )
+        return ERROR_INVALID_HANDLE;
+
+    if( iField > rec->count )
+        return ERROR_INVALID_FIELD;
+
+    MSI_FreeField( &rec->fields[iField] );
+
+    rec->fields[iField].type = MSIFIELD_STREAM;
+    rec->fields[iField].u.stream = stm;
+    IStream_AddRef( stm );
+
+    return ERROR_SUCCESS;
 }
Index: dlls/msi/table.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/table.c,v
retrieving revision 1.13
diff -u -r1.13 table.c
--- dlls/msi/table.c	28 Jun 2004 20:34:35 -0000	1.13
+++ dlls/msi/table.c	29 Jun 2004 00:27:03 -0000
@@ -165,6 +165,35 @@
     *out = 0;
     return count;
 }
+
+void enum_stream_names( IStorage *stg )
+{
+    IEnumSTATSTG *stgenum = NULL;
+    HRESULT r;
+    STATSTG stat;
+    ULONG n, count;
+    WCHAR name[0x40];
+
+    r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum );
+    if( FAILED( r ) )
+        return;
+
+    n = 0;
+    while( 1 )
+    {
+        count = 0;
+        r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
+        if( FAILED( r ) || !count )
+            break;
+        decode_streamname( stat.pwcsName, name );
+        ERR("stream %2ld -> %s %s\n", n, 
+            debugstr_w(stat.pwcsName), debugstr_w(name) );
+        n++;
+    }
+
+    IEnumSTATSTG_Release( stgenum );
+}
+
 #endif
 
 static UINT read_stream_data( IStorage *stg, LPCWSTR stname,
@@ -230,6 +259,92 @@
     return ret;
 }
 
+UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
+{
+    WCHAR encname[0x20];
+    HRESULT r;
+
+    encode_streamname(FALSE, stname, encname);
+
+    TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
+
+    r = IStorage_OpenStream(db->storage, encname, NULL, 
+            STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm);
+    if( FAILED( r ) )
+    {
+        WARN("open stream failed r = %08lx - empty table?\n",r);
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    return ERROR_SUCCESS;
+}
+
+/* FIXME: we should be passing around pointers to db structures internally */
+UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm )
+{
+    MSIDATABASE *db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE );
+
+    if ( !db )
+        return ERROR_INVALID_HANDLE;
+
+    return db_get_raw_stream( db, stname, stm );
+}
+
+UINT read_raw_stream_data( MSIHANDLE hdb, LPCWSTR stname,
+                              USHORT **pdata, UINT *psz )
+{
+    HRESULT r;
+    UINT ret = ERROR_FUNCTION_FAILED;
+    VOID *data;
+    ULONG sz, count;
+    IStream *stm = NULL;
+    STATSTG stat;
+
+    r = get_raw_stream( hdb, stname, &stm );
+    if( r != ERROR_FUNCTION_FAILED )
+        goto end;
+
+    ret = ERROR_FUNCTION_FAILED;
+    r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
+    if( FAILED( r ) )
+    {
+        ERR("open stream failed r = %08lx!\n",r);
+        goto end;
+    }
+
+    if( stat.cbSize.QuadPart >> 32 )
+    {
+        ERR("Too big!\n");
+        goto end;
+    }
+        
+    sz = stat.cbSize.QuadPart;
+    data = HeapAlloc( GetProcessHeap(), 0, sz );
+    if( !data )
+    {
+        ERR("couldn't allocate memory r=%08lx!\n",r);
+        ret = ERROR_NOT_ENOUGH_MEMORY;
+        goto end;
+    }
+        
+    r = IStream_Read(stm, data, sz, &count );
+    if( FAILED( r ) || ( count != sz ) )
+    {
+        HeapFree( GetProcessHeap(), 0, data );
+        ERR("read stream failed r = %08lx!\n",r);
+        goto end;
+    }
+
+    *pdata = data;
+    *psz = sz;
+    ret = ERROR_SUCCESS;
+
+end:
+    IStream_Release( stm );
+
+    return ret;
+}
+
 static UINT write_stream_data( IStorage *stg, LPCWSTR stname,
                                LPVOID data, UINT sz )
 {
@@ -1253,77 +1368,4 @@
     free_cached_tables( db );
 
     return ERROR_SUCCESS;
-}
-
-
-UINT read_raw_stream_data( MSIHANDLE hdb, LPCWSTR stname,
-                              USHORT **pdata, UINT *psz )
-{
-    HRESULT r;
-    UINT ret = ERROR_FUNCTION_FAILED;
-    VOID *data;
-    ULONG sz, count;
-    IStream *stm = NULL;
-    IStorage *stg = NULL;
-    STATSTG stat;
-    WCHAR encname[0x20];
-    MSIDATABASE *db;
-
-    db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE );
-
-    if ( !db )
-        return ERROR_INVALID_HANDLE;
-
-    stg = db->storage;
-
-    encode_streamname(FALSE, stname, encname);
-
-    TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
-
-    r = IStorage_OpenStream(stg, encname, NULL, 
-            STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
-    if( FAILED( r ) )
-    {
-        WARN("open stream failed r = %08lx - empty table?\n",r);
-        return ret;
-    }
-
-    r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
-    if( FAILED( r ) )
-    {
-        ERR("open stream failed r = %08lx!\n",r);
-        goto end;
-    }
-
-    if( stat.cbSize.QuadPart >> 32 )
-    {
-        ERR("Too big!\n");
-        goto end;
-    }
-        
-    sz = stat.cbSize.QuadPart;
-    data = HeapAlloc( GetProcessHeap(), 0, sz );
-    if( !data )
-    {
-        ERR("couldn't allocate memory r=%08lx!\n",r);
-        ret = ERROR_NOT_ENOUGH_MEMORY;
-        goto end;
-    }
-        
-    r = IStream_Read(stm, data, sz, &count );
-    if( FAILED( r ) || ( count != sz ) )
-    {
-        HeapFree( GetProcessHeap(), 0, data );
-        ERR("read stream failed r = %08lx!\n",r);
-        goto end;
-    }
-
-    *pdata = data;
-    *psz = sz;
-    ret = ERROR_SUCCESS;
-
-end:
-    IStream_Release( stm );
-
-    return ret;
 }


More information about the wine-patches mailing list