From: Theodoros Chatzigiannakis <tchatzigiannakis@gmail.com> --- dlls/msi/table.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/dlls/msi/table.c b/dlls/msi/table.c index 44de70841ea..ab3bb5dab2f 100644 --- a/dlls/msi/table.c +++ b/dlls/msi/table.c @@ -394,11 +394,12 @@ static UINT table_get_row_size( MSIDATABASE *db, const struct column_info *cols, static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg ) { BYTE *rawdata = NULL; - UINT rawsize = 0, i, j, row_size, row_size_mem; + UINT rawsize = 0, i, j, row_size, row_size_mem, bytes_per_strref; TRACE("%s\n",debugstr_w(t->name)); - row_size = table_get_row_size( db, t->colinfo, t->col_count, db->bytes_per_strref ); + bytes_per_strref = db->bytes_per_strref; + row_size = table_get_row_size( db, t->colinfo, t->col_count, bytes_per_strref ); row_size_mem = table_get_row_size( db, t->colinfo, t->col_count, LONG_STR_BYTES ); /* if we can't read the table, just assume that it's empty */ @@ -408,6 +409,21 @@ static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg TRACE("Read %d bytes\n", rawsize ); + /* Check if table data was written with a different bytes_per_strref than the database. + * Some installers create MSI files with mismatched string reference sizes. + * Skip system tables (_Columns, _Tables) as they may be updated during transforms. */ + if (bytes_per_strref == LONG_STR_BYTES && t->name[0] != '_') + { + UINT alt_row_size = table_get_row_size( db, t->colinfo, t->col_count, sizeof(USHORT) ); + if (alt_row_size != row_size && rawsize % alt_row_size == 0 && rawsize / alt_row_size > rawsize / row_size) + { + WARN("Table %s: detected 2-byte string refs (rawsize %u fits %u rows vs %u with db bytes_per_strref)\n", + debugstr_w(t->name), rawsize, rawsize / alt_row_size, rawsize / row_size); + bytes_per_strref = sizeof(USHORT); + row_size = alt_row_size; + } + } + if( rawsize % row_size ) { /* MSI files may have streams padded to 4-byte alignment */ @@ -442,7 +458,7 @@ static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg for (j = 0; j < t->col_count; j++) { UINT m = bytes_per_column( db, &t->colinfo[j], LONG_STR_BYTES ); - UINT n = bytes_per_column( db, &t->colinfo[j], db->bytes_per_strref ); + UINT n = bytes_per_column( db, &t->colinfo[j], bytes_per_strref ); UINT k; if ( n != 2 && n != 3 && n != 4 ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10114