msi [4/4]: Add support for large string tables

James Hawkins truiken at gmail.com
Thu Jun 7 18:41:51 CDT 2007


Hi,

Changelog:
* 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(-)

-- 
James Hawkins
-------------- next part --------------
diff --git a/dlls/msi/database.c b/dlls/msi/database.c
index 875f440..7adb362 100644
--- a/dlls/msi/database.c
+++ b/dlls/msi/database.c
@@ -188,10 +188,11 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath,
     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 c43f484..bc0a3f0 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( str
 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 b773a35..e816ffa 100644
--- a/dlls/msi/string.c
+++ b/dlls/msi/string.c
@@ -41,6 +41,7 @@ #include "query.h"
 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 
     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( ISt
     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( ISt
     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 2076201..9c78743 100644
--- a/dlls/msi/table.c
+++ b/dlls/msi/table.c
@@ -42,6 +42,7 @@ #include "wine/unicode.h"
 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( MSIDATABAS
        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( MSI
             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( MSIDATABAS
     count = table->row_count;
     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;
         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( MSIDATABAS
             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 tagM
         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 
         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( MSIDATAB
 
     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;
 
-- 
1.4.1


More information about the wine-patches mailing list