Beginnings of a script to initialize the .wine directory (with help
[wine.git] / dlls / msi / string.c
blob69dcf5960bf9e992721ebf4c135bff03e212539f
1 /*
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
21 #include <stdarg.h>
22 #include <assert.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "wine/debug.h"
28 #include "msi.h"
29 #include "msiquery.h"
30 #include "objbase.h"
31 #include "objidl.h"
32 #include "msipriv.h"
33 #include "winnls.h"
35 #include "query.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msi);
39 typedef struct _msistring
41 UINT hash;
42 UINT refcount;
43 LPSTR str;
44 } msistring;
46 struct string_table
48 UINT count; /* the number of strings */
49 UINT freeslot;
50 msistring *strings; /* an array of strings (in the tree) */
53 static int msistring_makehash( const char *str )
55 int hash = 0;
57 while( *str )
59 hash ^= *str++;
60 hash *= 53;
61 hash = (hash<<5) || (hash>>27);
63 return hash;
66 string_table *msi_init_stringtable( int entries )
68 string_table *st;
70 st = HeapAlloc( GetProcessHeap(), 0, sizeof (string_table) );
71 if( !st )
72 return NULL;
73 st->strings = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
74 sizeof (msistring) * entries );
75 if( !st )
77 HeapFree( GetProcessHeap(), 0, st );
78 return NULL;
80 st->count = entries;
81 st->freeslot = 1;
83 return st;
86 VOID msi_destroy_stringtable( string_table *st )
88 UINT i;
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 )
101 int i, sz;
102 msistring *p;
104 for( i = st->freeslot; i < st->count; i++ )
105 if( !st->strings[i].refcount )
106 return i;
107 for( i = 1; i < st->freeslot; i++ )
108 if( !st->strings[i].refcount )
109 return i;
111 /* dynamically resize */
112 sz = st->count + 1 + st->count/2;
113 p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
114 st->strings, sz*sizeof(msistring) );
115 if( !p )
116 return -1;
117 st->strings = p;
118 st->freeslot = st->count;
119 st->count = sz;
120 if( st->strings[st->freeslot].refcount )
121 ERR("oops. expected freeslot to be free...\n");
122 return st->freeslot;
125 static void st_mark_entry_used( string_table *st, int n )
127 if( n >= st->count )
128 return;
129 st->freeslot = n + 1;
132 int msi_addstring( string_table *st, UINT n, const CHAR *data, UINT len, UINT refcount )
134 if( !data[0] )
135 return 0;
136 if( n > 0 )
138 if( st->strings[n].refcount )
139 return -1;
141 else
143 if( ERROR_SUCCESS == msi_string2idA( st, data, &n ) )
145 st->strings[n].refcount++;
146 return n;
148 n = st_find_free_entry( st );
149 if( n < 0 )
150 return -1;
153 /* allocate a new string */
154 if( len < 0 )
155 len = strlen( data );
156 st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, len + 1 );
157 if( !st->strings[n].str )
158 return -1;
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 );
166 return n;
169 int msi_addstringW( string_table *st, UINT n, const WCHAR *data, UINT len, UINT refcount )
171 int sz;
173 /* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */
175 if( !data[0] )
176 return 0;
177 if( n > 0 )
179 if( st->strings[n].refcount )
180 return -1;
182 else
184 if( ERROR_SUCCESS == msi_string2id( st, data, &n ) )
186 st->strings[n].refcount++;
187 return n;
189 n = st_find_free_entry( st );
190 if( n < 0 )
191 return -1;
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 )
198 return -1;
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 );
207 return 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 )
213 if( id == 0 )
214 return "";
216 if( id >= st->count )
217 return NULL;
219 if( id && !st->strings[id].refcount )
220 return NULL;
222 return st->strings[id].str;
226 * msi_id2stringW
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 )
239 UINT len;
240 const char *str;
242 TRACE("Finding string %d of %d\n", id, st->count);
244 str = string_lookup_id( st, id );
245 if( !str )
246 return ERROR_FUNCTION_FAILED;
248 len = MultiByteToWideChar(CP_UTF8,0,str,-1,NULL,0);
250 if( !buffer )
252 *sz = len;
253 return ERROR_SUCCESS;
256 *sz = MultiByteToWideChar(CP_UTF8,0,str,-1,buffer,*sz);
258 return ERROR_SUCCESS;
262 * msi_id2stringA
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 )
275 UINT len;
276 const char *str;
278 TRACE("Finding string %d of %d\n", id, st->count);
280 str = string_lookup_id( st, id );
281 if( !str )
282 return ERROR_FUNCTION_FAILED;
284 len = strlen( str ) + 1;
286 if( !buffer )
288 *sz = len;
289 return ERROR_SUCCESS;
292 if( *sz < len )
293 *sz = len;
294 memcpy( buffer, str, *sz );
295 *sz = len;
297 return ERROR_SUCCESS;
301 * msi_string2idA
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 )
309 int hash;
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 ) )
318 r = ERROR_SUCCESS;
319 *id = i;
320 break;
324 return r;
327 UINT msi_string2id( string_table *st, LPCWSTR buffer, UINT *id )
329 DWORD sz;
330 UINT r = ERROR_INVALID_PARAMETER;
331 LPSTR str;
333 TRACE("Finding string %s in string table\n", debugstr_w(buffer) );
335 if( buffer[0] == 0 )
337 *id = 0;
338 return ERROR_SUCCESS;
341 sz = WideCharToMultiByte( CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL );
342 if( sz <= 0 )
343 return r;
344 str = HeapAlloc( GetProcessHeap(), 0, sz );
345 if( !str )
346 return ERROR_NOT_ENOUGH_MEMORY;
347 WideCharToMultiByte( CP_UTF8, 0, buffer, -1, str, sz, NULL, NULL );
349 r = msi_string2idA( st, str, id );
350 if( str )
351 HeapFree( GetProcessHeap(), 0, str );
353 return r;
357 UINT msi_string_count( string_table *st )
359 return st->count;
362 UINT msi_id_refcount( string_table *st, UINT i )
364 if( i >= st->count )
365 return 0;
366 return st->strings[i].refcount;
369 UINT msi_string_totalsize( string_table *st )
371 UINT size = 0, i;
373 for( i=0; i<st->count; i++)
375 if( st->strings[i].str )
376 size += strlen( st->strings[i].str );
378 return size;