1 // ExtractingFilePath.cpp 2 3 #include "StdAfx.h" 4 5 #include "../../../Common/Wildcard.h" 6 7 #include "../../../Windows/FileName.h" 8 9 #include "ExtractingFilePath.h" 10 11 static void ReplaceIncorrectChars(UString &s) 12 { 13 { 14 for (unsigned i = 0; i < s.Len(); i++) 15 { 16 wchar_t c = s[i]; 17 if ( 18 #ifdef _WIN32 19 c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"' 20 || c == '/' 21 // || c == 0x202E // RLO 22 || 23 #endif 24 c == WCHAR_PATH_SEPARATOR) 25 s.ReplaceOneCharAtPos(i, '_'); 26 } 27 } 28 29 #ifdef _WIN32 30 { 31 for (unsigned i = s.Len(); i != 0;) 32 { 33 wchar_t c = s[--i]; 34 if (c != '.' && c != ' ') 35 break; 36 s.ReplaceOneCharAtPos(i, '_'); 37 } 38 } 39 #endif 40 } 41 42 #ifdef _WIN32 43 44 /* WinXP-64 doesn't support ':', '\\' and '/' symbols in name of alt stream. 45 But colon in postfix ":$DATA" is allowed. 46 WIN32 functions don't allow empty alt stream name "name:" */ 47 48 void Correct_AltStream_Name(UString &s) 49 { 50 unsigned len = s.Len(); 51 const unsigned kPostfixSize = 6; 52 if (s.Len() >= kPostfixSize 53 && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA")) 54 len -= kPostfixSize; 55 for (unsigned i = 0; i < len; i++) 56 { 57 wchar_t c = s[i]; 58 if (c == ':' || c == '\\' || c == '/' 59 || c == 0x202E // RLO 60 ) 61 s.ReplaceOneCharAtPos(i, '_'); 62 } 63 if (s.IsEmpty()) 64 s = L'_'; 65 } 66 67 static const unsigned g_ReservedWithNum_Index = 4; 68 69 static const char * const g_ReservedNames[] = 70 { 71 "CON", "PRN", "AUX", "NUL", 72 "COM", "LPT" 73 }; 74 75 static bool IsSupportedName(const UString &name) 76 { 77 for (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++) 78 { 79 const char *reservedName = g_ReservedNames[i]; 80 unsigned len = MyStringLen(reservedName); 81 if (name.Len() < len) 82 continue; 83 if (!name.IsPrefixedBy_Ascii_NoCase(reservedName)) 84 continue; 85 if (i >= g_ReservedWithNum_Index) 86 { 87 wchar_t c = name[len]; 88 if (c < L'0' || c > L'9') 89 continue; 90 len++; 91 } 92 for (;;) 93 { 94 wchar_t c = name[len++]; 95 if (c == 0 || c == '.') 96 return false; 97 if (c != ' ') 98 break; 99 } 100 } 101 return true; 102 } 103 104 static void CorrectUnsupportedName(UString &name) 105 { 106 if (!IsSupportedName(name)) 107 name.InsertAtFront(L'_'); 108 } 109 110 #endif 111 112 static void Correct_PathPart(UString &s) 113 { 114 // "." and ".." 115 if (s[0] == '.' && (s[1] == 0 || s[1] == '.' && s[2] == 0)) 116 s.Empty(); 117 #ifdef _WIN32 118 else 119 ReplaceIncorrectChars(s); 120 #endif 121 } 122 123 // static const wchar_t *k_EmptyReplaceName = L"[]"; 124 static const wchar_t k_EmptyReplaceName = L'_'; 125 126 UString Get_Correct_FsFile_Name(const UString &name) 127 { 128 UString res = name; 129 Correct_PathPart(res); 130 131 #ifdef _WIN32 132 CorrectUnsupportedName(res); 133 #endif 134 135 if (res.IsEmpty()) 136 res = k_EmptyReplaceName; 137 return res; 138 } 139 140 141 void Correct_FsPath(bool absIsAllowed, UStringVector &parts, bool isDir) 142 { 143 unsigned i = 0; 144 145 if (absIsAllowed) 146 { 147 #if defined(_WIN32) && !defined(UNDER_CE) 148 bool isDrive = false; 149 #endif 150 if (parts[0].IsEmpty()) 151 { 152 i = 1; 153 #if defined(_WIN32) && !defined(UNDER_CE) 154 if (parts.Size() > 1 && parts[1].IsEmpty()) 155 { 156 i = 2; 157 if (parts.Size() > 2 && parts[2] == L"?") 158 { 159 i = 3; 160 if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3])) 161 { 162 isDrive = true; 163 i = 4; 164 } 165 } 166 } 167 #endif 168 } 169 #if defined(_WIN32) && !defined(UNDER_CE) 170 else if (NWindows::NFile::NName::IsDrivePath2(parts[0])) 171 { 172 isDrive = true; 173 i = 1; 174 } 175 176 if (isDrive) 177 { 178 // we convert "c:name" to "c:\name", if absIsAllowed path. 179 const UString &ds = parts[i - 1]; 180 if (ds.Len() != 2) 181 { 182 UString s = ds.Ptr(2); 183 parts.Insert(i, s); 184 } 185 } 186 #endif 187 } 188 189 for (; i < parts.Size();) 190 { 191 UString &s = parts[i]; 192 193 Correct_PathPart(s); 194 195 if (s.IsEmpty()) 196 { 197 if (isDir || i != parts.Size() - 1) 198 { 199 parts.Delete(i); 200 continue; 201 } 202 s = k_EmptyReplaceName; 203 } 204 else 205 { 206 #ifdef _WIN32 207 CorrectUnsupportedName(s); 208 #endif 209 } 210 211 i++; 212 } 213 214 if (!isDir) 215 { 216 if (parts.IsEmpty()) 217 parts.Add(k_EmptyReplaceName); 218 else 219 { 220 UString &s = parts.Back(); 221 if (s.IsEmpty()) 222 s = k_EmptyReplaceName; 223 } 224 } 225 } 226 227 UString MakePathFromParts(const UStringVector &parts) 228 { 229 UString s; 230 FOR_VECTOR (i, parts) 231 { 232 if (i != 0) 233 s.Add_PathSepar(); 234 s += parts[i]; 235 } 236 return s; 237 } 238