include: Use ULONG instead of unsigned long in ipexport.h.
[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  * StringTableLookUpString [SETUPAPI.@]
450  *
451  * Searches a string table 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  *
459  * RETURNS
460  *     Success: String ID
461  *     Failure: -1
462  */
463 DWORD WINAPI
464 StringTableLookUpString(HSTRING_TABLE hStringTable,
465                         LPWSTR lpString,
466                         DWORD dwFlags)
467 {
468     PSTRING_TABLE pStringTable;
469     DWORD i;
470
471     TRACE("%p %s %x\n", hStringTable, debugstr_w(lpString), dwFlags);
472
473     pStringTable = (PSTRING_TABLE)hStringTable;
474     if (pStringTable == NULL)
475     {
476         ERR("Invalid hStringTable!\n");
477         return (DWORD)-1;
478     }
479
480     /* Search for existing string in the string table */
481     for (i = 0; i < pStringTable->dwMaxSlots; i++)
482     {
483         if (pStringTable->pSlots[i].pString != NULL)
484         {
485             if (dwFlags & 1)
486             {
487                 if (!lstrcmpW(pStringTable->pSlots[i].pString, lpString))
488                     return i + 1;
489             }
490             else
491             {
492                 if (!lstrcmpiW(pStringTable->pSlots[i].pString, lpString))
493                     return i + 1;
494             }
495         }
496     }
497
498     return (DWORD)-1;
499 }
500
501
502 /**************************************************************************
503  * StringTableLookUpStringEx [SETUPAPI.@]
504  *
505  * Searches a string table and extra data for a given string.
506  *
507  * PARAMS
508  *     hStringTable [I] Handle to the string table
509  *     lpString     [I] String to be searched for
510  *     dwFlags      [I] Flags
511  *                        1: case sensitive compare
512  *     lpExtraData  [O] Pointer to the buffer that receives the extra data
513  *     lpReserved   [I/O] Unused
514  *
515  * RETURNS
516  *     Success: String ID
517  *     Failure: -1
518  */
519 DWORD WINAPI
520 StringTableLookUpStringEx(HSTRING_TABLE hStringTable,
521                           LPWSTR lpString,
522                           DWORD dwFlags,
523                           LPVOID lpExtraData,
524                           LPDWORD lpReserved)
525 {
526     FIXME("\n");
527     return (DWORD)-1;
528 }
529
530
531 /**************************************************************************
532  * StringTableSetExtraData [SETUPAPI.@]
533  *
534  * Sets extra data for a given string table entry.
535  *
536  * PARAMS
537  *     hStringTable    [I] Handle to the string table
538  *     dwId            [I] String ID
539  *     lpExtraData     [I] Pointer to the extra data
540  *     dwExtraDataSize [I] Size of the extra data
541  *
542  * RETURNS
543  *     Success: TRUE
544  *     Failure: FALSE
545  */
546 BOOL WINAPI
547 StringTableSetExtraData(HSTRING_TABLE hStringTable,
548                         DWORD dwId,
549                         LPVOID lpExtraData,
550                         DWORD dwExtraDataSize)
551 {
552     PSTRING_TABLE pStringTable;
553
554     TRACE("%p %x %p %u\n",
555           hStringTable, dwId, lpExtraData, dwExtraDataSize);
556
557     pStringTable = (PSTRING_TABLE)hStringTable;
558     if (pStringTable == NULL)
559     {
560         ERR("Invalid hStringTable!\n");
561         return FALSE;
562     }
563
564     if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
565     {
566         ERR("Invalid Slot id!\n");
567         return FALSE;
568     }
569
570     if (pStringTable->dwMaxDataSize < dwExtraDataSize)
571     {
572         ERR("Data size is too large!\n");
573         return FALSE;
574     }
575
576     pStringTable->pSlots[dwId - 1].pData = MyMalloc(dwExtraDataSize);
577     if (pStringTable->pSlots[dwId - 1].pData == NULL)
578     {
579         ERR("\n");
580         return FALSE;
581     }
582
583     memcpy(pStringTable->pSlots[dwId - 1].pData,
584            lpExtraData,
585            dwExtraDataSize);
586     pStringTable->pSlots[dwId - 1].dwSize = dwExtraDataSize;
587
588     return TRUE;
589 }
590
591
592 /**************************************************************************
593  * StringTableStringFromId [SETUPAPI.@]
594  *
595  * Returns a pointer to a string for the given string ID.
596  *
597  * PARAMS
598  *     hStringTable [I] Handle to the string table.
599  *     dwId         [I] String ID
600  *
601  * RETURNS
602  *     Success: Pointer to the string
603  *     Failure: NULL
604  */
605 LPWSTR WINAPI
606 StringTableStringFromId(HSTRING_TABLE hStringTable,
607                         DWORD dwId)
608 {
609     PSTRING_TABLE pStringTable;
610     static WCHAR empty[] = {0};
611
612     TRACE("%p %x\n", hStringTable, dwId);
613
614     pStringTable = (PSTRING_TABLE)hStringTable;
615     if (pStringTable == NULL)
616     {
617         ERR("Invalid hStringTable!\n");
618         return NULL;
619     }
620
621     if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
622         return empty;
623
624     return pStringTable->pSlots[dwId - 1].pString;
625 }
626
627
628 /**************************************************************************
629  * StringTableStringFromIdEx [SETUPAPI.@]
630  *
631  * Returns a string for the given string ID.
632  *
633  * PARAMS
634  *     hStringTable [I] Handle to the string table
635  *     dwId         [I] String ID
636  *     lpBuffer     [I] Pointer to string buffer
637  *     lpBufferSize [I/O] Pointer to the size of the string buffer
638  *
639  * RETURNS
640  *     Success: TRUE
641  *     Failure: FALSE
642  */
643 BOOL WINAPI
644 StringTableStringFromIdEx(HSTRING_TABLE hStringTable,
645                           DWORD dwId,
646                           LPWSTR lpBuffer,
647                           LPDWORD lpBufferLength)
648 {
649     PSTRING_TABLE pStringTable;
650     DWORD dwLength;
651     BOOL bResult = FALSE;
652
653     TRACE("%p %x %p %p\n", hStringTable, dwId, lpBuffer, lpBufferLength);
654
655     pStringTable = (PSTRING_TABLE)hStringTable;
656     if (pStringTable == NULL)
657     {
658         ERR("Invalid hStringTable!\n");
659         *lpBufferLength = 0;
660         return FALSE;
661     }
662
663     if (dwId == 0 || dwId > pStringTable->dwMaxSlots ||
664         pStringTable->pSlots[dwId - 1].pString == NULL)
665     {
666         WARN("Invalid string ID!\n");
667         *lpBufferLength = 0;
668         return FALSE;
669     }
670
671     dwLength = (lstrlenW(pStringTable->pSlots[dwId - 1].pString) + 1) * sizeof(WCHAR);
672     if (dwLength <= *lpBufferLength)
673     {
674         lstrcpyW(lpBuffer, pStringTable->pSlots[dwId - 1].pString);
675         bResult = TRUE;
676     }
677
678     *lpBufferLength = dwLength;
679
680     return bResult;
681 }
682
683
684 /**************************************************************************
685  * StringTableTrim [SETUPAPI.@]
686  *
687  * ...
688  *
689  * PARAMS
690  *     hStringTable [I] Handle to the string table
691  *
692  * RETURNS
693  *     None
694  */
695 VOID WINAPI
696 StringTableTrim(HSTRING_TABLE hStringTable)
697 {
698     FIXME("%p\n", hStringTable);
699 }