Added support for DIRID_USERPROFILE.
[wine] / dlls / setupapi / dirid.c
1 /*
2  * Directory id handling
3  *
4  * Copyright 2002 Alexandre Julliard for CodeWeavers
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winreg.h"
26 #include "winternl.h"
27 #include "winerror.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "setupapi.h"
32 #include "wine/unicode.h"
33 #include "setupapi_private.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
37
38 #define MAX_SYSTEM_DIRID DIRID_PRINTPROCESSOR
39
40 struct user_dirid
41 {
42     int    id;
43     WCHAR *str;
44 };
45
46 static int nb_user_dirids;     /* number of user dirids in use */
47 static int alloc_user_dirids;  /* number of allocated user dirids */
48 static struct user_dirid *user_dirids;
49 static const WCHAR *system_dirids[MAX_SYSTEM_DIRID+1];
50
51 /* retrieve the string for unknown dirids */
52 static const WCHAR *get_unknown_dirid(void)
53 {
54     static WCHAR *unknown_dirid;
55     static const WCHAR unknown_str[] = {'\\','u','n','k','n','o','w','n',0};
56
57     if (!unknown_dirid)
58     {
59         UINT len = GetSystemDirectoryW( NULL, 0 ) + strlenW(unknown_str);
60         if (!(unknown_dirid = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
61         GetSystemDirectoryW( unknown_dirid, len );
62         strcatW( unknown_dirid, unknown_str );
63     }
64     return unknown_dirid;
65 }
66
67 /* create the string for a system dirid */
68 static const WCHAR *create_system_dirid( int dirid )
69 {
70     static const WCHAR Null[]    = {0};
71     static const WCHAR C_Root[]  = {'C',':','\\',0};
72     static const WCHAR Drivers[] = {'\\','d','r','i','v','e','r','s',0};
73     static const WCHAR Inf[]     = {'\\','i','n','f',0};
74     static const WCHAR Help[]    = {'\\','h','e','l','p',0};
75     static const WCHAR Fonts[]   = {'\\','f','o','n','t','s',0};
76     static const WCHAR Viewers[] = {'\\','v','i','e','w','e','r','s',0};
77     static const WCHAR System[]  = {'\\','s','y','s','t','e','m',0};
78     static const WCHAR Spool[]   = {'\\','s','p','o','o','l',0};
79     static const WCHAR Profile[] = {'\\','p','r','o','f','i','l','e','s','\\','A','d','m','i','n','i','s','t','r','a','t','o','r',0};
80     static const WCHAR UserProfile[] = {'U','S','E','R','P','R','O','F','I','L','E',0};
81
82     WCHAR buffer[MAX_PATH+32], *str;
83     int len;
84
85     switch(dirid)
86     {
87     case DIRID_NULL:
88         return Null;
89     case DIRID_WINDOWS:
90         GetWindowsDirectoryW( buffer, MAX_PATH );
91         break;
92     case DIRID_SYSTEM:
93         GetSystemDirectoryW( buffer, MAX_PATH );
94         break;
95     case DIRID_DRIVERS:
96         GetSystemDirectoryW( buffer, MAX_PATH );
97         strcatW( buffer, Drivers );
98         break;
99     case DIRID_INF:
100         GetWindowsDirectoryW( buffer, MAX_PATH );
101         strcatW( buffer, Inf );
102         break;
103     case DIRID_HELP:
104         GetWindowsDirectoryW( buffer, MAX_PATH );
105         strcatW( buffer, Help );
106         break;
107     case DIRID_FONTS:
108         GetWindowsDirectoryW( buffer, MAX_PATH );
109         strcatW( buffer, Fonts );
110         break;
111     case DIRID_VIEWERS:
112         GetSystemDirectoryW( buffer, MAX_PATH );
113         strcatW( buffer, Viewers );
114         break;
115     case DIRID_APPS:
116         return C_Root;  /* FIXME */
117     case DIRID_SHARED:
118         GetWindowsDirectoryW( buffer, MAX_PATH );
119         break;
120     case DIRID_BOOT:
121         return C_Root;  /* FIXME */
122     case DIRID_SYSTEM16:
123         GetWindowsDirectoryW( buffer, MAX_PATH );
124         strcatW( buffer, System );
125         break;
126     case DIRID_SPOOL:
127     case DIRID_SPOOLDRIVERS:  /* FIXME */
128         GetWindowsDirectoryW( buffer, MAX_PATH );
129         strcatW( buffer, Spool );
130         break;
131     case DIRID_USERPROFILE:
132         if (GetEnvironmentVariableW( UserProfile, buffer, MAX_PATH )) break;
133         GetWindowsDirectoryW( buffer, MAX_PATH );
134         strcatW( buffer, Profile );
135         break;
136     case DIRID_LOADER:
137         return C_Root;  /* FIXME */
138     case DIRID_COLOR:  /* FIXME */
139     case DIRID_PRINTPROCESSOR:  /* FIXME */
140     default:
141         FIXME( "unknown dirid %d\n", dirid );
142         return get_unknown_dirid();
143     }
144     len = (strlenW(buffer) + 1) * sizeof(WCHAR);
145     if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len );
146     return str;
147 }
148
149 /* retrieve the string corresponding to a dirid, or NULL if none */
150 const WCHAR *DIRID_get_string( HINF hinf, int dirid )
151 {
152     int i;
153
154     if (dirid == DIRID_ABSOLUTE || dirid == DIRID_ABSOLUTE_16BIT) dirid = DIRID_NULL;
155
156     if (dirid >= DIRID_USER)
157     {
158         for (i = 0; i < nb_user_dirids; i++)
159             if (user_dirids[i].id == dirid) return user_dirids[i].str;
160         ERR("user id %d not found\n", dirid );
161         return NULL;
162     }
163     else
164     {
165         if (dirid > MAX_SYSTEM_DIRID) return get_unknown_dirid();
166         if (dirid == DIRID_SRCPATH) return PARSER_get_src_root( hinf );
167         if (!system_dirids[dirid]) system_dirids[dirid] = create_system_dirid( dirid );
168         return system_dirids[dirid];
169     }
170 }
171
172 /* store a user dirid string */
173 static BOOL store_user_dirid( HINF hinf, int id, WCHAR *str )
174 {
175     int i;
176
177     for (i = 0; i < nb_user_dirids; i++) if (user_dirids[i].id == id) break;
178
179     if (i < nb_user_dirids) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
180     else
181     {
182         if (nb_user_dirids >= alloc_user_dirids)
183         {
184             int new_size = max( 32, alloc_user_dirids * 2 );
185
186             struct user_dirid *new;
187
188             if (user_dirids)
189                 new = HeapReAlloc( GetProcessHeap(), 0, user_dirids,
190                                                   new_size * sizeof(*new) );
191             else
192                 new = HeapAlloc( GetProcessHeap(), 0, 
193                                                   new_size * sizeof(*new) );
194
195             if (!new) return FALSE;
196             user_dirids = new;
197             alloc_user_dirids = new_size;
198         }
199         nb_user_dirids++;
200     }
201     user_dirids[i].id  = id;
202     user_dirids[i].str = str;
203     TRACE("id %d -> %s\n", id, debugstr_w(str) );
204     return TRUE;
205 }
206
207
208 /***********************************************************************
209  *              SetupSetDirectoryIdA    (SETUPAPI.@)
210  */
211 BOOL WINAPI SetupSetDirectoryIdA( HINF hinf, DWORD id, PCSTR dir )
212 {
213     UNICODE_STRING dirW;
214     int i;
215
216     if (!id)  /* clear everything */
217     {
218         for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
219         nb_user_dirids = 0;
220         return TRUE;
221     }
222     if (id < DIRID_USER)
223     {
224         SetLastError( ERROR_INVALID_PARAMETER );
225         return FALSE;
226     }
227
228     /* duplicate the string */
229     if (!RtlCreateUnicodeStringFromAsciiz( &dirW, dir ))
230     {
231         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
232         return FALSE;
233     }
234     return store_user_dirid( hinf, id, dirW.Buffer );
235 }
236
237
238 /***********************************************************************
239  *              SetupSetDirectoryIdW    (SETUPAPI.@)
240  */
241 BOOL WINAPI SetupSetDirectoryIdW( HINF hinf, DWORD id, PCWSTR dir )
242 {
243     int i, len;
244     WCHAR *str;
245
246     if (!id)  /* clear everything */
247     {
248         for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
249         nb_user_dirids = 0;
250         return TRUE;
251     }
252     if (id < DIRID_USER)
253     {
254         SetLastError( ERROR_INVALID_PARAMETER );
255         return FALSE;
256     }
257
258     /* duplicate the string */
259     len = (strlenW(dir)+1) * sizeof(WCHAR);
260     if (!(str = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE;
261     memcpy( str, dir, len );
262     return store_user_dirid( hinf, id, str );
263 }