Commit 0eecfdef authored by Mike McCormack's avatar Mike McCormack Committed by Alexandre Julliard

Allow reading records containing streams.

parent 8079d2ae
......@@ -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__ */
......@@ -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
{
......
......@@ -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;
}
......@@ -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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment