MSI: Seperate the string table out into a seperate file, improve lookups

Mike McCormack mike at codeweavers.com
Tue Mar 16 22:13:23 CST 2004


ChangeLog:
* Seperate the string table out into a seperate file, improve lookups

-------------- next part --------------
? dlls/msi/string.c
Index: dlls/msi/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msi/Makefile.in,v
retrieving revision 1.7
diff -u -r1.7 Makefile.in
--- dlls/msi/Makefile.in	16 Mar 2004 19:38:19 -0000	1.7
+++ dlls/msi/Makefile.in	17 Mar 2004 03:27:24 -0000
@@ -15,6 +15,7 @@
 	order.c \
 	record.c \
 	select.c \
+	string.c \
 	suminfo.c \
 	table.c \
 	tokenize.c \
Index: dlls/msi/msi.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/msi.c,v
retrieving revision 1.11
diff -u -r1.11 msi.c
--- dlls/msi/msi.c	16 Mar 2004 19:18:22 -0000	1.11
+++ dlls/msi/msi.c	17 Mar 2004 03:27:25 -0000
@@ -246,7 +246,7 @@
     }
     db->storage = stg;
     db->mode = szMode;
-    ret = load_string_table( db, &db->strings);
+    ret = load_string_table( db );
     if( ret != ERROR_SUCCESS )
         goto end;
 
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.5
diff -u -r1.5 msipriv.h
--- dlls/msi/msipriv.h	16 Mar 2004 19:18:22 -0000	1.5
+++ dlls/msi/msipriv.h	17 Mar 2004 03:27:25 -0000
@@ -38,28 +38,13 @@
 struct tagMSITABLE;
 typedef struct tagMSITABLE MSITABLE;
 
-typedef struct pool_data_tag
-{
-    USHORT *data;
-    UINT size;
-} pool_data;
-
-typedef struct string_data_tag
-{
-    CHAR *data;
-    UINT size;
-} string_data;
-
-typedef struct string_table_tag
-{
-    pool_data   pool;
-    string_data info;
-} string_table;
+struct string_table;
+typedef struct string_table string_table;
 
 typedef struct tagMSIDATABASE
 {
     IStorage *storage;
-    string_table strings;
+    string_table *strings;
     LPWSTR mode;
     MSITABLE *first_table, *last_table;
 } MSIDATABASE;
@@ -167,10 +152,15 @@
 extern void free_cached_tables( MSIDATABASE *db );
 extern UINT find_cached_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table);
 extern UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table);
-extern UINT dump_string_table(MSIDATABASE *db);
-extern UINT load_string_table( MSIDATABASE *db, string_table *pst);
+extern UINT load_string_table( MSIDATABASE *db );
+
+/* string table functions */
+extern BOOL msi_addstring( string_table *st, UINT string_no, CHAR *data, UINT len, UINT refcount );
 extern UINT msi_id2string( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz );
 extern LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid);
+extern UINT msi_string2id( string_table *st, LPCWSTR buffer, UINT *id );
+extern string_table *msi_init_stringtable( int entries );
+extern VOID msi_destroy_stringtable( string_table *st );
 
 UINT VIEW_find_column( MSIVIEW *view, LPWSTR name, UINT *n );
 
Index: dlls/msi/table.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/table.c,v
retrieving revision 1.6
diff -u -r1.6 table.c
--- dlls/msi/table.c	28 Oct 2003 21:49:06 -0000	1.6
+++ dlls/msi/table.c	17 Mar 2004 03:27:25 -0000
@@ -49,8 +49,6 @@
     USHORT *data;
     UINT size;
     UINT ref_count;
-    /* MSICOLUMNINFO *columns; */
-    /* UINT num_cols; */
     struct tagMSITABLE *next;
     struct tagMSITABLE *prev;
     WCHAR name[1];
@@ -332,35 +330,22 @@
     return ERROR_SUCCESS;
 }
 
-UINT dump_string_table(MSIDATABASE *db)
-{
-    DWORD i, count, offset, len;
-    string_table *st = &db->strings;
-
-    MESSAGE("%d,%d bytes\n",st->pool.size,st->info.size);
-
-    count = st->pool.size/4;
-
-    offset = 0;
-    for(i=0; i<count; i++)
-    {
-        len = st->pool.data[i*2];
-        MESSAGE("[%2ld] = %s\n",i, debugstr_an(st->info.data+offset,len));
-        offset += len;
-    }
-
-    return ERROR_SUCCESS;
-}
-
-UINT load_string_table( MSIDATABASE *db, string_table *pst)
+UINT load_string_table( MSIDATABASE *db )
 {
     MSITABLE *pool = NULL, *info = NULL;
     UINT r, ret = ERROR_FUNCTION_FAILED;
+    DWORD i, count, offset, len;
     const WCHAR szStringData[] = { 
         '_','S','t','r','i','n','g','D','a','t','a',0 };
     const WCHAR szStringPool[] = { 
         '_','S','t','r','i','n','g','P','o','o','l',0 };
 
+    if( db->strings )
+    {
+        msi_destroy_stringtable( db->strings );
+        db->strings = NULL;
+    }
+
     r = get_table( db, szStringPool, &pool );
     if( r != ERROR_SUCCESS)
         goto end;
@@ -368,12 +353,18 @@
     if( r != ERROR_SUCCESS)
         goto end;
 
-    pst->pool.size = pool->size;
-    pst->pool.data = pool->data;
-    pst->info.size = info->size;
-    pst->info.data = (CHAR *)info->data;
+    count = pool->size/4;
+    db->strings = msi_init_stringtable( count );
+
+    offset = 0;
+    for( i=0; i<count; i++ )
+    {
+        len = pool->data[i*2];
+        msi_addstring( db->strings, i, (LPSTR)info->data+offset, len, pool->data[i*2+1] );
+        offset += len;
+    }
 
-    TRACE("Loaded %d,%d bytes\n",pst->pool.size,pst->info.size);
+    TRACE("Loaded %ld strings\n", count);
 
     ret = ERROR_SUCCESS;
 
@@ -386,78 +377,6 @@
     return ret;
 }
 
-UINT msi_id2string( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz )
-{
-    DWORD i, count, offset, len;
-
-    count = st->pool.size/4;
-    TRACE("Finding string %d of %ld\n", string_no, count);
-    if(string_no >= count)
-        return ERROR_FUNCTION_FAILED;
-
-    offset = 0;
-    for(i=0; i<string_no; i++)
-    {
-        len = st->pool.data[i*2];
-        offset += len;
-    }
-
-    len = st->pool.data[i*2];
-
-    if( !buffer )
-    {
-        *sz = len;
-        return ERROR_SUCCESS;
-    }
-
-    if( (offset+len) > st->info.size )
-        return ERROR_FUNCTION_FAILED;
-
-    len = MultiByteToWideChar(CP_ACP,0,&st->info.data[offset],len,buffer,*sz-1); 
-    buffer[len] = 0;
-    *sz = len+1;
-
-    return ERROR_SUCCESS;
-}
-
-static UINT msi_string2id( string_table *st, LPCWSTR buffer, UINT *id )
-{
-    DWORD i, count, offset, len, sz;
-    UINT r = ERROR_INVALID_PARAMETER;
-    LPSTR str;
-
-    count = st->pool.size/4;
-    TRACE("Finding string %s in %ld strings\n", debugstr_w(buffer), count);
-
-    sz = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
-    if( sz <= 0 )
-        return r;
-    str = HeapAlloc( GetProcessHeap(), 0, sz );
-    if( !str )
-        return ERROR_NOT_ENOUGH_MEMORY;
-    WideCharToMultiByte( CP_ACP, 0, buffer, -1, str, sz, NULL, NULL );
-
-    offset = 0;
-    sz--;  /* nul terminated */
-    for(i=0; i<count; i++)
-    {
-        len = st->pool.data[i*2];
-        if ( ( sz == len ) && !memcmp( str, st->info.data+offset, sz ) )
-        {
-            TRACE("%ld <- %s\n",i,debugstr_an(st->info.data+offset, len) );
-            *id = i;
-            r = ERROR_SUCCESS;
-            break;
-        }
-        offset += len;
-    }
-
-    if( str )
-        HeapFree( GetProcessHeap(), 0, str );
-
-    return r;
-}
-
 static LPWSTR strdupW( LPCWSTR str )
 {
     UINT len = lstrlenW( str ) + 1;
@@ -537,14 +456,14 @@
     UINT sz=0, r;
     LPWSTR str;
 
-    r = msi_id2string( &db->strings, stringid, NULL, &sz );
+    r = msi_id2string( db->strings, stringid, NULL, &sz );
     if( r != ERROR_SUCCESS )
         return NULL;
     sz ++; /* space for NUL char */
     str = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR));
     if( !str )
         return str;
-    r = msi_id2string( &db->strings, stringid, str, &sz );
+    r = msi_id2string( db->strings, stringid, str, &sz );
     if( r == ERROR_SUCCESS )
         return str;
     HeapFree(  GetProcessHeap(), 0, str );
@@ -571,7 +490,7 @@
     }
 
     /* convert table and column names to IDs from the string table */
-    r = msi_string2id( &db->strings, szTableName, &table_id );
+    r = msi_string2id( db->strings, szTableName, &table_id );
     if( r != ERROR_SUCCESS )
     {
         release_table( db, table );
@@ -634,7 +553,7 @@
     if( !lstrcmpW( name, szColumns ) )
         return TRUE;
 
-    r = msi_string2id( &db->strings, name, &table_id );
+    r = msi_string2id( db->strings, name, &table_id );
     if( r != ERROR_SUCCESS )
     {
         ERR("Couldn't find id for %s\n", debugstr_w(name));
--- /dev/null	1994-07-18 08:46:18.000000000 +0900
+++ dlls/msi/string.c	2004-03-17 13:10:02.000000000 +0900
@@ -0,0 +1,210 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002 Mike McCormack for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+#include <assert.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+typedef struct _msistring
+{
+    UINT hash;
+    UINT refcount;
+    LPSTR str;
+} msistring;
+
+struct string_table
+{
+    UINT count;         /* the number of strings */
+    UINT freeslot;
+    msistring *strings; /* an array of strings (in the tree) */
+};
+
+static int msistring_makehash( char *str )
+{
+    int hash = 0;
+
+    while( *str )
+    {
+        hash ^= *str++;
+        hash *= 53;
+        hash = (hash<<5) || (hash>>27);
+    }
+    return hash;
+}
+
+string_table *msi_init_stringtable( int entries )
+{
+    string_table *st;
+
+    st = HeapAlloc( GetProcessHeap(), 0, sizeof (string_table) );
+    if( !st )
+        return NULL;    
+    st->strings = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                              sizeof (msistring) * entries );
+    if( !st )
+    {
+        HeapFree( GetProcessHeap(), 0, st );
+        return NULL;    
+    }
+    st->count = entries;
+    st->freeslot = 0;
+
+    return st;
+}
+
+VOID msi_destroy_stringtable( string_table *st )
+{
+    UINT i;
+
+    for( i=0; i<st->count; i++ )
+    {
+        if( st->strings[i].refcount )
+            HeapFree( GetProcessHeap(), 0, st->strings[i].str );
+    }
+    HeapFree( GetProcessHeap(), 0, st->strings );
+    HeapFree( GetProcessHeap(), 0, st );
+}
+
+static int st_find_free_entry( string_table *st )
+{
+    int i;
+
+    for( i = st->freeslot; i < st->count; i++ )
+        if( !st->strings[i].refcount )
+            return i;
+    for( i = 0; i < st->freeslot; i++ )
+        if( !st->strings[i].refcount )
+            return i;
+
+    FIXME("dynamically resize\n");
+
+    return -1;
+}
+
+static void st_mark_entry_used( string_table *st, int n )
+{
+    if( n >= st->count )
+        return;
+    st->freeslot = n + 1;
+}
+
+int msi_addstring( string_table *st, UINT string_no, CHAR *data, UINT len, UINT refcount )
+{
+    int n;
+
+    TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) );
+
+    n = st_find_free_entry( st );
+    if( n < 0 )
+        return -1;
+
+    /* allocate a new string */
+    if( len < 0 )
+        len = strlen( data );
+    st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, len + 1 );
+    if( !st->strings[n].str )
+        return -1;
+    memcpy( st->strings[n].str, data, len );
+    st->strings[n].str[len] = 0;
+    st->strings[n].refcount = 1;
+    st->strings[n].hash = msistring_makehash( st->strings[n].str );
+
+    st_mark_entry_used( st, n );
+
+    return n;
+}
+
+UINT msi_id2string( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz )
+{
+    UINT len;
+    LPSTR str;
+
+    TRACE("Finding string %d of %d\n", string_no, st->count);
+    if( string_no >= st->count )
+        return ERROR_FUNCTION_FAILED;
+
+    if( !st->strings[string_no].refcount )
+        return ERROR_FUNCTION_FAILED;
+
+    str = st->strings[string_no].str;
+    len = strlen( str );
+
+    if( !buffer )
+    {
+        *sz = len;
+        return ERROR_SUCCESS;
+    }
+
+    len = MultiByteToWideChar(CP_ACP,0,str,len,buffer,*sz-1); 
+    buffer[len] = 0;
+    *sz = len+1;
+
+    return ERROR_SUCCESS;
+}
+
+UINT msi_string2id( string_table *st, LPCWSTR buffer, UINT *id )
+{
+    DWORD sz;
+    UINT i, r = ERROR_INVALID_PARAMETER;
+    LPSTR str;
+    int hash;
+
+    TRACE("Finding string %s in string table\n", debugstr_w(buffer) );
+
+    sz = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
+    if( sz <= 0 )
+        return r;
+    str = HeapAlloc( GetProcessHeap(), 0, sz );
+    if( !str )
+        return ERROR_NOT_ENOUGH_MEMORY;
+    WideCharToMultiByte( CP_ACP, 0, buffer, -1, str, sz, NULL, NULL );
+
+    hash = msistring_makehash( str );
+    for( i=0; i<st->count; i++)
+    {
+        if( ( st->strings[i].hash == hash ) &&
+            !strcmp( st->strings[i].str, str ) )
+        {
+            r = ERROR_SUCCESS;
+            *id = i;
+            break;
+        }
+    }
+
+    if( str )
+        HeapFree( GetProcessHeap(), 0, str );
+
+    return r;
+}
+


More information about the wine-patches mailing list