oleaut32: Add a test for loading/saving an empty picture.
[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->pSlots[i].dwSize = dwExtraDataSize;
277             pStringTable->dwUsedSlots++;
278             return i + 1;
279         }
280     }
281     TRACE("Couldn't find an empty slot!\n");
282     return ~0u;
283 }
284
285 /**************************************************************************
286  * StringTableAddString [SETUPAPI.@]
287  *
288  * Adds a new string to the string table.
289  *
290  * PARAMS
291  *     hStringTable [I] Handle to the string table
292  *     lpString     [I] String to be added to the string table
293  *     dwFlags      [I] Flags
294  *                        1: case sensitive compare
295  *
296  * RETURNS
297  *     Success: String ID
298  *     Failure: ~0u
299  *
300  * NOTES
301  *     If the given string already exists in the string table it will not
302  *     be added again. The ID of the existing string will be returned in
303  *     this case.
304  */
305 DWORD WINAPI
306 StringTableAddString(HSTRING_TABLE hStringTable, LPWSTR lpString, DWORD dwFlags)
307 {
308     return StringTableAddStringEx(hStringTable, lpString, dwFlags, NULL, 0);
309 }
310
311
312 /**************************************************************************
313  * StringTableDuplicate [SETUPAPI.@]
314  *
315  * Duplicates a given string table.
316  *
317  * PARAMS
318  *     hStringTable [I] Handle to the string table
319  *
320  * RETURNS
321  *     Success: Handle to the duplicated string table
322  *     Failure: NULL
323  *
324  */
325 HSTRING_TABLE WINAPI
326 StringTableDuplicate(HSTRING_TABLE hStringTable)
327 {
328     PSTRING_TABLE pSourceTable;
329     PSTRING_TABLE pDestinationTable;
330     DWORD i;
331     DWORD length;
332
333     TRACE("%p\n", hStringTable);
334
335     pSourceTable = (PSTRING_TABLE)hStringTable;
336     if (pSourceTable == NULL)
337     {
338         ERR("Invalid hStringTable!\n");
339         return NULL;
340     }
341
342     pDestinationTable = MyMalloc(sizeof(STRING_TABLE));
343     if (pDestinationTable == NULL)
344     {
345         ERR("Could not allocate a new string table!\n");
346         return NULL;
347     }
348
349     memset(pDestinationTable, 0, sizeof(STRING_TABLE));
350
351     pDestinationTable->pSlots = MyMalloc(sizeof(TABLE_SLOT) * pSourceTable->dwMaxSlots);
352     if (pDestinationTable->pSlots == NULL)
353     {
354         MyFree(pDestinationTable);
355         return NULL;
356     }
357
358     memset(pDestinationTable->pSlots, 0, sizeof(TABLE_SLOT) * pSourceTable->dwMaxSlots);
359
360     pDestinationTable->dwUsedSlots = 0;
361     pDestinationTable->dwMaxSlots = pSourceTable->dwMaxSlots;
362
363     for (i = 0; i < pSourceTable->dwMaxSlots; i++)
364     {
365         if (pSourceTable->pSlots[i].pString != NULL)
366         {
367             length = (lstrlenW(pSourceTable->pSlots[i].pString) + 1) * sizeof(WCHAR);
368             pDestinationTable->pSlots[i].pString = MyMalloc(length);
369             if (pDestinationTable->pSlots[i].pString != NULL)
370             {
371                 memcpy(pDestinationTable->pSlots[i].pString,
372                        pSourceTable->pSlots[i].pString,
373                        length);
374                 pDestinationTable->dwUsedSlots++;
375             }
376
377             if (pSourceTable->pSlots[i].pData != NULL)
378             {
379                 length = pSourceTable->pSlots[i].dwSize;
380                 pDestinationTable->pSlots[i].pData = MyMalloc(length);
381                 if (pDestinationTable->pSlots[i].pData)
382                 {
383                     memcpy(pDestinationTable->pSlots[i].pData,
384                            pSourceTable->pSlots[i].pData,
385                            length);
386                     pDestinationTable->pSlots[i].dwSize = length;
387                 }
388             }
389         }
390     }
391
392     return (HSTRING_TABLE)pDestinationTable;
393 }
394
395
396 /**************************************************************************
397  * StringTableGetExtraData [SETUPAPI.@]
398  *
399  * Retrieves extra data from a given string table entry.
400  *
401  * PARAMS
402  *     hStringTable    [I] Handle to the string table
403  *     dwId            [I] String ID
404  *     lpExtraData     [I] Pointer a buffer that receives the extra data
405  *     dwExtraDataSize [I] Size of the buffer
406  *
407  * RETURNS
408  *     Success: TRUE
409  *     Failure: FALSE
410  */
411 BOOL WINAPI
412 StringTableGetExtraData(HSTRING_TABLE hStringTable,
413                         DWORD dwId,
414                         LPVOID lpExtraData,
415                         DWORD dwExtraDataSize)
416 {
417     PSTRING_TABLE pStringTable;
418
419     TRACE("%p %x %p %u\n",
420           hStringTable, dwId, lpExtraData, dwExtraDataSize);
421
422     pStringTable = (PSTRING_TABLE)hStringTable;
423     if (pStringTable == NULL)
424     {
425         ERR("Invalid hStringTable!\n");
426         return FALSE;
427     }
428
429     if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
430     {
431         ERR("Invalid Slot id!\n");
432         return FALSE;
433     }
434
435     if (pStringTable->pSlots[dwId - 1].dwSize > dwExtraDataSize)
436     {
437         ERR("Data size is too large!\n");
438         return FALSE;
439     }
440
441     memcpy(lpExtraData,
442            pStringTable->pSlots[dwId - 1].pData,
443            dwExtraDataSize);
444
445     return TRUE;
446 }
447
448
449 /**************************************************************************
450  * StringTableLookUpStringEx [SETUPAPI.@]
451  *
452  * Searches a string table and extra data for a given string.
453  *
454  * PARAMS
455  *     hStringTable [I] Handle to the string table
456  *     lpString     [I] String to be searched for
457  *     dwFlags      [I] Flags
458  *                        1: case sensitive compare
459  *     lpExtraData  [O] Pointer to the buffer that receives the extra data
460  *     dwReserved   [I/O] Unused
461  *
462  * RETURNS
463  *     Success: String ID
464  *     Failure: -1
465  */
466 DWORD WINAPI
467 StringTableLookUpStringEx(HSTRING_TABLE hStringTable,
468                           LPWSTR lpString,
469                           DWORD dwFlags,
470                           LPVOID lpExtraData,
471                           DWORD dwReserved)
472 {
473     PSTRING_TABLE pStringTable;
474     DWORD i;
475
476     TRACE("%p %s %x %p, %x\n", hStringTable, debugstr_w(lpString), dwFlags,
477           lpExtraData, dwReserved);
478
479     pStringTable = (PSTRING_TABLE)hStringTable;
480     if (pStringTable == NULL)
481     {
482         ERR("Invalid hStringTable!\n");
483         return ~0u;
484     }
485
486     /* Search for existing string in the string table */
487     for (i = 0; i < pStringTable->dwMaxSlots; i++)
488     {
489         if (pStringTable->pSlots[i].pString != NULL)
490         {
491             if (dwFlags & 1)
492             {
493                 if (!lstrcmpW(pStringTable->pSlots[i].pString, lpString))
494                 {
495                     if (lpExtraData)
496                         memcpy(lpExtraData, pStringTable->pSlots[i].pData, dwReserved);
497                     return i + 1;
498                 }
499             }
500             else
501             {
502                 if (!lstrcmpiW(pStringTable->pSlots[i].pString, lpString))
503                 {
504                     if (lpExtraData)
505                         memcpy(lpExtraData, pStringTable->pSlots[i].pData, dwReserved);
506                     return i + 1;
507                 }
508             }
509         }
510     }
511     return ~0u;
512 }
513
514
515 /**************************************************************************
516  * StringTableLookUpString [SETUPAPI.@]
517  *
518  * Searches a string table for a given string.
519  *
520  * PARAMS
521  *     hStringTable [I] Handle to the string table
522  *     lpString     [I] String to be searched for
523  *     dwFlags      [I] Flags
524  *                        1: case sensitive compare
525  *
526  * RETURNS
527  *     Success: String ID
528  *     Failure: ~0u
529  */
530 DWORD WINAPI
531 StringTableLookUpString(HSTRING_TABLE hStringTable,
532                         LPWSTR lpString,
533                         DWORD dwFlags)
534 {
535     return StringTableLookUpStringEx(hStringTable, lpString, dwFlags, NULL, 0);
536 }
537
538
539 /**************************************************************************
540  * StringTableSetExtraData [SETUPAPI.@]
541  *
542  * Sets extra data for a given string table entry.
543  *
544  * PARAMS
545  *     hStringTable    [I] Handle to the string table
546  *     dwId            [I] String ID
547  *     lpExtraData     [I] Pointer to the extra data
548  *     dwExtraDataSize [I] Size of the extra data
549  *
550  * RETURNS
551  *     Success: TRUE
552  *     Failure: FALSE
553  */
554 BOOL WINAPI
555 StringTableSetExtraData(HSTRING_TABLE hStringTable,
556                         DWORD dwId,
557                         LPVOID lpExtraData,
558                         DWORD dwExtraDataSize)
559 {
560     PSTRING_TABLE pStringTable;
561
562     TRACE("%p %x %p %u\n",
563           hStringTable, dwId, lpExtraData, dwExtraDataSize);
564
565     pStringTable = (PSTRING_TABLE)hStringTable;
566     if (pStringTable == NULL)
567     {
568         ERR("Invalid hStringTable!\n");
569         return FALSE;
570     }
571
572     if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
573     {
574         ERR("Invalid Slot id!\n");
575         return FALSE;
576     }
577
578     if (pStringTable->dwMaxDataSize < dwExtraDataSize)
579     {
580         ERR("Data size is too large!\n");
581         return FALSE;
582     }
583
584     pStringTable->pSlots[dwId - 1].pData = MyMalloc(dwExtraDataSize);
585     if (pStringTable->pSlots[dwId - 1].pData == NULL)
586     {
587         ERR("\n");
588         return FALSE;
589     }
590
591     memcpy(pStringTable->pSlots[dwId - 1].pData,
592            lpExtraData,
593            dwExtraDataSize);
594     pStringTable->pSlots[dwId - 1].dwSize = dwExtraDataSize;
595
596     return TRUE;
597 }
598
599
600 /**************************************************************************
601  * StringTableStringFromId [SETUPAPI.@]
602  *
603  * Returns a pointer to a string for the given string ID.
604  *
605  * PARAMS
606  *     hStringTable [I] Handle to the string table.
607  *     dwId         [I] String ID
608  *
609  * RETURNS
610  *     Success: Pointer to the string
611  *     Failure: NULL
612  */
613 LPWSTR WINAPI
614 StringTableStringFromId(HSTRING_TABLE hStringTable,
615                         DWORD dwId)
616 {
617     PSTRING_TABLE pStringTable;
618     static WCHAR empty[] = {0};
619
620     TRACE("%p %x\n", hStringTable, dwId);
621
622     pStringTable = (PSTRING_TABLE)hStringTable;
623     if (pStringTable == NULL)
624     {
625         ERR("Invalid hStringTable!\n");
626         return NULL;
627     }
628
629     if (dwId == 0 || dwId > pStringTable->dwMaxSlots)
630         return empty;
631
632     return pStringTable->pSlots[dwId - 1].pString;
633 }
634
635
636 /**************************************************************************
637  * StringTableStringFromIdEx [SETUPAPI.@]
638  *
639  * Returns a string for the given string ID.
640  *
641  * PARAMS
642  *     hStringTable [I] Handle to the string table
643  *     dwId         [I] String ID
644  *     lpBuffer     [I] Pointer to string buffer
645  *     lpBufferSize [I/O] Pointer to the size of the string buffer
646  *
647  * RETURNS
648  *     Success: TRUE
649  *     Failure: FALSE
650  */
651 BOOL WINAPI
652 StringTableStringFromIdEx(HSTRING_TABLE hStringTable,
653                           DWORD dwId,
654                           LPWSTR lpBuffer,
655                           LPDWORD lpBufferLength)
656 {
657     PSTRING_TABLE pStringTable;
658     DWORD dwLength;
659     BOOL bResult = FALSE;
660
661     TRACE("%p %x %p %p\n", hStringTable, dwId, lpBuffer, lpBufferLength);
662
663     pStringTable = (PSTRING_TABLE)hStringTable;
664     if (pStringTable == NULL)
665     {
666         ERR("Invalid hStringTable!\n");
667         *lpBufferLength = 0;
668         return FALSE;
669     }
670
671     if (dwId == 0 || dwId > pStringTable->dwMaxSlots ||
672         pStringTable->pSlots[dwId - 1].pString == NULL)
673     {
674         WARN("Invalid string ID!\n");
675         *lpBufferLength = 0;
676         return FALSE;
677     }
678
679     dwLength = (lstrlenW(pStringTable->pSlots[dwId - 1].pString) + 1) * sizeof(WCHAR);
680     if (dwLength <= *lpBufferLength)
681     {
682         lstrcpyW(lpBuffer, pStringTable->pSlots[dwId - 1].pString);
683         bResult = TRUE;
684     }
685
686     *lpBufferLength = dwLength;
687
688     return bResult;
689 }
690
691
692 /**************************************************************************
693  * StringTableTrim [SETUPAPI.@]
694  *
695  * ...
696  *
697  * PARAMS
698  *     hStringTable [I] Handle to the string table
699  *
700  * RETURNS
701  *     None
702  */
703 VOID WINAPI
704 StringTableTrim(HSTRING_TABLE hStringTable)
705 {
706     FIXME("%p\n", hStringTable);
707 }