2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002-2004, Mike McCormack for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msi);
39 typedef struct _msistring
48 UINT count; /* the number of strings */
50 msistring *strings; /* an array of strings (in the tree) */
53 static int msistring_makehash( const char *str )
61 hash = (hash<<5) || (hash>>27);
66 string_table *msi_init_stringtable( int entries )
70 st = HeapAlloc( GetProcessHeap(), 0, sizeof (string_table) );
73 st->strings = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
74 sizeof (msistring) * entries );
77 HeapFree( GetProcessHeap(), 0, st );
86 VOID msi_destroy_stringtable( string_table *st )
90 for( i=0; i<st->count; i++ )
92 if( st->strings[i].refcount )
93 HeapFree( GetProcessHeap(), 0, st->strings[i].str );
95 HeapFree( GetProcessHeap(), 0, st->strings );
96 HeapFree( GetProcessHeap(), 0, st );
99 static int st_find_free_entry( string_table *st )
104 for( i = st->freeslot; i < st->count; i++ )
105 if( !st->strings[i].refcount )
107 for( i = 1; i < st->freeslot; i++ )
108 if( !st->strings[i].refcount )
111 /* dynamically resize */
112 sz = st->count + 1 + st->count/2;
113 p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
114 st->strings, sz*sizeof(msistring) );
118 st->freeslot = st->count;
120 if( st->strings[st->freeslot].refcount )
121 ERR("oops. expected freeslot to be free...\n");
125 static void st_mark_entry_used( string_table *st, int n )
129 st->freeslot = n + 1;
132 int msi_addstring( string_table *st, UINT n, const CHAR *data, UINT len, UINT refcount )
138 if( st->strings[n].refcount )
143 if( ERROR_SUCCESS == msi_string2idA( st, data, &n ) )
145 st->strings[n].refcount++;
148 n = st_find_free_entry( st );
153 /* allocate a new string */
155 len = strlen( data );
156 st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, len + 1 );
157 if( !st->strings[n].str )
159 memcpy( st->strings[n].str, data, len );
160 st->strings[n].str[len] = 0;
161 st->strings[n].refcount = 1;
162 st->strings[n].hash = msistring_makehash( st->strings[n].str );
164 st_mark_entry_used( st, n );
169 int msi_addstringW( string_table *st, UINT n, const WCHAR *data, UINT len, UINT refcount )
173 /* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */
179 if( st->strings[n].refcount )
184 if( ERROR_SUCCESS == msi_string2id( st, data, &n ) )
186 st->strings[n].refcount++;
189 n = st_find_free_entry( st );
194 /* allocate a new string */
195 sz = WideCharToMultiByte( CP_UTF8, 0, data, len, NULL, 0, NULL, NULL );
196 st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, sz + 1 );
197 if( !st->strings[n].str )
199 WideCharToMultiByte( CP_UTF8, 0, data, len,
200 st->strings[n].str, sz, NULL, NULL );
201 st->strings[n].str[sz] = 0;
202 st->strings[n].refcount = 1;
203 st->strings[n].hash = msistring_makehash( st->strings[n].str );
205 st_mark_entry_used( st, n );
210 /* find the string identified by an id - return null if there's none */
211 static const char *string_lookup_id( string_table *st, UINT id )
216 if( id >= st->count )
219 if( id && !st->strings[id].refcount )
222 return st->strings[id].str;
228 * [in] st - pointer to the string table
229 * [in] id - id of the string to retreive
230 * [out] buffer - destination of the string
231 * [in/out] sz - number of bytes available in the buffer on input
232 * number of bytes used on output
234 * The size includes the terminating nul character. Short buffers
235 * will be filled, but not nul terminated.
237 UINT msi_id2stringW( string_table *st, UINT id, LPWSTR buffer, UINT *sz )
242 TRACE("Finding string %d of %d\n", id, st->count);
244 str = string_lookup_id( st, id );
246 return ERROR_FUNCTION_FAILED;
248 len = MultiByteToWideChar(CP_UTF8,0,str,-1,NULL,0);
253 return ERROR_SUCCESS;
256 *sz = MultiByteToWideChar(CP_UTF8,0,str,-1,buffer,*sz);
258 return ERROR_SUCCESS;
264 * [in] st - pointer to the string table
265 * [in] id - id of the string to retreive
266 * [out] buffer - destination of the UTF8 string
267 * [in/out] sz - number of bytes available in the buffer on input
268 * number of bytes used on output
270 * The size includes the terminating nul character. Short buffers
271 * will be filled, but not nul terminated.
273 UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz )
278 TRACE("Finding string %d of %d\n", id, st->count);
280 str = string_lookup_id( st, id );
282 return ERROR_FUNCTION_FAILED;
284 len = strlen( str ) + 1;
289 return ERROR_SUCCESS;
294 memcpy( buffer, str, *sz );
297 return ERROR_SUCCESS;
303 * [in] st - pointer to the string table
304 * [in] str - UTF8 string to find in the string table
305 * [out] id - id of the string, if found
307 UINT msi_string2idA( string_table *st, LPCSTR str, UINT *id )
310 UINT i, r = ERROR_INVALID_PARAMETER;
312 hash = msistring_makehash( str );
313 for( i=0; i<st->count; i++ )
315 if( ( st->strings[i].hash == hash ) &&
316 !strcmp( st->strings[i].str, str ) )
327 UINT msi_string2id( string_table *st, LPCWSTR buffer, UINT *id )
330 UINT r = ERROR_INVALID_PARAMETER;
333 TRACE("Finding string %s in string table\n", debugstr_w(buffer) );
338 return ERROR_SUCCESS;
341 sz = WideCharToMultiByte( CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL );
344 str = HeapAlloc( GetProcessHeap(), 0, sz );
346 return ERROR_NOT_ENOUGH_MEMORY;
347 WideCharToMultiByte( CP_UTF8, 0, buffer, -1, str, sz, NULL, NULL );
349 r = msi_string2idA( st, str, id );
351 HeapFree( GetProcessHeap(), 0, str );
357 UINT msi_string_count( string_table *st )
362 UINT msi_id_refcount( string_table *st, UINT i )
366 return st->strings[i].refcount;
369 UINT msi_string_totalsize( string_table *st )
373 for( i=0; i<st->count; i++)
375 if( st->strings[i].str )
376 size += strlen( st->strings[i].str );