Commit 2e2b17f3 authored by Rob Shearman's avatar Rob Shearman Committed by Alexandre Julliard

msi: Fix transforms to work when the number of bytes per string reference…

msi: Fix transforms to work when the number of bytes per string reference differs to that of the database it is being applied to.
parent bf67b146
......@@ -577,7 +577,7 @@ extern MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR tabl
extern UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
USHORT **pdata, UINT *psz );
extern UINT read_stream_data( IStorage *stg, LPCWSTR stname,
USHORT **pdata, UINT *psz );
BYTE **pdata, UINT *psz );
extern UINT write_stream_data( IStorage *stg, LPCWSTR stname,
LPCVOID data, UINT sz, BOOL bTable );
......
......@@ -521,10 +521,10 @@ string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref )
UINT r, datasize = 0, poolsize = 0, codepage;
DWORD i, count, offset, len, n, refs;
r = read_stream_data( stg, szStringPool, &pool, &poolsize );
r = read_stream_data( stg, szStringPool, (BYTE **)&pool, &poolsize );
if( r != ERROR_SUCCESS)
goto end;
r = read_stream_data( stg, szStringData, (USHORT**)&data, &datasize );
r = read_stream_data( stg, szStringData, (BYTE **)&data, &datasize );
if( r != ERROR_SUCCESS)
goto end;
......
......@@ -263,7 +263,7 @@ void enum_stream_names( IStorage *stg )
}
UINT read_stream_data( IStorage *stg, LPCWSTR stname,
USHORT **pdata, UINT *psz )
BYTE **pdata, UINT *psz )
{
HRESULT r;
UINT ret = ERROR_FUNCTION_FAILED;
......@@ -506,7 +506,7 @@ static UINT read_table_from_storage( MSITABLE *t, IStorage *stg )
row_size = msi_table_get_row_size( t->colinfo, t->col_count );
/* if we can't read the table, just assume that it's empty */
read_stream_data( stg, t->name, (USHORT **)&rawdata, &rawsize );
read_stream_data( stg, t->name, &rawdata, &rawsize );
if( !rawdata )
return ERROR_SUCCESS;
......@@ -1752,14 +1752,27 @@ MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table )
return MSICONDITION_FALSE;
}
static UINT read_raw_int(const BYTE *data, UINT col, UINT bytes)
{
UINT ret = 0, i;
for (i = 0; i < bytes; i++)
ret += (data[col + i] << i * 8);
return ret;
}
static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string_table *st,
const USHORT *rawdata )
const BYTE *rawdata, UINT bytes_per_strref )
{
UINT i, val, ofs = 0;
USHORT mask = *rawdata++;
USHORT mask;
MSICOLUMNINFO *columns = tv->columns;
MSIRECORD *rec;
mask = rawdata[0] | (rawdata[1] << 8);
rawdata += 2;
rec = MSI_CreateRecord( tv->num_cols );
if( !rec )
return rec;
......@@ -1767,43 +1780,46 @@ static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string
TRACE("row ->\n");
for( i=0; i<tv->num_cols; i++ )
{
UINT n = bytes_per_column( &columns[i] );
if ( (mask&1) && (i>=(mask>>8)) )
break;
/* all keys must be present */
if ( (~mask&1) && (~columns[i].type & MSITYPE_KEY) && ((1<<i) & ~mask) )
continue;
switch( n )
if( (columns[i].type & MSITYPE_STRING) &&
! MSITYPE_IS_BINARY(tv->columns[i].type) )
{
case 2:
val = rawdata[ofs];
if( (columns[i].type & MSITYPE_STRING) &&
! MSITYPE_IS_BINARY(tv->columns[i].type) )
{
LPCWSTR sval = msi_string_lookup_id( st, val );
MSI_RecordSetStringW( rec, i+1, sval );
TRACE(" field %d [%s]\n", i+1, debugstr_w(sval));
}
else
LPCWSTR sval;
val = read_raw_int(rawdata, ofs, bytes_per_strref);
sval = msi_string_lookup_id( st, val );
MSI_RecordSetStringW( rec, i+1, sval );
TRACE(" field %d [%s]\n", i+1, debugstr_w(sval));
ofs += bytes_per_strref;
}
else
{
UINT n = bytes_per_column( &columns[i] );
switch( n )
{
case 2:
val = read_raw_int(rawdata, ofs, n);
if (val)
MSI_RecordSetInteger( rec, i+1, val^0x8000 );
TRACE(" field %d [0x%04x]\n", i+1, val );
break;
case 4:
val = read_raw_int(rawdata, ofs, n);
if (val)
MSI_RecordSetInteger( rec, i+1, val^0x80000000 );
TRACE(" field %d [0x%08x]\n", i+1, val );
break;
default:
ERR("oops - unknown column width %d\n", n);
break;
}
break;
case 4:
val = (rawdata[ofs] + (rawdata[ofs + 1]<<16));
if (val)
MSI_RecordSetInteger( rec, i+1, val^0x80000000 );
TRACE(" field %d [0x%08x]\n", i+1, val );
break;
default:
ERR("oops - unknown column width %d\n", n);
break;
ofs += n;
}
ofs += n/2;
}
return rec;
}
......@@ -1929,10 +1945,11 @@ static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
}
static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
string_table *st, LPCWSTR name )
string_table *st, LPCWSTR name,
UINT bytes_per_strref )
{
UINT rawsize = 0;
USHORT *rawdata = NULL;
BYTE *rawdata = NULL;
MSITABLEVIEW *tv = NULL;
UINT r, n, sz, i, mask;
MSIRECORD *rec = NULL;
......@@ -1964,9 +1981,9 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
/* interpret the data */
r = ERROR_SUCCESS;
for( n=0; n < (rawsize/2); )
for( n=0; n < rawsize; )
{
mask = rawdata[n];
mask = rawdata[n] | (rawdata[n+1] << 8);
if (mask&1)
{
......@@ -1974,23 +1991,37 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
* if the low bit is set, columns are continuous and
* the number of columns is specified in the high byte
*/
sz = 2 + tv->row_size;
sz = 2;
for( i=0; i<tv->num_cols; i++ )
{
if( (tv->columns[i].type & MSITYPE_STRING) &&
! MSITYPE_IS_BINARY(tv->columns[i].type) )
sz += bytes_per_strref;
else
sz += bytes_per_column( &tv->columns[i] );
}
}
else
{
/*
* If the low bit is not set, rowdata[n] is a bitmask.
* If the low bit is not set, mask is a bitmask.
* Excepting for key fields, which are always present,
* each bit indicates that a field is present in the transform record.
*
* rawdata[n] == 0 is a special case ... only the keys will be present
* mask == 0 is a special case ... only the keys will be present
* and it means that this row should be deleted.
*/
sz = 2;
for( i=0; i<tv->num_cols; i++ )
{
if( (tv->columns[i].type & MSITYPE_KEY) || ((1<<i)&mask))
sz += bytes_per_column( &tv->columns[i] );
{
if( (tv->columns[i].type & MSITYPE_STRING) &&
! MSITYPE_IS_BINARY(tv->columns[i].type) )
sz += bytes_per_strref;
else
sz += bytes_per_column( &tv->columns[i] );
}
}
}
......@@ -1998,11 +2029,11 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
if ( (n+sz) > rawsize )
{
ERR("borked.\n");
dump_table( st, rawdata, rawsize );
dump_table( st, (USHORT *)rawdata, rawsize );
break;
}
rec = msi_get_transform_record( tv, st, &rawdata[n] );
rec = msi_get_transform_record( tv, st, &rawdata[n], bytes_per_strref );
if (rec)
{
if ( mask & 1 )
......@@ -2058,7 +2089,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
msiobj_release( &rec->hdr );
}
n += sz/2;
n += sz;
}
err:
......@@ -2084,10 +2115,11 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
WCHAR name[0x40];
string_table *strings;
UINT ret = ERROR_FUNCTION_FAILED;
UINT bytes_per_strref;
TRACE("%p %p\n", db, stg );
strings = msi_load_string_table( stg, &db->bytes_per_strref );
strings = msi_load_string_table( stg, &bytes_per_strref );
if( !strings )
goto end;
......@@ -2099,11 +2131,11 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
* Apply _Tables and _Columns transforms first so that
* the table metadata is correct, and empty tables exist.
*/
ret = msi_table_load_transform( db, stg, strings, szTables );
ret = msi_table_load_transform( db, stg, strings, szTables, bytes_per_strref );
if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
goto end;
ret = msi_table_load_transform( db, stg, strings, szColumns );
ret = msi_table_load_transform( db, stg, strings, szColumns, bytes_per_strref );
if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
goto end;
......@@ -2128,7 +2160,7 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
!lstrcmpW( name+1, szTables ) )
continue;
ret = msi_table_load_transform( db, stg, strings, name+1 );
ret = msi_table_load_transform( db, stg, strings, name+1, bytes_per_strref );
}
if ( ret == ERROR_SUCCESS )
......
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