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