From f5e1c13070d301ec7df8dd1abf54f96f6474520f Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Wed, 17 Mar 2004 20:49:59 +0000 Subject: [PATCH] Move the string table out into a separate file, improve lookups. --- dlls/msi/Makefile.in | 1 + dlls/msi/msi.c | 2 +- dlls/msi/msipriv.h | 30 +++---- dlls/msi/string.c | 209 +++++++++++++++++++++++++++++++++++++++++++ dlls/msi/table.c | 127 +++++--------------------- 5 files changed, 244 insertions(+), 125 deletions(-) create mode 100644 dlls/msi/string.c diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in index dda2a58008e..845e6b91702 100644 --- a/dlls/msi/Makefile.in +++ b/dlls/msi/Makefile.in @@ -15,6 +15,7 @@ C_SRCS = \ order.c \ record.c \ select.c \ + string.c \ suminfo.c \ table.c \ tokenize.c \ diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c index 7e2a09f4fcb..9671a3247ff 100644 --- a/dlls/msi/msi.c +++ b/dlls/msi/msi.c @@ -246,7 +246,7 @@ UINT WINAPI MsiOpenDatabaseW( } db->storage = stg; db->mode = szMode; - ret = load_string_table( db, &db->strings); + ret = load_string_table( db ); if( ret != ERROR_SUCCESS ) goto end; diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index cbddbd8b79d..bfb90518b40 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -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_table( MSIDATABASE *db, MSITABLE *table ); 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 ); diff --git a/dlls/msi/string.c b/dlls/msi/string.c new file mode 100644 index 00000000000..cee657a1ec1 --- /dev/null +++ b/dlls/msi/string.c @@ -0,0 +1,209 @@ +/* + * 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 +#include + +#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; icount; 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; icount; 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; +} diff --git a/dlls/msi/table.c b/dlls/msi/table.c index da653c17b54..df1e78a9abd 100644 --- a/dlls/msi/table.c +++ b/dlls/msi/table.c @@ -49,8 +49,6 @@ struct tagMSITABLE 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 @@ UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) 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; ipool.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 @@ UINT load_string_table( MSIDATABASE *db, string_table *pst) 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 ); - TRACE("Loaded %d,%d bytes\n",pst->pool.size,pst->info.size); + offset = 0; + for( i=0; idata[i*2]; + msi_addstring( db->strings, i, (LPSTR)info->data+offset, len, pool->data[i*2+1] ); + offset += len; + } + + TRACE("Loaded %ld strings\n", count); ret = ERROR_SUCCESS; @@ -386,78 +377,6 @@ end: 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; ipool.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; ipool.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 @@ LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid) 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 @@ UINT get_tablecolumns( MSIDATABASE *db, } /* 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 @@ BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name ) 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));