diff options
Diffstat (limited to '')
-rw-r--r-- | CPP/Windows/FileName.cpp | 893 |
1 files changed, 893 insertions, 0 deletions
diff --git a/CPP/Windows/FileName.cpp b/CPP/Windows/FileName.cpp new file mode 100644 index 0000000..d61ff7e --- /dev/null +++ b/CPP/Windows/FileName.cpp | |||
@@ -0,0 +1,893 @@ | |||
1 | // Windows/FileName.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #ifndef _WIN32 | ||
6 | #include <limits.h> | ||
7 | #include <unistd.h> | ||
8 | #include "../Common/StringConvert.h" | ||
9 | #include "FileDir.h" | ||
10 | #endif | ||
11 | |||
12 | #include "FileName.h" | ||
13 | |||
14 | #ifndef _UNICODE | ||
15 | extern bool g_IsNT; | ||
16 | #endif | ||
17 | |||
18 | namespace NWindows { | ||
19 | namespace NFile { | ||
20 | namespace NName { | ||
21 | |||
22 | #define IS_SEPAR(c) IS_PATH_SEPAR(c) | ||
23 | |||
24 | int FindSepar(const wchar_t *s) throw() | ||
25 | { | ||
26 | for (const wchar_t *p = s;; p++) | ||
27 | { | ||
28 | const wchar_t c = *p; | ||
29 | if (c == 0) | ||
30 | return -1; | ||
31 | if (IS_SEPAR(c)) | ||
32 | return (int)(p - s); | ||
33 | } | ||
34 | } | ||
35 | |||
36 | #ifndef USE_UNICODE_FSTRING | ||
37 | int FindSepar(const FChar *s) throw() | ||
38 | { | ||
39 | for (const FChar *p = s;; p++) | ||
40 | { | ||
41 | const FChar c = *p; | ||
42 | if (c == 0) | ||
43 | return -1; | ||
44 | if (IS_SEPAR(c)) | ||
45 | return (int)(p - s); | ||
46 | } | ||
47 | } | ||
48 | #endif | ||
49 | |||
50 | #ifndef USE_UNICODE_FSTRING | ||
51 | void NormalizeDirPathPrefix(FString &dirPath) | ||
52 | { | ||
53 | if (dirPath.IsEmpty()) | ||
54 | return; | ||
55 | if (!IsPathSepar(dirPath.Back())) | ||
56 | dirPath.Add_PathSepar(); | ||
57 | } | ||
58 | #endif | ||
59 | |||
60 | void NormalizeDirPathPrefix(UString &dirPath) | ||
61 | { | ||
62 | if (dirPath.IsEmpty()) | ||
63 | return; | ||
64 | if (!IsPathSepar(dirPath.Back())) | ||
65 | dirPath.Add_PathSepar(); | ||
66 | } | ||
67 | |||
68 | #ifdef _WIN32 | ||
69 | |||
70 | #ifndef USE_UNICODE_FSTRING | ||
71 | #ifdef WIN_LONG_PATH | ||
72 | static void NormalizeDirSeparators(UString &s) | ||
73 | { | ||
74 | const unsigned len = s.Len(); | ||
75 | for (unsigned i = 0; i < len; i++) | ||
76 | if (s[i] == '/') | ||
77 | s.ReplaceOneCharAtPos(i, WCHAR_PATH_SEPARATOR); | ||
78 | } | ||
79 | #endif | ||
80 | #endif | ||
81 | |||
82 | void NormalizeDirSeparators(FString &s) | ||
83 | { | ||
84 | const unsigned len = s.Len(); | ||
85 | for (unsigned i = 0; i < len; i++) | ||
86 | if (s[i] == '/') | ||
87 | s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR); | ||
88 | } | ||
89 | |||
90 | #endif | ||
91 | |||
92 | |||
93 | #define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) | ||
94 | |||
95 | bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } | ||
96 | |||
97 | bool IsAltPathPrefix(CFSTR s) throw() | ||
98 | { | ||
99 | unsigned len = MyStringLen(s); | ||
100 | if (len == 0) | ||
101 | return false; | ||
102 | if (s[len - 1] != ':') | ||
103 | return false; | ||
104 | |||
105 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
106 | if (IsDevicePath(s)) | ||
107 | return false; | ||
108 | if (IsSuperPath(s)) | ||
109 | { | ||
110 | s += kSuperPathPrefixSize; | ||
111 | len -= kSuperPathPrefixSize; | ||
112 | } | ||
113 | if (len == 2 && IsDrivePath2(s)) | ||
114 | return false; | ||
115 | #endif | ||
116 | |||
117 | return true; | ||
118 | } | ||
119 | |||
120 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
121 | |||
122 | const char * const kSuperPathPrefix = "\\\\?\\"; | ||
123 | #ifdef WIN_LONG_PATH | ||
124 | static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; | ||
125 | #endif | ||
126 | |||
127 | #define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3])) | ||
128 | #define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3])) | ||
129 | #define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3])) | ||
130 | |||
131 | #define IS_UNC_WITH_SLASH(s) ( \ | ||
132 | ((s)[0] == 'U' || (s)[0] == 'u') \ | ||
133 | && ((s)[1] == 'N' || (s)[1] == 'n') \ | ||
134 | && ((s)[2] == 'C' || (s)[2] == 'c') \ | ||
135 | && IS_SEPAR((s)[3])) | ||
136 | |||
137 | bool IsDevicePath(CFSTR s) throw() | ||
138 | { | ||
139 | #ifdef UNDER_CE | ||
140 | |||
141 | s = s; | ||
142 | return false; | ||
143 | /* | ||
144 | // actually we don't know the way to open device file in WinCE. | ||
145 | unsigned len = MyStringLen(s); | ||
146 | if (len < 5 || len > 5 || !IsString1PrefixedByString2(s, "DSK")) | ||
147 | return false; | ||
148 | if (s[4] != ':') | ||
149 | return false; | ||
150 | // for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ)); | ||
151 | */ | ||
152 | |||
153 | #else | ||
154 | |||
155 | if (!IS_DEVICE_PATH(s)) | ||
156 | return false; | ||
157 | unsigned len = MyStringLen(s); | ||
158 | if (len == 6 && s[5] == ':') | ||
159 | return true; | ||
160 | if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive")) | ||
161 | return false; | ||
162 | for (unsigned i = 17; i < len; i++) | ||
163 | if (s[i] < '0' || s[i] > '9') | ||
164 | return false; | ||
165 | return true; | ||
166 | |||
167 | #endif | ||
168 | } | ||
169 | |||
170 | bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } | ||
171 | bool IsNetworkPath(CFSTR s) throw() | ||
172 | { | ||
173 | if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) | ||
174 | return false; | ||
175 | if (IsSuperUncPath(s)) | ||
176 | return true; | ||
177 | FChar c = s[2]; | ||
178 | return (c != '.' && c != '?'); | ||
179 | } | ||
180 | |||
181 | unsigned GetNetworkServerPrefixSize(CFSTR s) throw() | ||
182 | { | ||
183 | if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) | ||
184 | return 0; | ||
185 | unsigned prefixSize = 2; | ||
186 | if (IsSuperUncPath(s)) | ||
187 | prefixSize = kSuperUncPathPrefixSize; | ||
188 | else | ||
189 | { | ||
190 | FChar c = s[2]; | ||
191 | if (c == '.' || c == '?') | ||
192 | return 0; | ||
193 | } | ||
194 | int pos = FindSepar(s + prefixSize); | ||
195 | if (pos < 0) | ||
196 | return 0; | ||
197 | return prefixSize + (unsigned)(pos + 1); | ||
198 | } | ||
199 | |||
200 | bool IsNetworkShareRootPath(CFSTR s) throw() | ||
201 | { | ||
202 | unsigned prefixSize = GetNetworkServerPrefixSize(s); | ||
203 | if (prefixSize == 0) | ||
204 | return false; | ||
205 | s += prefixSize; | ||
206 | int pos = FindSepar(s); | ||
207 | if (pos < 0) | ||
208 | return true; | ||
209 | return s[(unsigned)pos + 1] == 0; | ||
210 | } | ||
211 | |||
212 | static const unsigned kDrivePrefixSize = 3; /* c:\ */ | ||
213 | |||
214 | bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } | ||
215 | // bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } | ||
216 | bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); } | ||
217 | bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } | ||
218 | // bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } | ||
219 | |||
220 | #ifndef USE_UNICODE_FSTRING | ||
221 | bool IsDrivePath2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } | ||
222 | // bool IsDriveName2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } | ||
223 | bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } | ||
224 | bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); } | ||
225 | bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } | ||
226 | #endif // USE_UNICODE_FSTRING | ||
227 | |||
228 | bool IsDrivePath_SuperAllowed(CFSTR s) throw() | ||
229 | { | ||
230 | if (IsSuperPath(s)) | ||
231 | s += kSuperPathPrefixSize; | ||
232 | return IsDrivePath(s); | ||
233 | } | ||
234 | |||
235 | bool IsDriveRootPath_SuperAllowed(CFSTR s) throw() | ||
236 | { | ||
237 | if (IsSuperPath(s)) | ||
238 | s += kSuperPathPrefixSize; | ||
239 | return IsDrivePath(s) && s[kDrivePrefixSize] == 0; | ||
240 | } | ||
241 | |||
242 | bool IsAbsolutePath(const wchar_t *s) throw() | ||
243 | { | ||
244 | return IS_SEPAR(s[0]) || IsDrivePath2(s); | ||
245 | } | ||
246 | |||
247 | int FindAltStreamColon(CFSTR path) throw() | ||
248 | { | ||
249 | unsigned i = 0; | ||
250 | if (IsDrivePath2(path)) | ||
251 | i = 2; | ||
252 | int colonPos = -1; | ||
253 | for (;; i++) | ||
254 | { | ||
255 | FChar c = path[i]; | ||
256 | if (c == 0) | ||
257 | return colonPos; | ||
258 | if (c == ':') | ||
259 | { | ||
260 | if (colonPos < 0) | ||
261 | colonPos = (int)i; | ||
262 | continue; | ||
263 | } | ||
264 | if (IS_SEPAR(c)) | ||
265 | colonPos = -1; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | #ifndef USE_UNICODE_FSTRING | ||
270 | |||
271 | static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s) | ||
272 | { | ||
273 | // Network path: we look "server\path\" as root prefix | ||
274 | int pos = FindSepar(s); | ||
275 | if (pos < 0) | ||
276 | return 0; | ||
277 | int pos2 = FindSepar(s + (unsigned)pos + 1); | ||
278 | if (pos2 < 0) | ||
279 | return 0; | ||
280 | return pos + pos2 + 2; | ||
281 | } | ||
282 | |||
283 | static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s) | ||
284 | { | ||
285 | if (IsDrivePath(s)) | ||
286 | return kDrivePrefixSize; | ||
287 | if (!IS_SEPAR(s[0])) | ||
288 | return 0; | ||
289 | if (s[1] == 0 || !IS_SEPAR(s[1])) | ||
290 | return 1; | ||
291 | unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); | ||
292 | return (size == 0) ? 0 : 2 + size; | ||
293 | } | ||
294 | |||
295 | static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s) | ||
296 | { | ||
297 | if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) | ||
298 | { | ||
299 | unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); | ||
300 | return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; | ||
301 | } | ||
302 | // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" | ||
303 | int pos = FindSepar(s + kSuperPathPrefixSize); | ||
304 | if (pos < 0) | ||
305 | return 0; | ||
306 | return kSuperPathPrefixSize + pos + 1; | ||
307 | } | ||
308 | |||
309 | unsigned GetRootPrefixSize(CFSTR s) throw() | ||
310 | { | ||
311 | if (IS_DEVICE_PATH(s)) | ||
312 | return kDevicePathPrefixSize; | ||
313 | if (IsSuperPath(s)) | ||
314 | return GetRootPrefixSize_Of_SuperPath(s); | ||
315 | return GetRootPrefixSize_Of_SimplePath(s); | ||
316 | } | ||
317 | |||
318 | #endif // USE_UNICODE_FSTRING | ||
319 | |||
320 | static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() | ||
321 | { | ||
322 | // Network path: we look "server\path\" as root prefix | ||
323 | int pos = FindSepar(s); | ||
324 | if (pos < 0) | ||
325 | return 0; | ||
326 | int pos2 = FindSepar(s + (unsigned)pos + 1); | ||
327 | if (pos2 < 0) | ||
328 | return 0; | ||
329 | return (unsigned)(pos + pos2 + 2); | ||
330 | } | ||
331 | |||
332 | static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw() | ||
333 | { | ||
334 | if (IsDrivePath(s)) | ||
335 | return kDrivePrefixSize; | ||
336 | if (!IS_SEPAR(s[0])) | ||
337 | return 0; | ||
338 | if (s[1] == 0 || !IS_SEPAR(s[1])) | ||
339 | return 1; | ||
340 | unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); | ||
341 | return (size == 0) ? 0 : 2 + size; | ||
342 | } | ||
343 | |||
344 | static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw() | ||
345 | { | ||
346 | if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) | ||
347 | { | ||
348 | unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); | ||
349 | return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; | ||
350 | } | ||
351 | // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" | ||
352 | int pos = FindSepar(s + kSuperPathPrefixSize); | ||
353 | if (pos < 0) | ||
354 | return 0; | ||
355 | return kSuperPathPrefixSize + (unsigned)(pos + 1); | ||
356 | } | ||
357 | |||
358 | unsigned GetRootPrefixSize(const wchar_t *s) throw() | ||
359 | { | ||
360 | if (IS_DEVICE_PATH(s)) | ||
361 | return kDevicePathPrefixSize; | ||
362 | if (IsSuperPath(s)) | ||
363 | return GetRootPrefixSize_Of_SuperPath(s); | ||
364 | return GetRootPrefixSize_Of_SimplePath(s); | ||
365 | } | ||
366 | |||
367 | #else // _WIN32 | ||
368 | |||
369 | bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } | ||
370 | |||
371 | #ifndef USE_UNICODE_FSTRING | ||
372 | unsigned GetRootPrefixSize(CFSTR s) throw(); | ||
373 | unsigned GetRootPrefixSize(CFSTR s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } | ||
374 | #endif | ||
375 | unsigned GetRootPrefixSize(const wchar_t *s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } | ||
376 | |||
377 | #endif // _WIN32 | ||
378 | |||
379 | |||
380 | #ifndef UNDER_CE | ||
381 | |||
382 | static bool GetCurDir(UString &path) | ||
383 | { | ||
384 | path.Empty(); | ||
385 | |||
386 | #ifdef _WIN32 | ||
387 | |||
388 | DWORD needLength; | ||
389 | #ifndef _UNICODE | ||
390 | if (!g_IsNT) | ||
391 | { | ||
392 | TCHAR s[MAX_PATH + 2]; | ||
393 | s[0] = 0; | ||
394 | needLength = ::GetCurrentDirectory(MAX_PATH + 1, s); | ||
395 | path = fs2us(fas2fs(s)); | ||
396 | } | ||
397 | else | ||
398 | #endif | ||
399 | { | ||
400 | WCHAR s[MAX_PATH + 2]; | ||
401 | s[0] = 0; | ||
402 | needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s); | ||
403 | path = s; | ||
404 | } | ||
405 | return (needLength > 0 && needLength <= MAX_PATH); | ||
406 | |||
407 | #else | ||
408 | |||
409 | FString s; | ||
410 | if (!NDir::GetCurrentDir(s)) | ||
411 | return false; | ||
412 | path = GetUnicodeString(s); | ||
413 | return true; | ||
414 | |||
415 | #endif | ||
416 | } | ||
417 | |||
418 | static bool ResolveDotsFolders(UString &s) | ||
419 | { | ||
420 | #ifdef _WIN32 | ||
421 | // s.Replace(L'/', WCHAR_PATH_SEPARATOR); | ||
422 | #endif | ||
423 | |||
424 | for (unsigned i = 0;;) | ||
425 | { | ||
426 | const wchar_t c = s[i]; | ||
427 | if (c == 0) | ||
428 | return true; | ||
429 | if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) | ||
430 | { | ||
431 | const wchar_t c1 = s[i + 1]; | ||
432 | if (c1 == '.') | ||
433 | { | ||
434 | const wchar_t c2 = s[i + 2]; | ||
435 | if (IS_SEPAR(c2) || c2 == 0) | ||
436 | { | ||
437 | if (i == 0) | ||
438 | return false; | ||
439 | int k = (int)i - 2; | ||
440 | i += 2; | ||
441 | |||
442 | for (;; k--) | ||
443 | { | ||
444 | if (k < 0) | ||
445 | return false; | ||
446 | if (!IS_SEPAR(s[(unsigned)k])) | ||
447 | break; | ||
448 | } | ||
449 | |||
450 | do | ||
451 | k--; | ||
452 | while (k >= 0 && !IS_SEPAR(s[(unsigned)k])); | ||
453 | |||
454 | unsigned num; | ||
455 | |||
456 | if (k >= 0) | ||
457 | { | ||
458 | num = i - (unsigned)k; | ||
459 | i = (unsigned)k; | ||
460 | } | ||
461 | else | ||
462 | { | ||
463 | num = (c2 == 0 ? i : (i + 1)); | ||
464 | i = 0; | ||
465 | } | ||
466 | |||
467 | s.Delete(i, num); | ||
468 | continue; | ||
469 | } | ||
470 | } | ||
471 | else if (IS_SEPAR(c1) || c1 == 0) | ||
472 | { | ||
473 | unsigned num = 2; | ||
474 | if (i != 0) | ||
475 | i--; | ||
476 | else if (c1 == 0) | ||
477 | num = 1; | ||
478 | s.Delete(i, num); | ||
479 | continue; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | i++; | ||
484 | } | ||
485 | } | ||
486 | |||
487 | #endif // UNDER_CE | ||
488 | |||
489 | #define LONG_PATH_DOTS_FOLDERS_PARSING | ||
490 | |||
491 | |||
492 | /* | ||
493 | Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\ | ||
494 | To solve that problem we check such path: | ||
495 | - super path contains "." or ".." - we use kSuperPathType_UseOnlySuper | ||
496 | - super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain | ||
497 | */ | ||
498 | #ifdef LONG_PATH_DOTS_FOLDERS_PARSING | ||
499 | #ifndef UNDER_CE | ||
500 | static bool AreThereDotsFolders(CFSTR s) | ||
501 | { | ||
502 | for (unsigned i = 0;; i++) | ||
503 | { | ||
504 | FChar c = s[i]; | ||
505 | if (c == 0) | ||
506 | return false; | ||
507 | if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) | ||
508 | { | ||
509 | FChar c1 = s[i + 1]; | ||
510 | if (c1 == 0 || IS_SEPAR(c1) || | ||
511 | (c1 == '.' && (s[i + 2] == 0 || IS_SEPAR(s[i + 2])))) | ||
512 | return true; | ||
513 | } | ||
514 | } | ||
515 | } | ||
516 | #endif | ||
517 | #endif // LONG_PATH_DOTS_FOLDERS_PARSING | ||
518 | |||
519 | #ifdef WIN_LONG_PATH | ||
520 | |||
521 | /* | ||
522 | Most of Windows versions have problems, if some file or dir name | ||
523 | contains '.' or ' ' at the end of name (Bad Path). | ||
524 | To solve that problem, we always use Super Path ("\\?\" prefix and full path) | ||
525 | in such cases. Note that "." and ".." are not bad names. | ||
526 | |||
527 | There are 3 cases: | ||
528 | 1) If the path is already Super Path, we use that path | ||
529 | 2) If the path is not Super Path : | ||
530 | 2.1) Bad Path; we use only Super Path. | ||
531 | 2.2) Good Path; we use Main Path. If it fails, we use Super Path. | ||
532 | |||
533 | NeedToUseOriginalPath returns: | ||
534 | kSuperPathType_UseOnlyMain : Super already | ||
535 | kSuperPathType_UseOnlySuper : not Super, Bad Path | ||
536 | kSuperPathType_UseMainAndSuper : not Super, Good Path | ||
537 | */ | ||
538 | |||
539 | int GetUseSuperPathType(CFSTR s) throw() | ||
540 | { | ||
541 | if (IsSuperOrDevicePath(s)) | ||
542 | { | ||
543 | #ifdef LONG_PATH_DOTS_FOLDERS_PARSING | ||
544 | if ((s)[2] != '.') | ||
545 | if (AreThereDotsFolders(s + kSuperPathPrefixSize)) | ||
546 | return kSuperPathType_UseOnlySuper; | ||
547 | #endif | ||
548 | return kSuperPathType_UseOnlyMain; | ||
549 | } | ||
550 | |||
551 | for (unsigned i = 0;; i++) | ||
552 | { | ||
553 | FChar c = s[i]; | ||
554 | if (c == 0) | ||
555 | return kSuperPathType_UseMainAndSuper; | ||
556 | if (c == '.' || c == ' ') | ||
557 | { | ||
558 | FChar c2 = s[i + 1]; | ||
559 | if (c2 == 0 || IS_SEPAR(c2)) | ||
560 | { | ||
561 | // if it's "." or "..", it's not bad name. | ||
562 | if (c == '.') | ||
563 | { | ||
564 | if (i == 0 || IS_SEPAR(s[i - 1])) | ||
565 | continue; | ||
566 | if (s[i - 1] == '.') | ||
567 | { | ||
568 | if (i - 1 == 0 || IS_SEPAR(s[i - 2])) | ||
569 | continue; | ||
570 | } | ||
571 | } | ||
572 | return kSuperPathType_UseOnlySuper; | ||
573 | } | ||
574 | } | ||
575 | } | ||
576 | } | ||
577 | |||
578 | |||
579 | |||
580 | /* | ||
581 | returns false in two cases: | ||
582 | - if GetCurDir was used, and GetCurDir returned error. | ||
583 | - if we can't resolve ".." name. | ||
584 | if path is ".", "..", res is empty. | ||
585 | if it's Super Path already, res is empty. | ||
586 | for \**** , and if GetCurDir is not drive (c:\), res is empty | ||
587 | for absolute paths, returns true, res is Super path. | ||
588 | */ | ||
589 | |||
590 | static bool GetSuperPathBase(CFSTR s, UString &res) | ||
591 | { | ||
592 | res.Empty(); | ||
593 | |||
594 | FChar c = s[0]; | ||
595 | if (c == 0) | ||
596 | return true; | ||
597 | if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) | ||
598 | return true; | ||
599 | |||
600 | if (IsSuperOrDevicePath(s)) | ||
601 | { | ||
602 | #ifdef LONG_PATH_DOTS_FOLDERS_PARSING | ||
603 | |||
604 | if ((s)[2] == '.') | ||
605 | return true; | ||
606 | |||
607 | // we will return true here, so we will try to use these problem paths. | ||
608 | |||
609 | if (!AreThereDotsFolders(s + kSuperPathPrefixSize)) | ||
610 | return true; | ||
611 | |||
612 | UString temp = fs2us(s); | ||
613 | unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp); | ||
614 | if (fixedSize == 0) | ||
615 | return true; | ||
616 | |||
617 | UString rem = &temp[fixedSize]; | ||
618 | if (!ResolveDotsFolders(rem)) | ||
619 | return true; | ||
620 | |||
621 | temp.DeleteFrom(fixedSize); | ||
622 | res += temp; | ||
623 | res += rem; | ||
624 | |||
625 | #endif | ||
626 | |||
627 | return true; | ||
628 | } | ||
629 | |||
630 | if (IS_SEPAR(c)) | ||
631 | { | ||
632 | if (IS_SEPAR(s[1])) | ||
633 | { | ||
634 | UString temp = fs2us(s + 2); | ||
635 | unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp); | ||
636 | // we ignore that error to allow short network paths server\share? | ||
637 | /* | ||
638 | if (fixedSize == 0) | ||
639 | return false; | ||
640 | */ | ||
641 | UString rem = &temp[fixedSize]; | ||
642 | if (!ResolveDotsFolders(rem)) | ||
643 | return false; | ||
644 | res += kSuperUncPrefix; | ||
645 | temp.DeleteFrom(fixedSize); | ||
646 | res += temp; | ||
647 | res += rem; | ||
648 | return true; | ||
649 | } | ||
650 | } | ||
651 | else | ||
652 | { | ||
653 | if (IsDrivePath2(s)) | ||
654 | { | ||
655 | UString temp = fs2us(s); | ||
656 | unsigned prefixSize = 2; | ||
657 | if (IsDrivePath(s)) | ||
658 | prefixSize = kDrivePrefixSize; | ||
659 | UString rem = temp.Ptr(prefixSize); | ||
660 | if (!ResolveDotsFolders(rem)) | ||
661 | return true; | ||
662 | res += kSuperPathPrefix; | ||
663 | temp.DeleteFrom(prefixSize); | ||
664 | res += temp; | ||
665 | res += rem; | ||
666 | return true; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | UString curDir; | ||
671 | if (!GetCurDir(curDir)) | ||
672 | return false; | ||
673 | NormalizeDirPathPrefix(curDir); | ||
674 | |||
675 | unsigned fixedSizeStart = 0; | ||
676 | unsigned fixedSize = 0; | ||
677 | const char *superMarker = NULL; | ||
678 | if (IsSuperPath(curDir)) | ||
679 | { | ||
680 | fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); | ||
681 | if (fixedSize == 0) | ||
682 | return false; | ||
683 | } | ||
684 | else | ||
685 | { | ||
686 | if (IsDrivePath(curDir)) | ||
687 | { | ||
688 | superMarker = kSuperPathPrefix; | ||
689 | fixedSize = kDrivePrefixSize; | ||
690 | } | ||
691 | else | ||
692 | { | ||
693 | if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) | ||
694 | return false; | ||
695 | fixedSizeStart = 2; | ||
696 | fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); | ||
697 | if (fixedSize == 0) | ||
698 | return false; | ||
699 | superMarker = kSuperUncPrefix; | ||
700 | } | ||
701 | } | ||
702 | |||
703 | UString temp; | ||
704 | if (IS_SEPAR(c)) | ||
705 | { | ||
706 | temp = fs2us(s + 1); | ||
707 | } | ||
708 | else | ||
709 | { | ||
710 | temp += &curDir[fixedSizeStart + fixedSize]; | ||
711 | temp += fs2us(s); | ||
712 | } | ||
713 | if (!ResolveDotsFolders(temp)) | ||
714 | return false; | ||
715 | if (superMarker) | ||
716 | res += superMarker; | ||
717 | res += curDir.Mid(fixedSizeStart, fixedSize); | ||
718 | res += temp; | ||
719 | return true; | ||
720 | } | ||
721 | |||
722 | |||
723 | /* | ||
724 | In that case if GetSuperPathBase doesn't return new path, we don't need | ||
725 | to use same path that was used as main path | ||
726 | |||
727 | GetSuperPathBase superPath.IsEmpty() onlyIfNew | ||
728 | false * * GetCurDir Error | ||
729 | true false * use Super path | ||
730 | true true true don't use any path, we already used mainPath | ||
731 | true true false use main path as Super Path, we don't try mainMath | ||
732 | That case is possible now if GetCurDir returns unknown | ||
733 | type of path (not drive and not network) | ||
734 | |||
735 | We can change that code if we want to try mainPath, if GetSuperPathBase returns error, | ||
736 | and we didn't try mainPath still. | ||
737 | If we want to work that way, we don't need to use GetSuperPathBase return code. | ||
738 | */ | ||
739 | |||
740 | bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew) | ||
741 | { | ||
742 | if (GetSuperPathBase(path, superPath)) | ||
743 | { | ||
744 | if (superPath.IsEmpty()) | ||
745 | { | ||
746 | // actually the only possible when onlyIfNew == true and superPath is empty | ||
747 | // is case when | ||
748 | |||
749 | if (onlyIfNew) | ||
750 | return false; | ||
751 | superPath = fs2us(path); | ||
752 | } | ||
753 | |||
754 | NormalizeDirSeparators(superPath); | ||
755 | return true; | ||
756 | } | ||
757 | return false; | ||
758 | } | ||
759 | |||
760 | bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew) | ||
761 | { | ||
762 | if (!GetSuperPathBase(s1, d1) || | ||
763 | !GetSuperPathBase(s2, d2)) | ||
764 | return false; | ||
765 | |||
766 | NormalizeDirSeparators(d1); | ||
767 | NormalizeDirSeparators(d2); | ||
768 | |||
769 | if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew) | ||
770 | return false; | ||
771 | if (d1.IsEmpty()) d1 = fs2us(s1); | ||
772 | if (d2.IsEmpty()) d2 = fs2us(s2); | ||
773 | return true; | ||
774 | } | ||
775 | |||
776 | |||
777 | /* | ||
778 | // returns true, if we need additional use with New Super path. | ||
779 | bool GetSuperPath(CFSTR path, UString &superPath) | ||
780 | { | ||
781 | if (GetSuperPathBase(path, superPath)) | ||
782 | return !superPath.IsEmpty(); | ||
783 | return false; | ||
784 | } | ||
785 | */ | ||
786 | #endif // WIN_LONG_PATH | ||
787 | |||
788 | bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res) | ||
789 | { | ||
790 | res = s; | ||
791 | |||
792 | #ifdef UNDER_CE | ||
793 | |||
794 | if (!IS_SEPAR(s[0])) | ||
795 | { | ||
796 | if (!dirPrefix) | ||
797 | return false; | ||
798 | res = dirPrefix; | ||
799 | res += s; | ||
800 | } | ||
801 | |||
802 | #else | ||
803 | |||
804 | unsigned prefixSize = GetRootPrefixSize(s); | ||
805 | if (prefixSize != 0) | ||
806 | { | ||
807 | if (!AreThereDotsFolders(s + prefixSize)) | ||
808 | return true; | ||
809 | |||
810 | UString rem = fs2us(s + prefixSize); | ||
811 | if (!ResolveDotsFolders(rem)) | ||
812 | return true; // maybe false; | ||
813 | res.DeleteFrom(prefixSize); | ||
814 | res += us2fs(rem); | ||
815 | return true; | ||
816 | } | ||
817 | |||
818 | /* | ||
819 | FChar c = s[0]; | ||
820 | if (c == 0) | ||
821 | return true; | ||
822 | if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) | ||
823 | return true; | ||
824 | if (IS_SEPAR(c) && IS_SEPAR(s[1])) | ||
825 | return true; | ||
826 | if (IsDrivePath(s)) | ||
827 | return true; | ||
828 | */ | ||
829 | |||
830 | UString curDir; | ||
831 | if (dirPrefix) | ||
832 | curDir = fs2us(dirPrefix); | ||
833 | else | ||
834 | { | ||
835 | if (!GetCurDir(curDir)) | ||
836 | return false; | ||
837 | } | ||
838 | NormalizeDirPathPrefix(curDir); | ||
839 | |||
840 | unsigned fixedSize = 0; | ||
841 | |||
842 | #ifdef _WIN32 | ||
843 | |||
844 | if (IsSuperPath(curDir)) | ||
845 | { | ||
846 | fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); | ||
847 | if (fixedSize == 0) | ||
848 | return false; | ||
849 | } | ||
850 | else | ||
851 | { | ||
852 | if (IsDrivePath(curDir)) | ||
853 | fixedSize = kDrivePrefixSize; | ||
854 | else | ||
855 | { | ||
856 | if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) | ||
857 | return false; | ||
858 | fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); | ||
859 | if (fixedSize == 0) | ||
860 | return false; | ||
861 | fixedSize += 2; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | #endif // _WIN32 | ||
866 | |||
867 | UString temp; | ||
868 | if (IS_SEPAR(s[0])) | ||
869 | { | ||
870 | temp = fs2us(s + 1); | ||
871 | } | ||
872 | else | ||
873 | { | ||
874 | temp += curDir.Ptr(fixedSize); | ||
875 | temp += fs2us(s); | ||
876 | } | ||
877 | if (!ResolveDotsFolders(temp)) | ||
878 | return false; | ||
879 | curDir.DeleteFrom(fixedSize); | ||
880 | res = us2fs(curDir); | ||
881 | res += us2fs(temp); | ||
882 | |||
883 | #endif // UNDER_CE | ||
884 | |||
885 | return true; | ||
886 | } | ||
887 | |||
888 | bool GetFullPath(CFSTR path, FString &fullPath) | ||
889 | { | ||
890 | return GetFullPath(NULL, path, fullPath); | ||
891 | } | ||
892 | |||
893 | }}} | ||