Allow reading records containing streams.
This commit is contained in:
parent
8079d2ae33
commit
0eecfdef67
|
@ -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,11 +209,40 @@ UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
|
|||
|
||||
if( type & MSITYPE_STRING )
|
||||
{
|
||||
LPWSTR sval = MSI_makestring( query->db, ival );
|
||||
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
|
||||
{
|
||||
if( (type & MSI_DATASIZEMASK) == 2 )
|
||||
MsiRecordSetInteger( handle, i, ival - (1<<15) );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
187
dlls/msi/table.c
187
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue