1 // ExtractingFilePath.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../../C/Types.h"
6 
7 #include "Common/Wildcard.h"
8 
9 #include "ExtractingFilePath.h"
10 
ReplaceIncorrectChars(const UString & s)11 static UString ReplaceIncorrectChars(const UString &s)
12 {
13   #ifdef _WIN32
14   UString res;
15   for (int i = 0; i < s.Length(); i++)
16   {
17     wchar_t c = s[i];
18     if (c < 0x20 || c == '*' || c == '?' || c == '<' || c == '>'  || c == '|' || c == ':' || c == '"')
19       c = '_';
20     res += c;
21   }
22   res.TrimRight();
23   while (!res.IsEmpty() && res[res.Length() - 1] == '.')
24     res.Delete(res.Length() - 1);
25   return res;
26   #else
27   return s;
28   #endif
29 }
30 
31 #ifdef _WIN32
32 static const wchar_t *g_ReservedNames[] =
33 {
34   L"CON", L"PRN", L"AUX", L"NUL"
35 };
36 
CheckTail(const UString & name,int len)37 static bool CheckTail(const UString &name, int len)
38 {
39   int dotPos = name.Find(L'.');
40   if (dotPos < 0)
41     dotPos = name.Length();
42   UString s = name.Left(dotPos);
43   s.TrimRight();
44   return (s.Length() != len);
45 }
46 
CheckNameNum(const UString & name,const wchar_t * reservedName)47 static bool CheckNameNum(const UString &name, const wchar_t *reservedName)
48 {
49   int len = MyStringLen(reservedName);
50   if (name.Length() <= len)
51     return true;
52   if (name.Left(len).CompareNoCase(reservedName) != 0)
53     return true;
54   wchar_t c = name[len];
55   if (c < L'0' || c > L'9')
56     return true;
57   return CheckTail(name, len + 1);
58 }
59 
IsSupportedName(const UString & name)60 static bool IsSupportedName(const UString &name)
61 {
62   for (int i = 0; i < sizeof(g_ReservedNames) / sizeof(g_ReservedNames[0]); i++)
63   {
64     const wchar_t *reservedName = g_ReservedNames[i];
65     int len = MyStringLen(reservedName);
66     if (name.Length() < len)
67       continue;
68     if (name.Left(len).CompareNoCase(reservedName) != 0)
69       continue;
70     if (!CheckTail(name, len))
71       return false;
72   }
73   if (!CheckNameNum(name, L"COM"))
74     return false;
75   return CheckNameNum(name, L"LPT");
76 }
77 #endif
78 
GetCorrectFileName(const UString & path)79 static UString GetCorrectFileName(const UString &path)
80 {
81   if (path == L".." || path == L".")
82     return UString();
83   return ReplaceIncorrectChars(path);
84 }
85 
MakeCorrectPath(UStringVector & pathParts)86 void MakeCorrectPath(UStringVector &pathParts)
87 {
88   for (int i = 0; i < pathParts.Size();)
89   {
90     UString &s = pathParts[i];
91     s = GetCorrectFileName(s);
92     if (s.IsEmpty())
93       pathParts.Delete(i);
94     else
95     {
96       #ifdef _WIN32
97       if (!IsSupportedName(s))
98         s = (UString)L"_" + s;
99       #endif
100       i++;
101     }
102   }
103 }
104 
MakePathNameFromParts(const UStringVector & parts)105 UString MakePathNameFromParts(const UStringVector &parts)
106 {
107   UString result;
108   for (int i = 0; i < parts.Size(); i++)
109   {
110     if (i != 0)
111       result += WCHAR_PATH_SEPARATOR;
112     result += parts[i];
113   }
114   return result;
115 }
116 
GetCorrectFsPath(const UString & path)117 UString GetCorrectFsPath(const UString &path)
118 {
119   UString res = GetCorrectFileName(path);
120   #ifdef _WIN32
121   if (!IsSupportedName(res))
122     res = (UString)L"_" + res;
123   #endif
124   return res;
125 }
126 
GetCorrectFullFsPath(const UString & path)127 UString GetCorrectFullFsPath(const UString &path)
128 {
129   UStringVector parts;
130   SplitPathToParts(path, parts);
131   for (int i = 0; i < parts.Size(); i++)
132   {
133     UString &s = parts[i];
134     #ifdef _WIN32
135     while (!s.IsEmpty() && s[s.Length() - 1] == '.')
136       s.Delete(s.Length() - 1);
137     if (!IsSupportedName(s))
138       s = (UString)L"_" + s;
139     #endif
140   }
141   return MakePathNameFromParts(parts);
142 }
143