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