msi: Add support for large string tables.
This commit is contained in:
parent
8568e0a4a8
commit
a05613a9f2
|
@ -188,10 +188,11 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
|
||||||
list_init( &db->tables );
|
list_init( &db->tables );
|
||||||
list_init( &db->transforms );
|
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 )
|
if( !db->strings )
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
|
msi_table_set_strref( db->bytes_per_strref );
|
||||||
ret = ERROR_SUCCESS;
|
ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
msiobj_addref( &db->hdr );
|
msiobj_addref( &db->hdr );
|
||||||
|
|
|
@ -75,6 +75,7 @@ typedef struct tagMSIDATABASE
|
||||||
MSIOBJECTHDR hdr;
|
MSIOBJECTHDR hdr;
|
||||||
IStorage *storage;
|
IStorage *storage;
|
||||||
string_table *strings;
|
string_table *strings;
|
||||||
|
UINT bytes_per_strref;
|
||||||
LPWSTR path;
|
LPWSTR path;
|
||||||
LPWSTR deletefile;
|
LPWSTR deletefile;
|
||||||
LPCWSTR mode;
|
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 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 const WCHAR *msi_string_lookup_id( string_table *st, UINT id );
|
||||||
extern HRESULT msi_init_string_table( IStorage *stg );
|
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 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 BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name );
|
||||||
extern MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table );
|
extern MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table );
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||||
|
|
||||||
#define HASH_SIZE 0x101
|
#define HASH_SIZE 0x101
|
||||||
|
#define LONG_STR_BYTES 3
|
||||||
|
|
||||||
typedef struct _msistring
|
typedef struct _msistring
|
||||||
{
|
{
|
||||||
|
@ -507,7 +508,7 @@ HRESULT msi_init_string_table( IStorage *stg )
|
||||||
return S_OK;
|
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;
|
string_table *st = NULL;
|
||||||
CHAR *data = NULL;
|
CHAR *data = NULL;
|
||||||
|
@ -515,6 +516,8 @@ string_table *msi_load_string_table( IStorage *stg )
|
||||||
UINT r, datasize = 0, poolsize = 0, codepage;
|
UINT r, datasize = 0, poolsize = 0, codepage;
|
||||||
DWORD i, count, offset, len, n, refs;
|
DWORD i, count, offset, len, n, refs;
|
||||||
|
|
||||||
|
static const USHORT large_str_sig[] = { 0x0000, 0x8000 };
|
||||||
|
|
||||||
r = read_stream_data( stg, szStringPool, &pool, &poolsize );
|
r = read_stream_data( stg, szStringPool, &pool, &poolsize );
|
||||||
if( r != ERROR_SUCCESS)
|
if( r != ERROR_SUCCESS)
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -522,8 +525,14 @@ string_table *msi_load_string_table( IStorage *stg )
|
||||||
if( r != ERROR_SUCCESS)
|
if( r != ERROR_SUCCESS)
|
||||||
goto end;
|
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;
|
count = poolsize/4;
|
||||||
if( poolsize > 4 )
|
if( poolsize > 4 && *bytes_per_strref != LONG_STR_BYTES )
|
||||||
codepage = pool[0] | ( pool[1] << 16 );
|
codepage = pool[0] | ( pool[1] << 16 );
|
||||||
else
|
else
|
||||||
codepage = CP_ACP;
|
codepage = CP_ACP;
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||||
|
|
||||||
#define MSITABLE_HASH_TABLE_SIZE 37
|
#define MSITABLE_HASH_TABLE_SIZE 37
|
||||||
|
#define LONG_STR_BYTES 3
|
||||||
|
|
||||||
typedef struct tagMSICOLUMNHASHENTRY
|
typedef struct tagMSICOLUMNHASHENTRY
|
||||||
{
|
{
|
||||||
|
@ -113,10 +114,19 @@ static UINT get_tablecolumns( MSIDATABASE *db,
|
||||||
LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz);
|
LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz);
|
||||||
static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count );
|
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 )
|
static inline UINT bytes_per_column( const MSICOLUMNINFO *col )
|
||||||
{
|
{
|
||||||
if( col->type & MSITYPE_STRING )
|
if( col->type & MSITYPE_STRING )
|
||||||
return 2;
|
return _Columns_cols[1].offset;
|
||||||
if( (col->type & 0xff) > 4 )
|
if( (col->type & 0xff) > 4 )
|
||||||
ERR("Invalid column size!\n");
|
ERR("Invalid column size!\n");
|
||||||
return col->type & 0xff;
|
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 n = bytes_per_column( &t->colinfo[j] );
|
||||||
UINT k;
|
UINT k;
|
||||||
|
|
||||||
if ( n != 2 && n != 4 )
|
if ( n != 2 && n != 3 && n != 4 )
|
||||||
{
|
{
|
||||||
ERR("oops - unknown column width %d\n", n);
|
ERR("oops - unknown column width %d\n", n);
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -975,12 +985,12 @@ static UINT get_tablecolumns( MSIDATABASE *db,
|
||||||
count = table->row_count;
|
count = table->row_count;
|
||||||
for( i=0; i<count; i++ )
|
for( i=0; i<count; i++ )
|
||||||
{
|
{
|
||||||
if( table->data[ i ][ 0 ] != table_id )
|
if( read_table_int(table->data, i, 0, db->bytes_per_strref) != table_id )
|
||||||
continue;
|
continue;
|
||||||
if( colinfo )
|
if( colinfo )
|
||||||
{
|
{
|
||||||
UINT id = read_table_int(table->data, i, 4, sizeof(USHORT));
|
UINT id = read_table_int(table->data, i, _Columns_cols[2].offset, db->bytes_per_strref);
|
||||||
UINT col = read_table_int(table->data, i, 2, sizeof(USHORT)) - (1<<15);
|
UINT col = read_table_int(table->data, i, _Columns_cols[1].offset, sizeof(USHORT)) - (1<<15);
|
||||||
|
|
||||||
/* check the column number is in range */
|
/* check the column number is in range */
|
||||||
if (col<1 || col>maxcount)
|
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 ].tablename = msi_makestring( db, table_id );
|
||||||
colinfo[ col - 1 ].number = col;
|
colinfo[ col - 1 ].number = col;
|
||||||
colinfo[ col - 1 ].colname = msi_makestring( db, id );
|
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 ].offset = 0;
|
||||||
colinfo[ col - 1 ].hash_table = NULL;
|
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;
|
data = tv->table->data;
|
||||||
|
|
||||||
n = bytes_per_column( &tv->columns[col-1] );
|
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 );
|
ERR("oops! what is %d bytes per column?\n", n );
|
||||||
return ERROR_FUNCTION_FAILED;
|
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;
|
data = tv->table->data;
|
||||||
|
|
||||||
n = bytes_per_column( &tv->columns[col-1] );
|
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 );
|
ERR("oops! what is %d bytes per column?\n", n );
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
@ -2053,7 +2063,7 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
|
||||||
|
|
||||||
TRACE("%p %p\n", db, 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 )
|
if( !strings )
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue