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