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