From a05613a9f29914b0df425d2592f35efd8343b517 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Thu, 7 Jun 2007 16:41:51 -0700 Subject: [PATCH] msi: Add support for large string tables. --- dlls/msi/database.c | 3 ++- dlls/msi/msipriv.h | 4 +++- dlls/msi/string.c | 13 +++++++++++-- dlls/msi/table.c | 28 +++++++++++++++++++--------- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/dlls/msi/database.c b/dlls/msi/database.c index 875f440d24e..7adb362eadd 100644 --- a/dlls/msi/database.c +++ b/dlls/msi/database.c @@ -188,10 +188,11 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) list_init( &db->tables ); list_init( &db->transforms ); - db->strings = msi_load_string_table( stg ); + db->strings = msi_load_string_table( stg, &db->bytes_per_strref ); if( !db->strings ) goto end; + msi_table_set_strref( db->bytes_per_strref ); ret = ERROR_SUCCESS; msiobj_addref( &db->hdr ); diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index c43f484dac0..bc0a3f0cd7b 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -75,6 +75,7 @@ typedef struct tagMSIDATABASE MSIOBJECTHDR hdr; IStorage *storage; string_table *strings; + UINT bytes_per_strref; LPWSTR path; LPWSTR deletefile; LPCWSTR mode; @@ -556,10 +557,11 @@ extern VOID msi_destroy_stringtable( string_table *st ); extern UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res ); extern const WCHAR *msi_string_lookup_id( string_table *st, UINT id ); extern HRESULT msi_init_string_table( IStorage *stg ); -extern string_table *msi_load_string_table( IStorage *stg ); +extern string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref ); extern UINT msi_save_string_table( string_table *st, IStorage *storage ); +extern void msi_table_set_strref(UINT bytes_per_strref); extern BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name ); extern MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table ); diff --git a/dlls/msi/string.c b/dlls/msi/string.c index b773a35a2d7..e816ffa84c0 100644 --- a/dlls/msi/string.c +++ b/dlls/msi/string.c @@ -41,6 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb); #define HASH_SIZE 0x101 +#define LONG_STR_BYTES 3 typedef struct _msistring { @@ -507,7 +508,7 @@ HRESULT msi_init_string_table( IStorage *stg ) return S_OK; } -string_table *msi_load_string_table( IStorage *stg ) +string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref ) { string_table *st = NULL; CHAR *data = NULL; @@ -515,6 +516,8 @@ string_table *msi_load_string_table( IStorage *stg ) UINT r, datasize = 0, poolsize = 0, codepage; DWORD i, count, offset, len, n, refs; + static const USHORT large_str_sig[] = { 0x0000, 0x8000 }; + r = read_stream_data( stg, szStringPool, &pool, &poolsize ); if( r != ERROR_SUCCESS) goto end; @@ -522,8 +525,14 @@ string_table *msi_load_string_table( IStorage *stg ) if( r != ERROR_SUCCESS) goto end; + if ( !memcmp(pool, large_str_sig, sizeof(large_str_sig)) ) + *bytes_per_strref = LONG_STR_BYTES; + else + *bytes_per_strref = sizeof(USHORT); + + /* FIXME: don't know where the codepage is in large str tables */ count = poolsize/4; - if( poolsize > 4 ) + if( poolsize > 4 && *bytes_per_strref != LONG_STR_BYTES ) codepage = pool[0] | ( pool[1] << 16 ); else codepage = CP_ACP; diff --git a/dlls/msi/table.c b/dlls/msi/table.c index 2076201008c..9c78743ca24 100644 --- a/dlls/msi/table.c +++ b/dlls/msi/table.c @@ -42,6 +42,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb); #define MSITABLE_HASH_TABLE_SIZE 37 +#define LONG_STR_BYTES 3 typedef struct tagMSICOLUMNHASHENTRY { @@ -113,10 +114,19 @@ static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz); static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count ); + +void msi_table_set_strref(UINT bytes_per_strref) +{ + _Columns_cols[0].offset = 0; + _Columns_cols[1].offset = bytes_per_strref; + _Columns_cols[2].offset = _Columns_cols[1].offset + sizeof(USHORT); + _Columns_cols[3].offset = _Columns_cols[2].offset + bytes_per_strref; +} + static inline UINT bytes_per_column( const MSICOLUMNINFO *col ) { if( col->type & MSITYPE_STRING ) - return 2; + return _Columns_cols[1].offset; if( (col->type & 0xff) > 4 ) ERR("Invalid column size!\n"); return col->type & 0xff; @@ -525,7 +535,7 @@ static UINT read_table_from_storage( MSITABLE *t, IStorage *stg ) UINT n = bytes_per_column( &t->colinfo[j] ); UINT k; - if ( n != 2 && n != 4 ) + if ( n != 2 && n != 3 && n != 4 ) { ERR("oops - unknown column width %d\n", n); goto err; @@ -975,12 +985,12 @@ static UINT get_tablecolumns( MSIDATABASE *db, count = table->row_count; for( i=0; idata[ i ][ 0 ] != table_id ) + if( read_table_int(table->data, i, 0, db->bytes_per_strref) != table_id ) continue; if( colinfo ) { - UINT id = read_table_int(table->data, i, 4, sizeof(USHORT)); - UINT col = read_table_int(table->data, i, 2, sizeof(USHORT)) - (1<<15); + UINT id = read_table_int(table->data, i, _Columns_cols[2].offset, db->bytes_per_strref); + UINT col = read_table_int(table->data, i, _Columns_cols[1].offset, sizeof(USHORT)) - (1<<15); /* check the column number is in range */ if (col<1 || col>maxcount) @@ -999,7 +1009,7 @@ static UINT get_tablecolumns( MSIDATABASE *db, colinfo[ col - 1 ].tablename = msi_makestring( db, table_id ); colinfo[ col - 1 ].number = col; colinfo[ col - 1 ].colname = msi_makestring( db, id ); - colinfo[ col - 1 ].type = read_table_int(table->data, i, 6, sizeof(USHORT)) - (1<<15); + colinfo[ col - 1 ].type = read_table_int(table->data, i, _Columns_cols[3].offset, sizeof(USHORT)) - (1<<15); colinfo[ col - 1 ].offset = 0; colinfo[ col - 1 ].hash_table = NULL; } @@ -1112,7 +1122,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT * data = tv->table->data; n = bytes_per_column( &tv->columns[col-1] ); - if (n != 2 && n != 4) + if (n != 2 && n != 3 && n != 4) { ERR("oops! what is %d bytes per column?\n", n ); return ERROR_FUNCTION_FAILED; @@ -1227,7 +1237,7 @@ static UINT TABLE_set_int( MSITABLEVIEW *tv, UINT row, UINT col, UINT val ) data = tv->table->data; n = bytes_per_column( &tv->columns[col-1] ); - if ( n != 2 && n != 4 ) + if ( n != 2 && n != 3 && n != 4 ) { ERR("oops! what is %d bytes per column?\n", n ); return ERROR_FUNCTION_FAILED; @@ -2053,7 +2063,7 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg ) TRACE("%p %p\n", db, stg ); - strings = msi_load_string_table( stg ); + strings = msi_load_string_table( stg, &db->bytes_per_strref ); if( !strings ) goto end;