2 * Setupapi string table functions
4 * Copyright 2005 Eric Kohl
5 * Copyright 2014 Nikolay Sivov for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "setupapi_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
36 DECLARE_HANDLE(HSTRING_TABLE
);
52 #define BUCKET_COUNT 509
53 #define DEFAULT_ALLOC_SIZE 4096
58 Returned string table 'handle' is a pointer to 'struct stringtable' structure.
59 Data itself is allocated separately, pointer is stored in 'data' field.
61 Data starts with array of 509 DWORDs - lookup table. Initially all offsets in that
62 array are set to -1. Right after lookup table goes data itself, stored in linked lists.
63 Lookup table offset points to first record of 'struct stringentry' type. When more
64 than one record is present in a bucket, first record links to next one with 'nextoffset'
65 field. Last record has nextoffset == -1, same when there's only one record. String data
66 is placed right after offset, and is followed by extra data. Each record has reserved
67 'max_extra_size' bytes to store extra data, it's not compacted in any way.
69 A simple hash function is used to determine which bucket a given string belongs to (see below).
71 All offsets including returned string ids are relative to 'data' pointer. When table
72 needs to grow 'allocated' size is doubled, but offsets are always valid and preserved.
76 static inline DWORD
get_string_hash(const WCHAR
*str
, BOOL case_sensitive
)
81 WCHAR ch
= case_sensitive
? *str
: towlower(*str
);
88 return hash
% BUCKET_COUNT
;
91 static inline DWORD
*get_bucket_ptr(struct stringtable
*table
, const WCHAR
*string
, BOOL case_sensitive
)
93 DWORD hash
= get_string_hash(string
, case_sensitive
);
94 return (DWORD
*)(table
->data
+ hash
*sizeof(DWORD
));
97 static inline WCHAR
*get_string_ptr(struct stringtable
*table
, DWORD id
)
99 return (WCHAR
*)(table
->data
+ id
+ sizeof(DWORD
));
102 static inline char *get_extradata_ptr(struct stringtable
*table
, DWORD id
)
104 WCHAR
*ptrW
= get_string_ptr(table
, id
);
105 /* skip string itself */
106 return (char*)(ptrW
+ lstrlenW(ptrW
) + 1);
109 static inline BOOL
is_valid_string_id(struct stringtable
*table
, DWORD id
)
111 return (id
>= BUCKET_COUNT
*sizeof(DWORD
)) && (id
< table
->allocated
);
114 static inline int get_aligned16_size(int size
)
116 return (size
+ 15) & ~15;
119 /**************************************************************************
120 * StringTableInitializeEx [SETUPAPI.@]
122 * Creates a new string table and initializes it.
125 * max_extra_size [I] Maximum extra data size
126 * reserved [I] Unused
129 * Success: Handle to the string table
132 HSTRING_TABLE WINAPI
StringTableInitializeEx(ULONG max_extra_size
, DWORD reserved
)
134 struct stringtable
*table
;
136 TRACE("(%ld %lx)\n", max_extra_size
, reserved
);
138 table
= MyMalloc(sizeof(*table
));
139 if (!table
) return NULL
;
141 table
->allocated
= get_aligned16_size(BUCKET_COUNT
*sizeof(DWORD
) + DEFAULT_ALLOC_SIZE
);
142 table
->data
= MyMalloc(table
->allocated
);
148 table
->nextoffset
= BUCKET_COUNT
*sizeof(DWORD
);
149 /* FIXME: actually these two are not zero */
150 table
->unk
[0] = table
->unk
[1] = 0;
151 table
->max_extra_size
= max_extra_size
;
152 table
->lcid
= GetThreadLocale();
154 /* bucket area is filled with 0xff, actual string data area is zeroed */
155 memset(table
->data
, 0xff, table
->nextoffset
);
156 memset(table
->data
+ table
->nextoffset
, 0, table
->allocated
- table
->nextoffset
);
158 return (HSTRING_TABLE
)table
;
161 /**************************************************************************
162 * StringTableInitialize [SETUPAPI.@]
164 * Creates a new string table and initializes it.
170 * Success: Handle to the string table
173 HSTRING_TABLE WINAPI
StringTableInitialize(void)
175 return StringTableInitializeEx(0, 0);
178 /**************************************************************************
179 * StringTableDestroy [SETUPAPI.@]
181 * Destroys a string table.
184 * hTable [I] Handle to the string table to be destroyed
189 void WINAPI
StringTableDestroy(HSTRING_TABLE hTable
)
191 struct stringtable
*table
= (struct stringtable
*)hTable
;
193 TRACE("%p\n", table
);
202 /**************************************************************************
203 * StringTableDuplicate [SETUPAPI.@]
205 * Duplicates a given string table.
208 * hTable [I] Handle to the string table
211 * Success: Handle to the duplicated string table
215 HSTRING_TABLE WINAPI
StringTableDuplicate(HSTRING_TABLE hTable
)
217 struct stringtable
*src
= (struct stringtable
*)hTable
, *dest
;
224 dest
= MyMalloc(sizeof(*dest
));
229 dest
->data
= MyMalloc(src
->allocated
);
235 memcpy(dest
->data
, src
->data
, src
->allocated
);
236 return (HSTRING_TABLE
)dest
;
239 /**************************************************************************
240 * StringTableGetExtraData [SETUPAPI.@]
242 * Retrieves extra data from a given string table entry.
245 * hTable [I] Handle to the string table
247 * extra [I] Pointer a buffer that receives the extra data
248 * extra_size [I] Size of the buffer
254 BOOL WINAPI
StringTableGetExtraData(HSTRING_TABLE hTable
, ULONG id
, void *extra
, ULONG extra_size
)
256 struct stringtable
*table
= (struct stringtable
*)hTable
;
259 TRACE("%p %lu %p %lu\n", table
, id
, extra
, extra_size
);
264 if (!is_valid_string_id(table
, id
))
267 if (table
->max_extra_size
> extra_size
)
269 ERR("data size is too large\n");
273 extraptr
= get_extradata_ptr(table
, id
);
274 memcpy(extra
, extraptr
, extra_size
);
278 /**************************************************************************
279 * StringTableLookUpStringEx [SETUPAPI.@]
281 * Searches a string table and extra data for a given string.
284 * hTable [I] Handle to the string table
285 * string [I] String to be searched for
287 * 1: case sensitive compare
288 * extra [O] Pointer to the buffer that receives the extra data
289 * extra_size [I/O] Unused
295 DWORD WINAPI
StringTableLookUpStringEx(HSTRING_TABLE hTable
, LPWSTR string
, DWORD flags
,
296 void *extra
, ULONG extra_size
)
298 struct stringtable
*table
= (struct stringtable
*)hTable
;
299 BOOL case_sensitive
= flags
& 1;
300 struct stringentry
*entry
;
304 TRACE("%p->%p %s %lx %p, %lx\n", table
, table
->data
, debugstr_w(string
), flags
, extra
, extra_size
);
309 /* get corresponding offset */
310 offset
= *get_bucket_ptr(table
, string
, case_sensitive
);
314 /* now we're at correct bucket, do linear search for string */
316 entry
= (struct stringentry
*)(table
->data
+ offset
);
318 cmp
= wcscmp(entry
->data
, string
);
320 cmp
= lstrcmpiW(entry
->data
, string
);
323 memcpy(extra
, get_extradata_ptr(table
, offset
), extra_size
);
328 if (entry
->nextoffset
== -1)
331 offset
= entry
->nextoffset
;
332 if (offset
> table
->allocated
)
337 /**************************************************************************
338 * StringTableLookUpString [SETUPAPI.@]
340 * Searches a string table for a given string.
343 * hTable [I] Handle to the string table
344 * string [I] String to be searched for
346 * 1: case sensitive compare
352 DWORD WINAPI
StringTableLookUpString(HSTRING_TABLE hTable
, LPWSTR string
, DWORD flags
)
354 return StringTableLookUpStringEx(hTable
, string
, flags
, NULL
, 0);
357 /**************************************************************************
358 * StringTableAddStringEx [SETUPAPI.@]
360 * Adds a new string plus extra data to the string table.
363 * hTable [I] Handle to the string table
364 * string [I] String to be added to the string table
366 * 1: case sensitive compare
367 * extra [I] Pointer to the extra data
368 * extra_size [I] Size of the extra data
375 * If the given string already exists in the string table it will not
376 * be added again. The ID of the existing string will be returned in
379 DWORD WINAPI
StringTableAddStringEx(HSTRING_TABLE hTable
, LPWSTR string
,
380 DWORD flags
, void *extra
, DWORD extra_size
)
382 struct stringtable
*table
= (struct stringtable
*)hTable
;
383 BOOL case_sensitive
= flags
& 1;
384 struct stringentry
*entry
;
389 TRACE("%p %s %lx %p, %lu\n", hTable
, debugstr_w(string
), flags
, extra
, extra_size
);
394 id
= StringTableLookUpStringEx(hTable
, string
, flags
, NULL
, 0);
398 /* needed space for new record */
399 len
= sizeof(DWORD
) + (lstrlenW(string
)+1)*sizeof(WCHAR
) + table
->max_extra_size
;
400 if (table
->nextoffset
+ len
>= table
->allocated
) {
401 table
->allocated
<<= 1;
402 table
->data
= _recalloc(table
->data
, 1, table
->allocated
);
406 offset
= get_bucket_ptr(table
, string
, case_sensitive
);
408 /* bucket used for a very first time */
409 *offset
= table
->nextoffset
;
411 entry
= (struct stringentry
*)(table
->data
+ *offset
);
412 /* link existing last entry to newly added */
413 while (entry
->nextoffset
!= -1)
414 entry
= (struct stringentry
*)(table
->data
+ entry
->nextoffset
);
415 entry
->nextoffset
= table
->nextoffset
;
417 entry
= (struct stringentry
*)(table
->data
+ table
->nextoffset
);
418 entry
->nextoffset
= -1;
419 id
= table
->nextoffset
;
422 ptrW
= get_string_ptr(table
, id
);
423 lstrcpyW(ptrW
, string
);
427 /* copy extra data */
429 memcpy(get_extradata_ptr(table
, id
), extra
, extra_size
);
431 table
->nextoffset
+= len
;
435 /**************************************************************************
436 * StringTableAddString [SETUPAPI.@]
438 * Adds a new string to the string table.
441 * hTable [I] Handle to the string table
442 * string [I] String to be added to the string table
444 * 1: case sensitive compare
451 * If the given string already exists in the string table it will not
452 * be added again. The ID of the existing string will be returned in
455 DWORD WINAPI
StringTableAddString(HSTRING_TABLE hTable
, LPWSTR string
, DWORD flags
)
457 return StringTableAddStringEx(hTable
, string
, flags
, NULL
, 0);
460 /**************************************************************************
461 * StringTableSetExtraData [SETUPAPI.@]
463 * Sets extra data for a given string table entry.
466 * hTable [I] Handle to the string table
468 * extra [I] Pointer to the extra data
469 * extra_size [I] Size of the extra data
475 BOOL WINAPI
StringTableSetExtraData(HSTRING_TABLE hTable
, DWORD id
, void *extra
, ULONG extra_size
)
477 struct stringtable
*table
= (struct stringtable
*)hTable
;
480 TRACE("%p %ld %p %lu\n", hTable
, id
, extra
, extra_size
);
485 if (!is_valid_string_id(table
, id
))
488 if (table
->max_extra_size
< extra_size
)
490 ERR("data size is too large\n");
494 extraptr
= get_extradata_ptr(table
, id
);
495 memset(extraptr
, 0, table
->max_extra_size
);
496 memcpy(extraptr
, extra
, extra_size
);
501 /**************************************************************************
502 * StringTableStringFromId [SETUPAPI.@]
504 * Returns a pointer to a string for the given string ID.
507 * hTable [I] Handle to the string table.
511 * Success: Pointer to the string
514 LPWSTR WINAPI
StringTableStringFromId(HSTRING_TABLE hTable
, ULONG id
)
516 struct stringtable
*table
= (struct stringtable
*)hTable
;
517 static WCHAR empty
[] = {0};
519 TRACE("%p %ld\n", table
, id
);
524 if (!is_valid_string_id(table
, id
))
527 return get_string_ptr(table
, id
);
530 /**************************************************************************
531 * StringTableStringFromIdEx [SETUPAPI.@]
533 * Returns a string for the given string ID.
536 * hTable [I] Handle to the string table
538 * buff [I] Pointer to string buffer
539 * buflen [I/O] Pointer to the size of the string buffer
545 BOOL WINAPI
StringTableStringFromIdEx(HSTRING_TABLE hTable
, ULONG id
, LPWSTR buff
, DWORD
*buflen
)
547 struct stringtable
*table
= (struct stringtable
*)hTable
;
552 TRACE("%p %lx %p %p\n", table
, id
, buff
, buflen
);
559 if (!is_valid_string_id(table
, id
)) {
560 WARN("invalid string id\n");
565 ptrW
= get_string_ptr(table
, id
);
566 len
= (lstrlenW(ptrW
) + 1)*sizeof(WCHAR
);
568 lstrcpyW(buff
, ptrW
);
576 /**************************************************************************
577 * StringTableTrim [SETUPAPI.@]
582 * hTable [I] Handle to the string table
587 void WINAPI
StringTableTrim(HSTRING_TABLE hTable
)
589 FIXME("%p\n", hTable
);