// ExtractingFilePath.cpp #include "StdAfx.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/FileName.h" #include "ExtractingFilePath.h" bool g_PathTrailReplaceMode = #ifdef _WIN32 true #else false #endif ; static void ReplaceIncorrectChars(UString &s) { { for (unsigned i = 0; i < s.Len(); i++) { wchar_t c = s[i]; if ( #ifdef _WIN32 c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"' || c == '/' // || c == 0x202E // RLO || #endif c == WCHAR_PATH_SEPARATOR) s.ReplaceOneCharAtPos(i, '_'); } } if (g_PathTrailReplaceMode) { /* // if (g_PathTrailReplaceMode == 1) { if (!s.IsEmpty()) { wchar_t c = s.Back(); if (c == '.' || c == ' ') { // s += (wchar_t)(0x9c); // STRING TERMINATOR s += (wchar_t)'_'; } } } else */ { unsigned i; for (i = s.Len(); i != 0;) { wchar_t c = s[i - 1]; if (c != '.' && c != ' ') break; i--; s.ReplaceOneCharAtPos(i, '_'); // s.ReplaceOneCharAtPos(i, (c == ' ' ? (wchar_t)(0x2423) : (wchar_t)0x00B7)); } /* if (g_PathTrailReplaceMode > 1 && i != s.Len()) { s.DeleteFrom(i); } */ } } } #ifdef _WIN32 /* WinXP-64 doesn't support ':', '\\' and '/' symbols in name of alt stream. But colon in postfix ":$DATA" is allowed. WIN32 functions don't allow empty alt stream name "name:" */ void Correct_AltStream_Name(UString &s) { unsigned len = s.Len(); const unsigned kPostfixSize = 6; if (s.Len() >= kPostfixSize && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA")) len -= kPostfixSize; for (unsigned i = 0; i < len; i++) { wchar_t c = s[i]; if (c == ':' || c == '\\' || c == '/' || c == 0x202E // RLO ) s.ReplaceOneCharAtPos(i, '_'); } if (s.IsEmpty()) s = '_'; } static const unsigned g_ReservedWithNum_Index = 4; static const char * const g_ReservedNames[] = { "CON", "PRN", "AUX", "NUL", "COM", "LPT" }; static bool IsSupportedName(const UString &name) { for (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++) { const char *reservedName = g_ReservedNames[i]; unsigned len = MyStringLen(reservedName); if (name.Len() < len) continue; if (!name.IsPrefixedBy_Ascii_NoCase(reservedName)) continue; if (i >= g_ReservedWithNum_Index) { wchar_t c = name[len]; if (c < L'0' || c > L'9') continue; len++; } for (;;) { wchar_t c = name[len++]; if (c == 0 || c == '.') return false; if (c != ' ') break; } } return true; } static void CorrectUnsupportedName(UString &name) { if (!IsSupportedName(name)) name.InsertAtFront(L'_'); } #endif static void Correct_PathPart(UString &s) { // "." and ".." if (s.IsEmpty()) return; if (s[0] == '.' && (s[1] == 0 || s[1] == '.' && s[2] == 0)) s.Empty(); #ifdef _WIN32 else ReplaceIncorrectChars(s); #endif } // static const char * const k_EmptyReplaceName = "[]"; static const char k_EmptyReplaceName = '_'; UString Get_Correct_FsFile_Name(const UString &name) { UString res = name; Correct_PathPart(res); #ifdef _WIN32 CorrectUnsupportedName(res); #endif if (res.IsEmpty()) res = k_EmptyReplaceName; return res; } void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir) { unsigned i = 0; if (absIsAllowed) { #if defined(_WIN32) && !defined(UNDER_CE) bool isDrive = false; #endif if (parts[0].IsEmpty()) { i = 1; #if defined(_WIN32) && !defined(UNDER_CE) if (parts.Size() > 1 && parts[1].IsEmpty()) { i = 2; if (parts.Size() > 2 && parts[2] == L"?") { i = 3; if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3])) { isDrive = true; i = 4; } } } #endif } #if defined(_WIN32) && !defined(UNDER_CE) else if (NWindows::NFile::NName::IsDrivePath2(parts[0])) { isDrive = true; i = 1; } if (isDrive) { // we convert "c:name" to "c:\name", if absIsAllowed path. UString &ds = parts[i - 1]; if (ds.Len() > 2) { parts.Insert(i, ds.Ptr(2)); ds.DeleteFrom(2); } } #endif } if (i != 0) keepAndReplaceEmptyPrefixes = false; for (; i < parts.Size();) { UString &s = parts[i]; Correct_PathPart(s); if (s.IsEmpty()) { if (!keepAndReplaceEmptyPrefixes) if (isDir || i != parts.Size() - 1) { parts.Delete(i); continue; } s = k_EmptyReplaceName; } else { keepAndReplaceEmptyPrefixes = false; #ifdef _WIN32 CorrectUnsupportedName(s); #endif } i++; } if (!isDir) { if (parts.IsEmpty()) parts.Add((UString)k_EmptyReplaceName); else { UString &s = parts.Back(); if (s.IsEmpty()) s = k_EmptyReplaceName; } } } UString MakePathFromParts(const UStringVector &parts) { UString s; FOR_VECTOR (i, parts) { if (i != 0) s.Add_PathSepar(); s += parts[i]; } return s; }