From 0eecfdef67a98fc70fa13b85833c9252e6ea9688 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Tue, 29 Jun 2004 03:41:28 +0000 Subject: [PATCH] Allow reading records containing streams. --- dlls/msi/msipriv.h | 6 ++ dlls/msi/msiquery.c | 36 ++++++++- dlls/msi/record.c | 71 ++++++++++++++++- dlls/msi/table.c | 187 +++++++++++++++++++++++++++----------------- 4 files changed, 222 insertions(+), 78 deletions(-) diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index c6b00e3b951..1bbdd2d4105 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -206,4 +206,10 @@ UINT read_raw_stream_data( MSIHANDLE hdb, LPCWSTR stname, 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__ */ diff --git a/dlls/msi/msiquery.c b/dlls/msi/msiquery.c index f6054040c27..799907c1ea6 100644 --- a/dlls/msi/msiquery.c +++ b/dlls/msi/msiquery.c @@ -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 @@ UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record) 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 { diff --git a/dlls/msi/record.c b/dlls/msi/record.c index e5bf28e9aea..5ced6fd8ea1 100644 --- a/dlls/msi/record.c +++ b/dlls/msi/record.c @@ -434,6 +434,73 @@ UINT WINAPI MsiRecordSetStreamW(MSIHANDLE hRecord, unsigned int iField, LPCWSTR 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; } diff --git a/dlls/msi/table.c b/dlls/msi/table.c index afbe1103e78..0bdb6c104ca 100644 --- a/dlls/msi/table.c +++ b/dlls/msi/table.c @@ -165,6 +165,35 @@ static BOOL decode_streamname(LPWSTR in, LPWSTR out) *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,91 @@ end: 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_SUCCESS) + 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 ) { @@ -1254,76 +1368,3 @@ UINT MSI_CommitTables( MSIDATABASE *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; -}