/* * vislib::sys::Path::Resolve */ vislib::StringW vislib::sys::Path::Resolve(StringW path, StringW basepath) { // TODO: Windows shell API resolve does not work in the expected // way, so we use the same manual approach for Windows and Linux. #ifdef _WIN32 /* Replace unchefmäßige path separators. */ basepath.Replace(L'/', SEPARATOR_W); path.Replace(L'/', SEPARATOR_W); #endif /* _WIN32 */ if (Path::IsRelative(basepath)) { basepath = Resolve(basepath); } if (path.IsEmpty()) { /* Path is empty, i. e. return current working directory. */ return Path::Canonicalise(basepath); } else if (Path::IsAbsolute(path)) { /* Path is absolute, just return it. */ return Path::Canonicalise(path); } else if ((path[0] == MYDOCUMENTS_MARKER_W) && ((path.Length() == 1) || path[1] == SEPARATOR_W)) { /* * replace leading ~ with users home directory */ path.Replace(MYDOCUMENTS_MARKER_W, Path::GetUserHomeDirectoryW()); return Path::Canonicalise(path); } else if ((path[0] == SEPARATOR_W) && (path[1] != SEPARATOR_W)) { /* * Concatenate current drive and relative path, and canonicalise * the result. */ return Path::Concatenate(basepath.Substring(0, 2), path, true); } else { /* * Concatenate current directory and relative path, and canonicalise * the result. */ return Concatenate(basepath, path, true); } }
/* * vislib::sys::Path::Canonicalise */ vislib::StringW vislib::sys::Path::Canonicalise(const StringW& path) { const StringW DOUBLE_SEPARATOR(Path::SEPARATOR_W, 2); #ifdef _WIN32 StringW retval; if (::PathCanonicalizeW(retval.AllocateBuffer(MAX_PATH), path) != TRUE) { throw SystemException(__FILE__, __LINE__); } retval.Replace(DOUBLE_SEPARATOR.PeekBuffer(), SEPARATOR_W); retval.Replace(DOUBLE_SEPARATOR.PeekBuffer(), SEPARATOR_W); /* Ensure that a UNC path remains a UNC path. */ if (path.StartsWith(DOUBLE_SEPARATOR)) { // Note: Double separator replacement above leaves at least one // separator, so we must only prepend one additional one. retval.Prepend(SEPARATOR_W); } return retval; #else /* _WIN32 */ const wchar_t *BACK_REF = L"/.."; const wchar_t *CUR_REF = L"/."; // Note: "./" does not work StringW::Size BACK_REF_LEN = ::wcslen(BACK_REF); StringW::Size bwRefPos = 0; // Position of back reference. StringW::Size remDirPos = 0; // Position of directory to erase. StringW retval(path); /* Remove backward references, first. */ while ((bwRefPos = retval.Find(BACK_REF)) != StringW::INVALID_POS) { if ((bwRefPos > 0) && (remDirPos = retval.FindLast(SEPARATOR_W, bwRefPos - 1)) != StringW::INVALID_POS) { /* Found inner backward reference, so remove some parts. */ retval.Remove(remDirPos, bwRefPos - remDirPos + BACK_REF_LEN); } else { /* * No other path separator is before this one, so we can remove * everything before 'bwRefPos'. */ retval.Remove(0, bwRefPos + BACK_REF_LEN); } } /* * Remove references to the current directory. This must be done after * removing backward references. */ retval.Remove(CUR_REF); /* Remove odd and even number of repeated path separators. */ retval.Replace(DOUBLE_SEPARATOR.PeekBuffer(), SEPARATOR_W); retval.Replace(DOUBLE_SEPARATOR.PeekBuffer(), SEPARATOR_W); return retval; #endif /* _WIN32 */ }