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
FindSepar(const wchar_t * s)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
FindSepar(const FChar * s)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
NormalizeDirPathPrefix(FString & dirPath)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
NormalizeDirPathPrefix(UString & dirPath)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
NormalizeDirSeparators(UString & s)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
NormalizeDirSeparators(FString & s)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
IsDrivePath(const wchar_t * s)95 bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
96
IsAltPathPrefix(CFSTR s)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
IsDevicePath(CFSTR s)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
IsSuperUncPath(CFSTR s)170 bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
IsNetworkPath(CFSTR s)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
GetNetworkServerPrefixSize(CFSTR s)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
IsNetworkShareRootPath(CFSTR s)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
IsDrivePath2(const wchar_t * s)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; }
IsSuperPath(const wchar_t * s)216 bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
IsSuperOrDevicePath(const wchar_t * 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
IsDrivePath2(CFSTR s)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; }
IsDrivePath(CFSTR s)223 bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
IsSuperPath(CFSTR s)224 bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); }
IsSuperOrDevicePath(CFSTR s)225 bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
226 #endif // USE_UNICODE_FSTRING
227
IsDrivePath_SuperAllowed(CFSTR s)228 bool IsDrivePath_SuperAllowed(CFSTR s) throw()
229 {
230 if (IsSuperPath(s))
231 s += kSuperPathPrefixSize;
232 return IsDrivePath(s);
233 }
234
IsDriveRootPath_SuperAllowed(CFSTR s)235 bool IsDriveRootPath_SuperAllowed(CFSTR s) throw()
236 {
237 if (IsSuperPath(s))
238 s += kSuperPathPrefixSize;
239 return IsDrivePath(s) && s[kDrivePrefixSize] == 0;
240 }
241
IsAbsolutePath(const wchar_t * s)242 bool IsAbsolutePath(const wchar_t *s) throw()
243 {
244 return IS_SEPAR(s[0]) || IsDrivePath2(s);
245 }
246
FindAltStreamColon(CFSTR path)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
GetRootPrefixSize_Of_NetworkPath(CFSTR s)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
GetRootPrefixSize_Of_SimplePath(CFSTR s)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
GetRootPrefixSize_Of_SuperPath(CFSTR s)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
GetRootPrefixSize(CFSTR s)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
GetRootPrefixSize_Of_NetworkPath(const wchar_t * s)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
GetRootPrefixSize_Of_SimplePath(const wchar_t * s)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
GetRootPrefixSize_Of_SuperPath(const wchar_t * s)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
GetRootPrefixSize(const wchar_t * s)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
IsAbsolutePath(const wchar_t * s)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();
GetRootPrefixSize(CFSTR s)373 unsigned GetRootPrefixSize(CFSTR s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; }
374 #endif
GetRootPrefixSize(const wchar_t * s)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
GetCurDir(UString & path)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
ResolveDotsFolders(UString & s)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
AreThereDotsFolders(CFSTR s)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
GetUseSuperPathType(CFSTR s)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
GetSuperPathBase(CFSTR s,UString & res)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
GetSuperPath(CFSTR path,UString & superPath,bool onlyIfNew)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
GetSuperPaths(CFSTR s1,CFSTR s2,UString & d1,UString & d2,bool onlyIfNew)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
GetFullPath(CFSTR dirPrefix,CFSTR s,FString & res)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
GetFullPath(CFSTR path,FString & fullPath)888 bool GetFullPath(CFSTR path, FString &fullPath)
889 {
890 return GetFullPath(NULL, path, fullPath);
891 }
892
893 }}}
894