setupapi: Implement StringTableLookUpStringEx.
[wine] / dlls / setupapi / stringtable.c
1 /*
2  * Setupapi string table functions
3  *
4  * Copyright 2005 Eric Kohl
5  *
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.
10  *
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.
15  *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #include "setupapi.h"
32
33 #include "wine/debug.h"
34
35
36 #define TABLE_DEFAULT_SIZE 256
37
38 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
39
40 DECLARE_HANDLE(HSTRING_TABLE);
41
42 typedef struct _TABLE_SLOT
43 {
44     LPWSTR pString;
45     LPVOID pData;
46     DWORD dwSize;
47 } TABLE_SLOT, *PTABLE_SLOT;
48
49 typedef struct _STRING_TABLE
50 {
51     PTABLE_SLOT pSlots;
52     DWORD dwUsedSlots;
53     DWORD dwMaxSlots;
54     DWORD dwMaxDataSize;
55 } STRING_TABLE, *PSTRING_TABLE;
56
57
58 /**************************************************************************
59  * StringTableInitialize [SETUPAPI.@]
60  *
61  * Creates a new string table and initializes it.
62  *
63  * PARAMS
64  *     None
65  *
66  * RETURNS
67  *     Success: Handle to the string table
68  *     Failure: NULL
69  */
70 HSTRING_TABLE WINAPI
71 StringTableInitialize(VOID)
72 {
73     PSTRING_TABLE pStringTable;
74
75     TRACE("\n");
76
77     pStringTable = MyMalloc(sizeof(STRING_TABLE));
78     if (pStringTable == NULL)
79     {
80         ERR("Invalid hStringTable!\n");
81         return NULL;
82     }
83
84     memset(pStringTable, 0, sizeof(STRING_TABLE));
85
86     pStringTable->pSlots = MyMalloc(sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE);
87     if (pStringTable->pSlots == NULL)
88     {
89         MyFree(pStringTable);
90         return NULL;
91     }
92
93     memset(pStringTable->pSlots, 0, sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE);
94
95     pStringTable->dwUsedSlots = 0;
96     pStringTable->dwMaxSlots = TABLE_DEFAULT_SIZE;
97     pStringTable->dwMaxDataSize = 0;
98
99     TRACE("Done\n");
100
101     return (HSTRING_TABLE)pStringTable;
102 }
103
104
105 /**************************************************************************
106  * StringTableInitializeEx [SETUPAPI.@]
107  *
108  * Creates a new string table and initializes it.
109  *
110  * PARAMS
111  *     dwMaxExtraDataSize [I] Maximum extra data size
112  *     dwReserved         [I] Unused
113  *
114  * RETURNS
115  *     Success: Handle to the string table
116  *     Failure: NULL
117  */
118 HSTRING_TABLE WINAPI
119 StringTableInitializeEx(DWORD dwMaxExtraDataSize,
120                         DWORD dwReserved)
121 {
122     PSTRING_TABLE pStringTable;
123
124     TRACE("\n");
125
126     pStringTable = MyMalloc(sizeof(STRING_TABLE));
127     if (pStringTable == NULL) return NULL;
128
129     memset(pStringTable, 0, sizeof(STRING_TABLE));
130
131     pStringTable->pSlots = MyMalloc(sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE);
132     if (pStringTable->pSlots == NULL)
133     {
134         MyFree(pStringTable);
135         return NULL;
136     }
137
138     memset(pStringTable->pSlots, 0, sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE);
139
140     pStringTable->dwUsedSlots = 0;
141     pStringTable->dwMaxSlots = TABLE_DEFAULT_SIZE;
142     pStringTable->dwMaxDataSize = dwMaxExtraDataSize;
143
144     TRACE("Done\n");
145
146     return (HSTRING_TABLE)pStringTable;
147 }
148
149
150 /**************************************************************************
151  * StringTableDestroy [SETUPAPI.@]
152  *
153  * Destroys a string table.
154  *
155  * PARAMS
156  *     hStringTable [I] Handle to the string table to be destroyed
157  *
158  * RETURNS
159  *     None
160  */
161 VOID WINAPI
162 StringTableDestroy(HSTRING_TABLE hStringTable)
163 {
164     PSTRING_TABLE pStringTable;
165     DWORD i;
166
167     TRACE("%p\n", hStringTable);
168
169     pStringTable = (PSTRING_TABLE)hStringTable;
170     if (pStringTable == NULL)
171         return;
172
173     if (pStringTable->pSlots != NULL)
174     {
175         for (i = 0; i < pStringTable->dwMaxSlots; i++)
176         {
177             MyFree(pStringTable->pSlots[i].pString);
178             pStringTable->pSlots[i].pString = NULL;
179
180             MyFree(pStringTable->pSlots[i].pData);
181             pStringTable->pSlots[i].pData = NULL;
182             pStringTable->pSlots[i].dwSize = 0;
183         }
184
185         MyFree(pStringTable->pSlots);
186     }
187
188     MyFree(pStringTable);
189 }
190
191
192 /**************************************************************************
193  * StringTableAddStringEx [SETUPAPI.@]
194  *
195  * Adds a new string plus extra data to the string table.
196  *
197  * PARAMS
198  *     hStringTable    [I] Handle to the string table
199  *     lpString        [I] String to be added to the string table
200  *     dwFlags         [I] Flags
201  *                           1: case sensitive compare
202  *     lpExtraData     [I] Pointer to the extra data
203  *     dwExtraDataSize [I] Size of the extra data
204  *
205  * RETURNS
206  *     Success: String ID
207  *     Failure: ~0u
208  *
209  * NOTES
210  *     If the given string already exists in the string table it will not
211  *     be added again. The ID of the existing string will be returned in
212  *     this case.
213  */
214 DWORD WINAPI
215 StringTableAddStringEx(HSTRING_TABLE hStringTable, LPWSTR lpString,
216                        DWORD dwFlags, LPVOID lpExtraData, DWORD dwExtraDataSize)
217 {
218     PSTRING_TABLE pStringTable;
219     DWORD i;
220
221     TRACE("%p %s %x %p, %u\n", hStringTable, debugstr_w(lpString), dwFlags,
222           lpExtraData, dwExtraDataSize);
223
224     pStringTable = (PSTRING_TABLE)hStringTable;
225     if (!pStringTable)
226     {
227         ERR("Invalid hStringTable!\n");
228         return ~0u;
229     }
230
231     /* Search for existing string in the string table */
232     for (i = 0; i < pStringTable->dwMaxSlots; i++)
233     {
234         if (pStringTable->pSlots[i].pString)
235         {
236             if (dwFlags & 1)
237             {
238                 if (!lstrcmpW(pStringTable->pSlots[i].pString, lpString))
239                     return i + 1;
240             }
241             else
242             {
243                 if (!lstrcmpiW(pStringTable->pSlots[i].pString, lpString))
244                     return i + 1;
245             }
246         }
247     }
248
249     /* Check for filled slot table */
250     if (pStringTable->dwUsedSlots == pStringTable->dwMaxSlots)
251     {
252         FIXME("Resize the string table!\n");
253         return ~0u;
254     }
255
256     /* Search for an empty slot */
257     for (i = 0; i < pStringTable->dwMaxSlots; i++)
258     {
259         if (!pStringTable->pSlots[i].pString)
260         {
261             pStringTable->pSlots[i].pString = MyMalloc((lstrlenW(lpString) + 1) * sizeof(WCHAR));
262             if (!pStringTable->pSlots[i].pString)
263             {
264                 WARN("Couldn't allocate memory for a new string!\n");
265                 return ~0u;
266             }
267             lstrcpyW(pStringTable->pSlots[i].pString, lpString);
268
269             pStringTable->pSlots[i].pData = MyMalloc(dwExtraDataSize);
270             if (!pStringTable->pSlots[i].pData)
271             {
272                 TRACE("Couldn't allocate memory for data!\n");
273                 return ~0u;
274             }
275             memcpy(pStringTable->pSlots[i].pData, lpExtraData, dwExtraDataSize);
276             pStringTable->dwUsedSlots++;
277             return i + 1;
278         }
279     }
280     TRACE("Couldn't find an empty slot!\n");
281     return ~0u;
282 }
283
284 /**************************************************************************
285  * StringTableAddString [SETUPAPI.@]
286  *
287  * Adds a new string to the string table.
288  *
289  * PARAMS
290  *     hStringTable [I] Handle to the string table
291  *     lpString     [I] String to be added to the string table
292  *     dwFlags      [I] Flags
293  *                        1: case sensitive compare
294  *
295  * RETURNS
296  *     Success: String ID
297  *     Failure: ~0u
298  *
299  * NOTES
300  *     If the given string already exists in the string table it will not
301  *     be added again. The ID of the existing string will be returned in
302  *     this case.
303  */
304 DWORD WINAPI
305 StringTableAddString(HSTRING_TABLE hStringTable, LPWSTR lpString, DWORD dwFlags)
306 {
307     return StringTableAddStringEx(hStringTable, lpString, dwFlags, NULL, 0);
308 }
309
310
311 /**************************************************************************
312  * StringTableDuplicate [SETUPAPI.@]
313  *
314  * Duplicates a given string table.
315  *
316  * PARAMS
317  *     hStringTable [I] Handle to the string table
318  *
319  * RETURNS
320  *     Success: Handle to the duplicated string table
321  *     Failure: NULL
322  *
323  */
324 HSTRING_TABLE WINAPI
325 StringTableDuplicate(HSTRING_TABLE hStringTable)
326 {
327     PSTRING_TABLE pSourceTable;
328     PSTRING_TABLE pDestinationTable;
329     DWORD i;
330     DWORD length;
331
332     TRACE("%p\n", hStringTable);
333
334     pSourceTable = (PSTRING_TABLE)hStringTable;
335     if (pSourceTable == NULL)
336     {
337         ERR("Invalid hStringTable!\n");
338         return NULL;
339     }
340
341     pDestinationTable = MyMalloc(sizeof(STRING_TABLE));
342     if (pDestinationTable == NULL)
343     {
344         ERR("Could not allocate a new string table!\n");
345         return NULL;
346     }
347
348     memset(pDestinationTable, 0, sizeof(STRING_TABLE));
349
350     pDestinationTable->pSlots = MyMalloc(sizeof(TABLE_SLOT) * pSourceTable->dwMaxSlots);
351     if (pDestinationTable->pSlots == NULL)
352     {
353         MyFree(pDestinationTable);
354         return NULL;
355     }
356
357     memset(pDestinationTable->pSlots, 0, sizeof(TABLE_SLOT) * pSourceTable->dwMaxSlots);
358
359     pDestinationTable->dwUsedSlots = 0;
360     pDestinationTable->dwMaxSlots = pSourceTable->dwMaxSlots;
361
362     for (i = 0; i < pSourceTable->dwMaxSlots; i++)
363     {
364         if (pSourceTable->pSlots[i].pString != NULL)
365         {
366             length = (lstrlenW(pSourceTable->pSlots[i].pString) + 1) * sizeof(WCHAR);
367             pDestinationTable->pSlots[i].pString = MyMalloc(length);
368             if (pDestinationTable->pSlots[i].pString != NULL)
369             {
370                 memcpy(pDestinationTable->pSlots[i].pString,
371                        pSourceTable->pSlots[i].pString,
372                        length);
373                 pDestinationTable->dwUsedSlots++;
374             }
375
376             if (pSourceTable->pSlots[i].pData != NULL)
377             {
378                 length = pSourceTable->pSlots[i].dwSize;
379                 pDestinationTable->pSlots[i].pData = MyMalloc(length);
380                 if (pDestinationTable->pSlots[i].pData)
381                 {
382                     memcpy(pDestinationTable->pSlots[i].pData,
383                            pSourceTable->pSlots[i].pData,
384                            length);
385                     pDestinationTable->pSlots[i].dwSize = length;
386                 }
387             }
388         }
389     }
390
391     return (HSTRING_TABLE)pDestinationTable;
392 }
393
394
395 /**************************************************************************
396  * StringTableGetExtraData [SETUPAPI.@]
397  *
398  * Retrieves extra data from a given string table entry.
399  *
400  * PARAMS
401  *     hStringTable    [I] Handle to the string table
402  *     dwId            [I] String ID
403  *     lpExtraData     [I] Pointer a buffer that receives the extra data
404  *     dwExtraDataSize [I] Size of the buffer
405  *
406  * RETURNS
407  *     Success: TRUE
408  *     Failure: FALSE
409  */
410 BOOL WINAPI
411 StringTableGetExtraData(HSTRING_TABLE hStringTable,
412                         DWORD dwId,
413                         LPVOID lpExtraData,
414                         DWORD dwExtraDataSize)
415 {
416     PSTRING_TABLE pStringTable;
417
418     TRACE("%p %x %p %u\n",
419           hStringTable, dwId, lpExtraData, dwExtraDataSize);
420
421     pStringTable = (PSTRING_TABLE)hStringTable;
422     if (pStringTable == NULL)
423     {
424         ERR("Invalid hStringTable!\n");
425         return FALSE;
426     }
427
428     if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
429     {
430         ERR("Invalid Slot id!\n");
431         return FALSE;
432     }
433
434     if (pStringTable->pSlots[dwId - 1].dwSize > dwExtraDataSize)
435     {
436         ERR("Data size is too large!\n");
437         return FALSE;
438     }
439
440     memcpy(lpExtraData,
441            pStringTable->pSlots[dwId - 1].pData,
442            dwExtraDataSize);
443
444     return TRUE;
445 }
446
447
448 /**************************************************************************
449  * StringTableLookUpStringEx [SETUPAPI.@]
450  *
451  * Searches a string table and extra data for a given string.
452  *
453  * PARAMS
454  *     hStringTable [I] Handle to the string table
455  *     lpString     [I] String to be searched for
456  *     dwFlags      [I] Flags
457  *                        1: case sensitive compare
458  *     lpExtraData  [O] Pointer to the buffer that receives the extra data
459  *     lpReserved   [I/O] Unused
460  *
461  * RETURNS
462  *     Success: String ID
463  *     Failure: -1
464  */
465 DWORD WINAPI
466 StringTableLookUpStringEx(HSTRING_TABLE hStringTable,
467                           LPWSTR lpString,
468                           DWORD dwFlags,
469                           LPVOID lpExtraData,
470                           LPDWORD lpReserved)
471 {
472     PSTRING_TABLE pStringTable;
473     DWORD i;
474
475     TRACE("%p %s %x %p, %p\n", hStringTable, debugstr_w(lpString), dwFlags,
476           lpExtraData, lpReserved);
477
478     pStringTable = (PSTRING_TABLE)hStringTable;
479     if (pStringTable == NULL)
480     {
481         ERR("Invalid hStringTable!\n");
482         return ~0u;
483     }
484
485     /* Search for existing string in the string table */
486     for (i = 0; i < pStringTable->dwMaxSlots; i++)
487     {
488         if (pStringTable->pSlots[i].pString != NULL)
489         {
490             if (dwFlags & 1)
491             {
492                 if (!lstrcmpW(pStringTable->pSlots[i].pString, lpString))
493                 {
494                     if (lpExtraData)
495                         memcpy(lpExtraData, pStringTable->pSlots[i].pData, pStringTable->pSlots[i].dwSize);
496                     return i + 1;
497                 }
498             }
499             else
500             {
501                 if (!lstrcmpiW(pStringTable->pSlots[i].pString, lpString))
502                 {
503                     if (lpExtraData)
504                         memcpy(lpExtraData, pStringTable->pSlots[i].pData, pStringTable->pSlots[i].dwSize);
505                     return i + 1;
506                 }
507             }
508         }
509     }
510     return ~0u;
511 }
512
513
514 /**************************************************************************
515  * StringTableLookUpString [SETUPAPI.@]
516  *
517  * Searches a string table for a given string.
518  *
519  * PARAMS
520  *     hStringTable [I] Handle to the string table
521  *     lpString     [I] String to be searched for
522  *     dwFlags      [I] Flags
523  *                        1: case sensitive compare
524  *
525  * RETURNS
526  *     Success: String ID
527  *     Failure: ~0u
528  */
529 DWORD WINAPI
530 StringTableLookUpString(HSTRING_TABLE hStringTable,
531                         LPWSTR lpString,
532                         DWORD dwFlags)
533 {
534     return StringTableLookUpStringEx(hStringTable, lpString, dwFlags, NULL, NULL);
535 }
536
537
538 /**************************************************************************
539  * StringTableSetExtraData [SETUPAPI.@]
540  *
541  * Sets extra data for a given string table entry.
542  *
543  * PARAMS
544  *     hStringTable    [I] Handle to the string table
545  *     dwId            [I] String ID
546  *     lpExtraData     [I] Pointer to the extra data
547  *     dwExtraDataSize [I] Size of the extra data
548  *
549  * RETURNS
550  *     Success: TRUE
551  *     Failure: FALSE
552  */
553 BOOL WINAPI
554 StringTableSetExtraData(HSTRING_TABLE hStringTable,
555                         DWORD dwId,
556                         LPVOID lpExtraData,
557                         DWORD dwExtraDataSize)
558 {
559     PSTRING_TABLE pStringTable;
560
561     TRACE("%p %x %p %u\n",
562           hStringTable, dwId, lpExtraData, dwExtraDataSize);
563
564     pStringTable = (PSTRING_TABLE)hStringTable;
565     if (pStringTable == NULL)
566     {
567         ERR("Invalid hStringTable!\n");
568         return FALSE;
569     }
570
571     if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
572     {
573         ERR("Invalid Slot id!\n");
574         return FALSE;
575     }
576
577     if (pStringTable->dwMaxDataSize < dwExtraDataSize)
578     {
579         ERR("Data size is too large!\n");
580         return FALSE;
581     }
582
583     pStringTable->pSlots[dwId - 1].pData = MyMalloc(dwExtraDataSize);
584     if (pStringTable->pSlots[dwId - 1].pData == NULL)
585     {
586         ERR("\n");
587         return FALSE;
588     }
589
590     memcpy(pStringTable->pSlots[dwId - 1].pData,
591            lpExtraData,
592            dwExtraDataSize);
593     pStringTable->pSlots[dwId - 1].dwSize = dwExtraDataSize;
594
595     return TRUE;
596 }
597
598
599 /**************************************************************************
600  * StringTableStringFromId [SETUPAPI.@]
601  *
602  * Returns a pointer to a string for the given string ID.
603  *
604  * PARAMS
605  *     hStringTable [I] Handle to the string table.
606  *     dwId         [I] String ID
607  *
608  * RETURNS
609  *     Success: Pointer to the string
610  *     Failure: NULL
611  */
612 LPWSTR WINAPI
613 StringTableStringFromId(HSTRING_TABLE hStringTable,
614                         DWORD dwId)
615 {
616     PSTRING_TABLE pStringTable;
617     static WCHAR empty[] = {0};
618
619     TRACE("%p %x\n", hStringTable, dwId);
620
621     pStringTable = (PSTRING_TABLE)hStringTable;
622     if (pStringTable == NULL)
623     {
624         ERR("Invalid hStringTable!\n");
625         return NULL;
626     }
627
628     if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
629         return empty;
630
631     return pStringTable->pSlots[dwId - 1].pString;
632 }
633
634
635 /**************************************************************************
636  * StringTableStringFromIdEx [SETUPAPI.@]
637  *
638  * Returns a string for the given string ID.
639  *
640  * PARAMS
641  *     hStringTable [I] Handle to the string table
642  *     dwId         [I] String ID
643  *     lpBuffer     [I] Pointer to string buffer
644  *     lpBufferSize [I/O] Pointer to the size of the string buffer
645  *
646  * RETURNS
647  *     Success: TRUE
648  *     Failure: FALSE
649  */
650 BOOL WINAPI
651 StringTableStringFromIdEx(HSTRING_TABLE hStringTable,
652                           DWORD dwId,
653                           LPWSTR lpBuffer,
654                           LPDWORD lpBufferLength)
655 {
656     PSTRING_TABLE pStringTable;
657     DWORD dwLength;
658     BOOL bResult = FALSE;
659
660     TRACE("%p %x %p %p\n", hStringTable, dwId, lpBuffer, lpBufferLength);
661
662     pStringTable = (PSTRING_TABLE)hStringTable;
663     if (pStringTable == NULL)
664     {
665         ERR("Invalid hStringTable!\n");
666         *lpBufferLength = 0;
667         return FALSE;
668     }
669
670     if (dwId == 0 || dwId > pStringTable->dwMaxSlots ||
671         pStringTable->pSlots[dwId - 1].pString == NULL)
672     {
673         WARN("Invalid string ID!\n");
674         *lpBufferLength = 0;
675         return FALSE;
676     }
677
678     dwLength = (lstrlenW(pStringTable->pSlots[dwId - 1].pString) + 1) * sizeof(WCHAR);
679     if (dwLength <= *lpBufferLength)
680     {
681         lstrcpyW(lpBuffer, pStringTable->pSlots[dwId - 1].pString);
682         bResult = TRUE;
683     }
684
685     *lpBufferLength = dwLength;
686
687     return bResult;
688 }
689
690
691 /**************************************************************************
692  * StringTableTrim [SETUPAPI.@]
693  *
694  * ...
695  *
696  * PARAMS
697  *     hStringTable [I] Handle to the string table
698  *
699  * RETURNS
700  *     None
701  */
702 VOID WINAPI
703 StringTableTrim(HSTRING_TABLE hStringTable)
704 {
705     FIXME("%p\n", hStringTable);
706 }