Moved the WindowFromPoint functionality to the server so that we can
[wine/wine-kai.git] / dlls / msi / string.c
blobfa69ebc57a1e6ffd68171352dd6bd33e01a9d966
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 "wine/unicode.h"
29 #include "msi.h"
30 #include "msiquery.h"
31 #include "objbase.h"
32 #include "objidl.h"
33 #include "msipriv.h"
34 #include "winnls.h"
36 #include "query.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40 typedef struct _msistring
42 UINT hash;
43 UINT refcount;
44 LPWSTR str;
45 } msistring;
47 struct string_table
49 UINT maxcount; /* the number of strings */
50 UINT freeslot;
51 UINT codepage;
52 msistring *strings; /* an array of strings (in the tree) */
55 static int msistring_makehash( const WCHAR *str )
57 int hash = 0;
59 while( *str )
61 hash ^= *str++;
62 hash *= 53;
63 hash = (hash<<5) || (hash>>27);
65 return hash;
68 string_table *msi_init_stringtable( int entries, UINT codepage )
70 string_table *st;
72 st = HeapAlloc( GetProcessHeap(), 0, sizeof (string_table) );
73 if( !st )
74 return NULL;
75 st->strings = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
76 sizeof (msistring) * entries );
77 if( !st )
79 HeapFree( GetProcessHeap(), 0, st );
80 return NULL;
82 if( entries < 1 )
83 entries = 1;
84 st->maxcount = entries;
85 st->freeslot = 1;
86 st->codepage = codepage;
88 return st;
91 VOID msi_destroy_stringtable( string_table *st )
93 UINT i;
95 for( i=0; i<st->maxcount; i++ )
97 if( st->strings[i].refcount )
98 HeapFree( GetProcessHeap(), 0, st->strings[i].str );
100 HeapFree( GetProcessHeap(), 0, st->strings );
101 HeapFree( GetProcessHeap(), 0, st );
104 static int st_find_free_entry( string_table *st )
106 int i, sz;
107 msistring *p;
109 TRACE("%p\n", st);
111 if( st->freeslot )
113 for( i = st->freeslot; i < st->maxcount; i++ )
114 if( !st->strings[i].refcount )
115 return i;
117 for( i = 1; i < st->maxcount; i++ )
118 if( !st->strings[i].refcount )
119 return i;
121 /* dynamically resize */
122 sz = st->maxcount + 1 + st->maxcount/2;
123 p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
124 st->strings, sz*sizeof(msistring) );
125 if( !p )
126 return -1;
127 st->strings = p;
128 st->freeslot = st->maxcount;
129 st->maxcount = sz;
130 if( st->strings[st->freeslot].refcount )
131 ERR("oops. expected freeslot to be free...\n");
132 return st->freeslot;
135 static void st_mark_entry_used( string_table *st, int n )
137 if( n >= st->maxcount )
138 return;
139 st->freeslot = n + 1;
142 int msi_addstring( string_table *st, int n, const CHAR *data, int len, UINT refcount )
144 int sz;
146 if( !data )
147 return 0;
148 if( !data[0] )
149 return 0;
150 if( n > 0 )
152 if( st->strings[n].refcount )
153 return -1;
155 else
157 if( ERROR_SUCCESS == msi_string2idA( st, data, &n ) )
159 st->strings[n].refcount++;
160 return n;
162 n = st_find_free_entry( st );
163 if( n < 0 )
164 return -1;
167 if( n < 1 )
169 ERR("invalid index adding %s (%d)\n", debugstr_a( data ), n );
170 return -1;
173 /* allocate a new string */
174 if( len < 0 )
175 len = strlen(data);
176 sz = MultiByteToWideChar( st->codepage, 0, data, len, NULL, 0 );
177 st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, (sz+1)*sizeof(WCHAR) );
178 if( !st->strings[n].str )
179 return -1;
180 MultiByteToWideChar( st->codepage, 0, data, len, st->strings[n].str, sz );
181 st->strings[n].str[sz] = 0;
182 st->strings[n].refcount = 1;
183 st->strings[n].hash = msistring_makehash( st->strings[n].str );
185 st_mark_entry_used( st, n );
187 return n;
190 int msi_addstringW( string_table *st, int n, const WCHAR *data, int len, UINT refcount )
192 /* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */
194 if( !data )
195 return 0;
196 if( !data[0] )
197 return 0;
198 if( n > 0 )
200 if( st->strings[n].refcount )
201 return -1;
203 else
205 if( ERROR_SUCCESS == msi_string2idW( st, data, &n ) )
207 st->strings[n].refcount++;
208 return n;
210 n = st_find_free_entry( st );
211 if( n < 0 )
212 return -1;
215 if( n < 1 )
217 ERR("invalid index adding %s (%d)\n", debugstr_w( data ), n );
218 return -1;
221 /* allocate a new string */
222 if(len<0)
223 len = strlenW(data);
224 TRACE("%s, n = %d len = %d\n", debugstr_w(data), n, len );
226 st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof(WCHAR) );
227 if( !st->strings[n].str )
228 return -1;
229 TRACE("%d\n",__LINE__);
230 memcpy( st->strings[n].str, data, len*sizeof(WCHAR) );
231 st->strings[n].str[len] = 0;
232 st->strings[n].refcount = 1;
233 st->strings[n].hash = msistring_makehash( st->strings[n].str );
235 st_mark_entry_used( st, n );
237 return n;
240 /* find the string identified by an id - return null if there's none */
241 const WCHAR *msi_string_lookup_id( string_table *st, UINT id )
243 static const WCHAR zero[] = { 0 };
244 if( id == 0 )
245 return zero;
247 if( id >= st->maxcount )
248 return NULL;
250 if( id && !st->strings[id].refcount )
251 return NULL;
253 return st->strings[id].str;
257 * msi_id2stringW
259 * [in] st - pointer to the string table
260 * [in] id - id of the string to retrieve
261 * [out] buffer - destination of the string
262 * [in/out] sz - number of bytes available in the buffer on input
263 * number of bytes used on output
265 * The size includes the terminating nul character. Short buffers
266 * will be filled, but not nul terminated.
268 UINT msi_id2stringW( string_table *st, UINT id, LPWSTR buffer, UINT *sz )
270 UINT len;
271 const WCHAR *str;
273 TRACE("Finding string %d of %d\n", id, st->maxcount);
275 str = msi_string_lookup_id( st, id );
276 if( !str )
277 return ERROR_FUNCTION_FAILED;
279 len = strlenW( str ) + 1;
281 if( !buffer )
283 *sz = len;
284 return ERROR_SUCCESS;
287 if( *sz < len )
288 *sz = len;
289 memcpy( buffer, str, (*sz)*sizeof(WCHAR) );
290 *sz = len;
292 return ERROR_SUCCESS;
296 * msi_id2stringA
298 * [in] st - pointer to the string table
299 * [in] id - id of the string to retrieve
300 * [out] buffer - destination of the UTF8 string
301 * [in/out] sz - number of bytes available in the buffer on input
302 * number of bytes used on output
304 * The size includes the terminating nul character. Short buffers
305 * will be filled, but not nul terminated.
307 UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz )
309 UINT len;
310 const WCHAR *str;
311 int n;
313 TRACE("Finding string %d of %d\n", id, st->maxcount);
315 str = msi_string_lookup_id( st, id );
316 if( !str )
317 return ERROR_FUNCTION_FAILED;
319 len = WideCharToMultiByte( st->codepage, 0, str, -1, NULL, 0, NULL, NULL );
321 if( !buffer )
323 *sz = len;
324 return ERROR_SUCCESS;
327 if( len > *sz )
329 n = strlenW( str ) + 1;
330 while( n && (len > *sz) )
331 len = WideCharToMultiByte( st->codepage, 0,
332 str, --n, NULL, 0, NULL, NULL );
334 else
335 n = -1;
337 *sz = WideCharToMultiByte( st->codepage, 0, str, n, buffer, len, NULL, NULL );
339 return ERROR_SUCCESS;
343 * msi_string2idW
345 * [in] st - pointer to the string table
346 * [in] str - string to find in the string table
347 * [out] id - id of the string, if found
349 UINT msi_string2idW( string_table *st, LPCWSTR str, UINT *id )
351 int hash;
352 UINT i, r = ERROR_INVALID_PARAMETER;
354 hash = msistring_makehash( str );
355 for( i=0; i<st->maxcount; i++ )
357 if( ( st->strings[i].hash == hash ) &&
358 !strcmpW( st->strings[i].str, str ) )
360 r = ERROR_SUCCESS;
361 *id = i;
362 break;
366 return r;
369 UINT msi_string2idA( string_table *st, LPCSTR buffer, UINT *id )
371 DWORD sz;
372 UINT r = ERROR_INVALID_PARAMETER;
373 LPWSTR str;
375 TRACE("Finding string %s in string table\n", debugstr_a(buffer) );
377 if( buffer[0] == 0 )
379 *id = 0;
380 return ERROR_SUCCESS;
383 sz = MultiByteToWideChar( st->codepage, 0, buffer, -1, NULL, 0 );
384 if( sz <= 0 )
385 return r;
386 str = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
387 if( !str )
388 return ERROR_NOT_ENOUGH_MEMORY;
389 MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz );
391 r = msi_string2idW( st, str, id );
392 if( str )
393 HeapFree( GetProcessHeap(), 0, str );
395 return r;
398 UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res )
400 const WCHAR *l_str, *r_str;
402 l_str = msi_string_lookup_id( st, lval );
403 if( !l_str )
404 return ERROR_INVALID_PARAMETER;
406 r_str = msi_string_lookup_id( st, rval );
407 if( !r_str )
408 return ERROR_INVALID_PARAMETER;
410 /* does this do the right thing for all UTF-8 strings? */
411 *res = strcmpW( l_str, r_str );
413 return ERROR_SUCCESS;
416 UINT msi_string_count( string_table *st )
418 return st->maxcount;
421 UINT msi_id_refcount( string_table *st, UINT i )
423 if( i >= st->maxcount )
424 return 0;
425 return st->strings[i].refcount;
428 UINT msi_string_totalsize( string_table *st, UINT *total )
430 UINT size = 0, i, len;
432 if( st->strings[0].str || st->strings[0].refcount )
433 ERR("oops. element 0 has a string\n");
434 *total = 0;
435 for( i=1; i<st->maxcount; i++ )
437 if( st->strings[i].str )
439 TRACE("[%u] = %s\n", i, debugstr_w(st->strings[i].str));
440 len = WideCharToMultiByte( st->codepage, 0,
441 st->strings[i].str, -1, NULL, 0, NULL, NULL);
442 if( len )
443 len--;
444 size += len;
445 *total = (i+1);
448 TRACE("%u/%u strings %u bytes codepage %x\n", *total, st->maxcount, size, st->codepage );
449 return size;
452 UINT msi_string_get_codepage( string_table *st )
454 return st->codepage;