xref: /reactos/dll/win32/setupapi/dirid.c (revision c2c66aff)
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 */
get_unknown_dirid(void)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 */
create_system_dirid(int 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 
get_csidl_dir(DWORD csidl)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 */
DIRID_get_string(int dirid)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 */
store_user_dirid(HINF hinf,int id,WCHAR * str)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  */
SetupSetDirectoryIdA(HINF hinf,DWORD id,PCSTR dir)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  */
SetupSetDirectoryIdW(HINF hinf,DWORD id,PCWSTR dir)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 }
279