msi: Add support for binary OBJECTS.

This commit is contained in:
Hib Eris 2009-05-24 18:51:53 +02:00 committed by Alexandre Julliard
parent 8356484c9f
commit f6dd90de5e
3 changed files with 165 additions and 58 deletions

View File

@ -930,6 +930,7 @@ MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
msiobj_release(&clone->hdr);
return NULL;
}
clone->fields[i].type = MSIFIELD_STREAM;
}
else
{

View File

@ -1158,6 +1158,93 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
return ERROR_SUCCESS;
}
static UINT msi_stream_name( const MSITABLEVIEW *tv, UINT row, LPWSTR *pstname )
{
LPWSTR p, stname = NULL;
UINT i, r, type, ival;
DWORD len;
LPCWSTR sval;
MSIVIEW *view = (MSIVIEW *) tv;
TRACE("%p %d\n", tv, row);
len = lstrlenW( tv->name ) + 1;
stname = msi_alloc( len*sizeof(WCHAR) );
if ( !stname )
{
r = ERROR_OUTOFMEMORY;
goto err;
}
lstrcpyW( stname, tv->name );
for ( i = 0; i < tv->num_cols; i++ )
{
type = tv->columns[i].type;
if ( type & MSITYPE_KEY )
{
static const WCHAR szDot[] = { '.', 0 };
r = TABLE_fetch_int( view, row, i+1, &ival );
if ( r != ERROR_SUCCESS )
goto err;
if ( tv->columns[i].type & MSITYPE_STRING )
{
sval = msi_string_lookup_id( tv->db->strings, ival );
if ( !sval )
{
r = ERROR_INVALID_PARAMETER;
goto err;
}
}
else
{
static const WCHAR fmt[] = { '%','d',0 };
WCHAR number[0x20];
UINT n = bytes_per_column( tv->db, &tv->columns[i] );
switch( n )
{
case 2:
sprintfW( number, fmt, ival^0x8000 );
break;
case 4:
sprintfW( number, fmt, ival^0x80000000 );
break;
default:
ERR( "oops - unknown column width %d\n", n );
r = ERROR_FUNCTION_FAILED;
goto err;
}
sval = number;
}
len += lstrlenW( szDot ) + lstrlenW( sval );
p = msi_realloc ( stname, len*sizeof(WCHAR) );
if ( !p )
{
r = ERROR_OUTOFMEMORY;
goto err;
}
stname = p;
lstrcatW( stname, szDot );
lstrcatW( stname, sval );
}
else
continue;
}
*pstname = stname;
return ERROR_SUCCESS;
err:
msi_free( stname );
*pstname = NULL;
return r;
}
/*
* We need a special case for streams, as we need to reference column with
* the name of the stream in the same table, and the table name
@ -1166,58 +1253,19 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT ival = 0, refcol = 0, r;
LPCWSTR sval;
LPWSTR full_name;
DWORD len;
static const WCHAR szDot[] = { '.', 0 };
WCHAR number[0x20];
UINT r;
LPWSTR full_name = NULL;
if( !view->ops->fetch_int )
return ERROR_INVALID_PARAMETER;
/*
* The column marked with the type stream data seems to have a single number
* which references the column containing the name of the stream data
*
* Fetch the column to reference first.
*/
r = view->ops->fetch_int( view, row, col, &ival );
if( r != ERROR_SUCCESS )
r = msi_stream_name( tv, row, &full_name );
if ( r != ERROR_SUCCESS )
{
ERR("fetching stream, error = %d\n", r);
return r;
/* check the column value is in range */
if (ival > tv->num_cols || ival == col)
{
ERR("bad column ref (%u) for stream\n", ival);
return ERROR_FUNCTION_FAILED;
}
if ( tv->columns[ival - 1].type & MSITYPE_STRING )
{
/* now get the column with the name of the stream */
r = view->ops->fetch_int( view, row, ival, &refcol );
if ( r != ERROR_SUCCESS )
return r;
/* lookup the string value from the string table */
sval = msi_string_lookup_id( tv->db->strings, refcol );
if ( !sval )
return ERROR_INVALID_PARAMETER;
}
else
{
static const WCHAR fmt[] = { '%','d',0 };
sprintfW( number, fmt, ival );
sval = number;
}
len = lstrlenW( tv->name ) + 2 + lstrlenW( sval );
full_name = msi_alloc( len*sizeof(WCHAR) );
lstrcpyW( full_name, tv->name );
lstrcatW( full_name, szDot );
lstrcatW( full_name, sval );
r = db_get_raw_stream( tv->db, full_name, stm );
if( r )
ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r);
@ -1285,6 +1333,46 @@ static UINT TABLE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
return msi_view_get_row(tv->db, view, row, rec);
}
static UINT msi_addstreamW( MSIDATABASE *db, LPCWSTR name, IStream *data )
{
UINT r;
MSIQUERY *query = NULL;
MSIRECORD *rec = NULL;
static const WCHAR insert[] = {
'I','N','S','E','R','T',' ','I','N','T','O',' ',
'`','_','S','t','r','e','a','m','s','`',' ',
'(','`','N','a','m','e','`',',',
'`','D','a','t','a','`',')',' ',
'V','A','L','U','E','S',' ','(','?',',','?',')',0};
TRACE("%p %s %p\n", db, debugstr_w(name), data);
rec = MSI_CreateRecord( 2 );
if ( !rec )
return ERROR_OUTOFMEMORY;
r = MSI_RecordSetStringW( rec, 1, name );
if ( r != ERROR_SUCCESS )
goto err;
r = MSI_RecordSetIStream( rec, 2, data );
if ( r != ERROR_SUCCESS )
goto err;
r = MSI_DatabaseOpenViewW( db, insert, &query );
if ( r != ERROR_SUCCESS )
goto err;
r = MSI_ViewExecute( query, rec );
err:
msiobj_release( &query->hdr );
msiobj_release( &rec->hdr );
return r;
}
static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
@ -1315,6 +1403,27 @@ static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UI
{
if ( MSITYPE_IS_BINARY(tv->columns[ i ].type) )
{
IStream *stm;
LPWSTR stname;
r = MSI_RecordGetIStream( rec, i + 1, &stm );
if ( r != ERROR_SUCCESS )
return r;
r = msi_stream_name( tv, row, &stname );
if ( r != ERROR_SUCCESS )
{
IStream_Release( stm );
return r;
}
r = msi_addstreamW( tv->db, stname, stm );
IStream_Release( stm );
msi_free ( stname );
if ( r != ERROR_SUCCESS )
return r;
val = 1; /* refers to the first key column */
}
else if ( tv->columns[i].type & MSITYPE_STRING )

View File

@ -1524,18 +1524,18 @@ static void test_binary(void)
query = "SELECT * FROM `_Streams`";
r = do_query( hdb, query, &rec );
todo_wine ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
size = MAX_PATH;
r = MsiRecordGetString( rec, 1, file, &size );
todo_wine ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
todo_wine ok( !lstrcmp(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file );
ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
ok( !lstrcmp(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file );
size = MAX_PATH;
memset( buf, 0, MAX_PATH );
r = MsiRecordReadStream( rec, 2, buf, &size );
todo_wine ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
todo_wine ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
r = MsiCloseHandle( rec );
ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
@ -1553,8 +1553,8 @@ static void test_binary(void)
size = MAX_PATH;
memset( buf, 0, MAX_PATH );
r = MsiRecordReadStream( rec, 3, buf, &size );
todo_wine ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
todo_wine ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
r = MsiCloseHandle( rec );
ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
@ -6982,12 +6982,9 @@ static void test_dbmerge(void)
size = MAX_PATH;
ZeroMemory(buf, MAX_PATH);
r = MsiRecordReadStream(hrec, 2, buf, &size);
todo_wine
{
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
ok(!lstrcmpA(buf, "binary.dat\n"),
"Expected \"binary.dat\\n\", got \"%s\"\n", buf);
}
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
ok(!lstrcmpA(buf, "binary.dat\n"),
"Expected \"binary.dat\\n\", got \"%s\"\n", buf);
MsiCloseHandle(hrec);