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