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,
|
UINT ACTION_DoTopLevelINSTALL(MSIHANDLE hPackage, LPCWSTR szPackagePath,
|
||||||
LPCWSTR szCommandLine);
|
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__ */
|
#endif /* __WINE_MSI_PRIVATE__ */
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
#include "wine/unicode.h"
|
||||||
#include "msi.h"
|
#include "msi.h"
|
||||||
#include "msiquery.h"
|
#include "msiquery.h"
|
||||||
#include "objbase.h"
|
#include "objbase.h"
|
||||||
|
@ -208,11 +209,40 @@ UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
|
||||||
|
|
||||||
if( type & MSITYPE_STRING )
|
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 );
|
MsiRecordSetStringW( handle, i, sval );
|
||||||
HeapFree( GetProcessHeap(), 0, sval );
|
HeapFree( GetProcessHeap(), 0, sval );
|
||||||
}
|
}
|
||||||
else
|
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 )
|
if( (type & MSI_DATASIZEMASK) == 2 )
|
||||||
MsiRecordSetInteger( handle, i, ival - (1<<15) );
|
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)
|
UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz)
|
||||||
{
|
{
|
||||||
FIXME("%ld %d %p %p\n",handle,iField,buf,sz);
|
MSIRECORD *rec;
|
||||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
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;
|
*out = 0;
|
||||||
return count;
|
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
|
#endif
|
||||||
|
|
||||||
static UINT read_stream_data( IStorage *stg, LPCWSTR stname,
|
static UINT read_stream_data( IStorage *stg, LPCWSTR stname,
|
||||||
|
@ -230,6 +259,91 @@ end:
|
||||||
return ret;
|
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,
|
static UINT write_stream_data( IStorage *stg, LPCWSTR stname,
|
||||||
LPVOID data, UINT sz )
|
LPVOID data, UINT sz )
|
||||||
{
|
{
|
||||||
|
@ -1254,76 +1368,3 @@ UINT MSI_CommitTables( MSIDATABASE *db )
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
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