Commit | Line | Data |
7766f137 |
1 | /* vdir.h |
2 | * |
3 | * (c) 1999 Microsoft Corporation. All rights reserved. |
4 | * Portions (c) 1999 ActiveState Tool Corp, http://www.ActiveState.com/ |
5 | * |
6 | * You may distribute under the terms of either the GNU General Public |
7 | * License or the Artistic License, as specified in the README file. |
8 | */ |
9 | |
10 | #ifndef ___VDir_H___ |
11 | #define ___VDir_H___ |
12 | |
13 | const int driveCount = 30; |
14 | |
15 | class VDir |
16 | { |
17 | public: |
18 | VDir(); |
19 | ~VDir() {}; |
20 | |
21 | void Init(VDir* pDir, VMem *pMem); |
22 | void SetDefaultA(char const *pDefault); |
23 | void SetDefaultW(WCHAR const *pDefault); |
24 | char* MapPathA(const char *pInName); |
25 | WCHAR* MapPathW(const WCHAR *pInName); |
26 | int SetCurrentDirectoryA(char *lpBuffer); |
27 | int SetCurrentDirectoryW(WCHAR *lpBuffer); |
28 | inline const char *GetDirA(int index) |
29 | { |
30 | return dirTableA[index]; |
31 | }; |
32 | inline const WCHAR *GetDirW(int index) |
33 | { |
34 | return dirTableW[index]; |
35 | }; |
36 | inline int GetDefault(void) { return nDefault; }; |
37 | |
38 | inline char* GetCurrentDirectoryA(int dwBufSize, char *lpBuffer) |
39 | { |
40 | char* ptr = dirTableA[nDefault]; |
41 | while (dwBufSize--) |
42 | { |
43 | if ((*lpBuffer++ = *ptr++) == '\0') |
44 | break; |
45 | } |
46 | return lpBuffer; |
47 | }; |
48 | inline WCHAR* GetCurrentDirectoryW(int dwBufSize, WCHAR *lpBuffer) |
49 | { |
50 | WCHAR* ptr = dirTableW[nDefault]; |
51 | while (dwBufSize--) |
52 | { |
53 | if ((*lpBuffer++ = *ptr++) == '\0') |
54 | break; |
55 | } |
56 | return lpBuffer; |
57 | }; |
58 | |
59 | |
60 | DWORD CalculateEnvironmentSpace(void); |
61 | LPSTR BuildEnvironmentSpace(LPSTR lpStr); |
62 | |
63 | protected: |
64 | int SetDirA(char const *pPath, int index); |
65 | void FromEnvA(char *pEnv, int index); |
66 | inline const char *GetDefaultDirA(void) |
67 | { |
68 | return dirTableA[nDefault]; |
69 | }; |
70 | |
71 | inline void SetDefaultDirA(char const *pPath, int index) |
72 | { |
73 | SetDirA(pPath, index); |
74 | nDefault = index; |
75 | }; |
76 | int SetDirW(WCHAR const *pPath, int index); |
77 | inline const WCHAR *GetDefaultDirW(void) |
78 | { |
79 | return dirTableW[nDefault]; |
80 | }; |
81 | |
82 | inline void SetDefaultDirW(WCHAR const *pPath, int index) |
83 | { |
84 | SetDirW(pPath, index); |
85 | nDefault = index; |
86 | }; |
87 | |
88 | inline int DriveIndex(char chr) |
89 | { |
90 | return (chr | 0x20)-'a'; |
91 | }; |
92 | |
93 | VMem *pMem; |
94 | int nDefault; |
95 | char *dirTableA[driveCount]; |
96 | char szLocalBufferA[MAX_PATH+1]; |
97 | WCHAR *dirTableW[driveCount]; |
98 | WCHAR szLocalBufferW[MAX_PATH+1]; |
99 | }; |
100 | |
101 | |
102 | VDir::VDir() |
103 | { |
104 | nDefault = 0; |
105 | memset(dirTableA, 0, sizeof(dirTableA)); |
106 | memset(dirTableW, 0, sizeof(dirTableW)); |
107 | } |
108 | |
109 | void VDir::Init(VDir* pDir, VMem *p) |
110 | { |
111 | int index; |
112 | DWORD driveBits; |
113 | char szBuffer[MAX_PATH*driveCount]; |
114 | |
115 | pMem = p; |
116 | if (pDir) { |
117 | for (index = 0; index < driveCount; ++index) { |
118 | SetDirW(pDir->GetDirW(index), index); |
119 | } |
120 | nDefault = pDir->GetDefault(); |
121 | } |
122 | else { |
123 | driveBits = GetLogicalDrives(); |
124 | if (GetLogicalDriveStrings(sizeof(szBuffer), szBuffer)) { |
125 | char* pEnv = GetEnvironmentStrings(); |
126 | char* ptr = szBuffer; |
127 | for (index = 0; index < driveCount; ++index) { |
128 | if (driveBits & (1<<index)) { |
129 | ptr += SetDirA(ptr, index) + 1; |
130 | FromEnvA(pEnv, index); |
131 | } |
132 | } |
133 | FreeEnvironmentStrings(pEnv); |
134 | } |
135 | SetDefaultA("."); |
136 | } |
137 | } |
138 | |
139 | int VDir::SetDirA(char const *pPath, int index) |
140 | { |
141 | char chr, *ptr; |
142 | int length = 0; |
143 | WCHAR wBuffer[MAX_PATH+1]; |
144 | if (index < driveCount && pPath != NULL) { |
145 | length = strlen(pPath); |
146 | pMem->Free(dirTableA[index]); |
147 | ptr = dirTableA[index] = (char*)pMem->Malloc(length+2); |
148 | if (ptr != NULL) { |
149 | strcpy(ptr, pPath); |
150 | ptr += length-1; |
151 | chr = *ptr++; |
152 | if (chr != '\\' && chr != '/') { |
153 | *ptr++ = '\\'; |
154 | *ptr = '\0'; |
155 | } |
156 | MultiByteToWideChar(CP_ACP, 0, dirTableA[index], -1, |
157 | wBuffer, (sizeof(wBuffer)/sizeof(WCHAR))); |
158 | length = wcslen(wBuffer); |
159 | pMem->Free(dirTableW[index]); |
160 | dirTableW[index] = (WCHAR*)pMem->Malloc((length+1)*2); |
161 | if (dirTableW[index] != NULL) { |
162 | wcscpy(dirTableW[index], wBuffer); |
163 | } |
164 | } |
165 | } |
166 | return length; |
167 | } |
168 | |
169 | void VDir::FromEnvA(char *pEnv, int index) |
170 | { /* gets the directory for index from the environment variable. */ |
171 | while (*pEnv != '\0') { |
172 | if ((pEnv[0] == '=') && (DriveIndex(pEnv[1]) == index)) { |
173 | SetDirA(&pEnv[4], index); |
174 | break; |
175 | } |
176 | else |
177 | pEnv += strlen(pEnv)+1; |
178 | } |
179 | } |
180 | |
181 | void VDir::SetDefaultA(char const *pDefault) |
182 | { |
183 | char szBuffer[MAX_PATH+1]; |
184 | char *pPtr; |
185 | |
186 | if (GetFullPathNameA(pDefault, sizeof(szBuffer), szBuffer, &pPtr)) { |
187 | if (*pDefault != '.' && pPtr != NULL) |
188 | *pPtr = '\0'; |
189 | |
190 | SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0])); |
191 | } |
192 | } |
193 | |
194 | int VDir::SetDirW(WCHAR const *pPath, int index) |
195 | { |
196 | WCHAR chr, *ptr; |
197 | char szBuffer[MAX_PATH+1]; |
198 | int length = 0; |
199 | if (index < driveCount && pPath != NULL) { |
200 | length = wcslen(pPath); |
201 | pMem->Free(dirTableW[index]); |
202 | ptr = dirTableW[index] = (WCHAR*)pMem->Malloc((length+2)*2); |
203 | if (ptr != NULL) { |
204 | wcscpy(ptr, pPath); |
205 | ptr += length-1; |
206 | chr = *ptr++; |
207 | if (chr != '\\' && chr != '/') { |
208 | *ptr++ = '\\'; |
209 | *ptr = '\0'; |
210 | } |
211 | WideCharToMultiByte(CP_ACP, 0, dirTableW[index], -1, szBuffer, sizeof(szBuffer), NULL, NULL); |
212 | length = strlen(szBuffer); |
213 | pMem->Free(dirTableA[index]); |
214 | dirTableA[index] = (char*)pMem->Malloc(length+1); |
215 | if (dirTableA[index] != NULL) { |
216 | strcpy(dirTableA[index], szBuffer); |
217 | } |
218 | } |
219 | } |
220 | return length; |
221 | } |
222 | |
223 | void VDir::SetDefaultW(WCHAR const *pDefault) |
224 | { |
225 | WCHAR szBuffer[MAX_PATH+1]; |
226 | WCHAR *pPtr; |
227 | |
228 | if (GetFullPathNameW(pDefault, (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr)) { |
229 | if (*pDefault != '.' && pPtr != NULL) |
230 | *pPtr = '\0'; |
231 | |
232 | SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0])); |
233 | } |
234 | } |
235 | |
236 | inline BOOL IsPathSep(char ch) |
237 | { |
238 | return (ch == '\\' || ch == '/'); |
239 | } |
240 | |
241 | inline void DoGetFullPathNameA(char* lpBuffer, DWORD dwSize, char* Dest) |
242 | { |
243 | char *pPtr; |
244 | |
245 | /* |
246 | * On WinNT GetFullPathName does not fail, (or at least always |
247 | * succeeds when the drive is valid) WinNT does set *Dest to Nullch |
248 | * On Win98 GetFullPathName will set last error if it fails, but |
249 | * does not touch *Dest |
250 | */ |
251 | *Dest = '\0'; |
252 | GetFullPathNameA(lpBuffer, dwSize, Dest, &pPtr); |
253 | } |
254 | |
255 | char *VDir::MapPathA(const char *pInName) |
256 | { /* |
257 | * possiblities -- relative path or absolute path with or without drive letter |
258 | * OR UNC name |
259 | */ |
260 | char szBuffer[(MAX_PATH+1)*2]; |
261 | char szlBuf[MAX_PATH+1]; |
262 | |
263 | if (strlen(pInName) > MAX_PATH) { |
264 | strncpy(szlBuf, pInName, MAX_PATH); |
265 | if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) { |
266 | /* absolute path - reduce length by 2 for drive specifier */ |
267 | szlBuf[MAX_PATH-2] = '\0'; |
268 | } |
269 | else |
270 | szlBuf[MAX_PATH] = '\0'; |
271 | pInName = szlBuf; |
272 | } |
273 | /* strlen(pInName) is now <= MAX_PATH */ |
274 | |
275 | if (pInName[1] == ':') { |
276 | /* has drive letter */ |
277 | if (IsPathSep(pInName[2])) { |
278 | /* absolute with drive letter */ |
279 | strcpy(szLocalBufferA, pInName); |
280 | } |
281 | else { |
282 | /* relative path with drive letter */ |
283 | strcpy(szBuffer, GetDirA(DriveIndex(*pInName))); |
284 | strcat(szBuffer, &pInName[2]); |
285 | if(strlen(szBuffer) > MAX_PATH) |
286 | szBuffer[MAX_PATH] = '\0'; |
287 | |
288 | DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); |
289 | } |
290 | } |
291 | else { |
292 | /* no drive letter */ |
293 | if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) { |
294 | /* UNC name */ |
295 | strcpy(szLocalBufferA, pInName); |
296 | } |
297 | else { |
298 | strcpy(szBuffer, GetDefaultDirA()); |
299 | if (IsPathSep(pInName[0])) { |
300 | /* absolute path */ |
301 | szLocalBufferA[0] = szBuffer[0]; |
302 | szLocalBufferA[1] = szBuffer[1]; |
303 | strcpy(&szLocalBufferA[2], pInName); |
304 | } |
305 | else { |
306 | /* relative path */ |
307 | strcat(szBuffer, pInName); |
308 | if (strlen(szBuffer) > MAX_PATH) |
309 | szBuffer[MAX_PATH] = '\0'; |
310 | |
311 | DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); |
312 | } |
313 | } |
314 | } |
315 | |
316 | return szLocalBufferA; |
317 | } |
318 | |
319 | int VDir::SetCurrentDirectoryA(char *lpBuffer) |
320 | { |
321 | HANDLE hHandle; |
322 | WIN32_FIND_DATA win32FD; |
323 | char szBuffer[MAX_PATH+1], *pPtr; |
324 | int nRet = -1; |
325 | |
326 | GetFullPathNameA(MapPathA(lpBuffer), sizeof(szBuffer), szBuffer, &pPtr); |
327 | |
328 | hHandle = FindFirstFile(szBuffer, &win32FD); |
329 | if (hHandle != INVALID_HANDLE_VALUE) { |
330 | FindClose(hHandle); |
331 | SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0])); |
332 | nRet = 0; |
333 | } |
334 | return nRet; |
335 | } |
336 | |
337 | int VDir::SetCurrentDirectoryW(WCHAR *lpBuffer) |
338 | { |
339 | HANDLE hHandle; |
340 | WIN32_FIND_DATAW win32FD; |
341 | WCHAR szBuffer[MAX_PATH+1], *pPtr; |
342 | int nRet = -1; |
343 | |
344 | GetFullPathNameW(MapPathW(lpBuffer), (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr); |
345 | |
346 | hHandle = FindFirstFileW(szBuffer, &win32FD); |
347 | if (hHandle != INVALID_HANDLE_VALUE) { |
348 | FindClose(hHandle); |
349 | SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0])); |
350 | nRet = 0; |
351 | } |
352 | return nRet; |
353 | } |
354 | |
355 | DWORD VDir::CalculateEnvironmentSpace(void) |
356 | { /* the current directory environment strings are stored as '=d=d:\path' */ |
357 | int index; |
358 | DWORD dwSize = 0; |
359 | for (index = 0; index < driveCount; ++index) { |
360 | if (dirTableA[index] != NULL) { |
361 | dwSize += strlen(dirTableA[index]) + 4; /* add 1 for trailing NULL and 3 for '=d=' */ |
362 | } |
363 | } |
364 | return dwSize; |
365 | } |
366 | |
367 | LPSTR VDir::BuildEnvironmentSpace(LPSTR lpStr) |
368 | { /* store the current directory environment strings as '=d=d:\path' */ |
369 | int index; |
370 | LPSTR lpDirStr; |
371 | for (index = 0; index < driveCount; ++index) { |
372 | lpDirStr = dirTableA[index]; |
373 | if (lpDirStr != NULL) { |
374 | lpStr[0] = '='; |
375 | lpStr[1] = lpDirStr[0]; |
376 | lpStr[2] = '='; |
377 | strcpy(&lpStr[3], lpDirStr); |
378 | lpStr += strlen(lpDirStr) + 4; /* add 1 for trailing NULL and 3 for '=d=' */ |
379 | } |
380 | } |
381 | return lpStr; |
382 | } |
383 | |
384 | inline BOOL IsPathSep(WCHAR ch) |
385 | { |
386 | return (ch == '\\' || ch == '/'); |
387 | } |
388 | |
389 | inline void DoGetFullPathNameW(WCHAR* lpBuffer, DWORD dwSize, WCHAR* Dest) |
390 | { |
391 | WCHAR *pPtr; |
392 | |
393 | /* |
394 | * On WinNT GetFullPathName does not fail, (or at least always |
395 | * succeeds when the drive is valid) WinNT does set *Dest to Nullch |
396 | * On Win98 GetFullPathName will set last error if it fails, but |
397 | * does not touch *Dest |
398 | */ |
399 | *Dest = '\0'; |
400 | GetFullPathNameW(lpBuffer, dwSize, Dest, &pPtr); |
401 | } |
402 | |
403 | WCHAR* VDir::MapPathW(const WCHAR *pInName) |
404 | { /* |
405 | * possiblities -- relative path or absolute path with or without drive letter |
406 | * OR UNC name |
407 | */ |
408 | WCHAR szBuffer[(MAX_PATH+1)*2]; |
409 | WCHAR szlBuf[MAX_PATH+1]; |
410 | |
411 | if (wcslen(pInName) > MAX_PATH) { |
412 | wcsncpy(szlBuf, pInName, MAX_PATH); |
413 | if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) { |
414 | /* absolute path - reduce length by 2 for drive specifier */ |
415 | szlBuf[MAX_PATH-2] = '\0'; |
416 | } |
417 | else |
418 | szlBuf[MAX_PATH] = '\0'; |
419 | pInName = szlBuf; |
420 | } |
421 | /* strlen(pInName) is now <= MAX_PATH */ |
422 | |
423 | if (pInName[1] == ':') { |
424 | /* has drive letter */ |
425 | if (IsPathSep(pInName[2])) { |
426 | /* absolute with drive letter */ |
427 | wcscpy(szLocalBufferW, pInName); |
428 | } |
429 | else { |
430 | /* relative path with drive letter */ |
431 | wcscpy(szBuffer, GetDirW(DriveIndex((char)*pInName))); |
432 | wcscat(szBuffer, &pInName[2]); |
433 | if(wcslen(szBuffer) > MAX_PATH) |
434 | szBuffer[MAX_PATH] = '\0'; |
435 | |
436 | DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); |
437 | } |
438 | } |
439 | else { |
440 | /* no drive letter */ |
441 | if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) { |
442 | /* UNC name */ |
443 | wcscpy(szLocalBufferW, pInName); |
444 | } |
445 | else { |
446 | wcscpy(szBuffer, GetDefaultDirW()); |
447 | if (IsPathSep(pInName[0])) { |
448 | /* absolute path */ |
449 | szLocalBufferW[0] = szBuffer[0]; |
450 | szLocalBufferW[1] = szBuffer[1]; |
451 | wcscpy(&szLocalBufferW[2], pInName); |
452 | } |
453 | else { |
454 | /* relative path */ |
455 | wcscat(szBuffer, pInName); |
456 | if (wcslen(szBuffer) > MAX_PATH) |
457 | szBuffer[MAX_PATH] = '\0'; |
458 | |
459 | DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); |
460 | } |
461 | } |
462 | } |
463 | return szLocalBufferW; |
464 | } |
465 | |
466 | |
467 | #endif /* ___VDir_H___ */ |