// An absolute path starts either with \\ (an UNC or device path like \\.\ or \\?\) // or with a ASCII alpha character followed by colon followed by backslash. bool isAbsolute(std::u16string_view s)
{ return startsWithSlashSlash(s) || startsWithDriveColonSlash(s);
}
staticbool IsValidFilePathComponent(
std::optional<std::u16string_view>& roComponent,
DWORD dwFlags)
{
assert(roComponent); auto lpComponentEnd = roComponent->end(); auto lpCurrent = roComponent->begin(); bool bValid = lpCurrent != lpComponentEnd; // Empty components are not allowed
sal_Unicode cLast = 0;
while (bValid)
{ /* Path component length must not exceed MAX_PATH even if long path with "\\?\" prefix is used */ if (lpCurrent - roComponent->begin() >= MAX_PATH)
{
bValid = false; break;
}
switch ( *lpCurrent )
{ /* Both backslash and slash determine the end of a path component */ case'\0': case'/': case'\\': switch ( cLast )
{ /* Component must not end with '.' or blank and can't be empty */
case'.': if ( dwFlags & VALIDATEPATH_ALLOW_ELLIPSE )
{ if ( (dwFlags & VALIDATEPATH_ALLOW_INVALID_SPACE_AND_PERIOD) || 1 == lpCurrent - roComponent->begin() )
{ /* Either do allow periods anywhere, or current directory */
lpComponentEnd = lpCurrent; break;
} elseif ( 2 == lpCurrent - roComponent->begin() && '.' == roComponent->front() )
{ /* Parent directory is O.K. */
lpComponentEnd = lpCurrent; break;
}
}
[[fallthrough]]; case0: case' ': if ( dwFlags & VALIDATEPATH_ALLOW_INVALID_SPACE_AND_PERIOD )
lpComponentEnd = lpCurrent; else
bValid = false; break; default:
lpComponentEnd = lpCurrent; break;
} break; /* The following characters are reserved */ case'?': case'*': case'<': case'>': case'\"': case'|': case':':
bValid = false; break; default: /* Characters below ASCII 32 are not allowed */ if ( *lpCurrent < ' ' )
bValid = false; break;
}
if (lpCurrent != lpComponentEnd)
cLast = *lpCurrent++;
if (lpCurrent == lpComponentEnd) break;
}
if ( bValid )
{ // Empty components are not allowed if (lpComponentEnd - roComponent->begin() < 1)
bValid = false; // If we reached the end of the string nullopt is returned elseif (lpComponentEnd == roComponent->end())
roComponent.reset(); else
roComponent->remove_prefix(lpComponentEnd - roComponent->begin());
}
if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
dwFlags |= VALIDATEPATH_ALLOW_ELLIPSE;
DWORD dwCandidatPathType = PATHTYPE_ERROR;
if (path.matchIgnoreAsciiCase(WSTR_LONG_PATH_PREFIX_UNC))
{ /* This is long path in UNC notation */
oComponent = path.subView(WSTR_LONG_PATH_PREFIX_UNC.size());
dwCandidatPathType = PATHTYPE_ABSOLUTE_UNC | PATHTYPE_IS_LONGPATH;
} elseif (path.matchIgnoreAsciiCase(WSTR_LONG_PATH_PREFIX))
{ /* This is long path */
oComponent = path.subView(WSTR_LONG_PATH_PREFIX.size());
if (startsWithDriveColon(*oComponent))
{
oComponent->remove_prefix(2);
dwCandidatPathType = PATHTYPE_ABSOLUTE_LOCAL | PATHTYPE_IS_LONGPATH;
}
} elseif ( 2 == countInitialSeparators(path) )
{ /* The UNC path notation */
oComponent = path.subView(2);
dwCandidatPathType = PATHTYPE_ABSOLUTE_UNC;
} elseif (startsWithDriveColon(path))
{ /* Local path verification. Must start with <drive>: */
oComponent = path.subView(2);
dwCandidatPathType = PATHTYPE_ABSOLUTE_LOCAL;
}
if (bValid && oComponent)
{
oComponent->remove_prefix(1);
/* If the string behind the backslash is empty, we've done */
if (oComponent->empty())
oComponent.reset();
}
}
/* The path can be longer than MAX_PATH only in case it has the longpath prefix */ if (bValid && !(dwPathType & PATHTYPE_IS_LONGPATH) && path.getLength() >= MAX_PATH)
{
bValid = false;
}
/* Now decode the URL what should result in a UTF-8 string */ while ( bValidEncoded && pSrc < pSrcEnd )
{ switch ( *pSrc )
{ case'%':
{ char aToken[3]; char aChar;
// A helper that makes sure that for existing part of the path, the case is correct. // Unlike GetLongPathNameW that it wraps, this function does not require the path to exist. static OUString GetCaseCorrectPathName(std::u16string_view sysPath)
{ // Prepare a null-terminated string first. // Neither OUString, nor u16string_view are guaranteed to be null-terminated
osl::LongPathBuffer<wchar_t> szPath(sysPath.size() + WSTR_LONG_PATH_PREFIX_UNC.size() + 1); wchar_t* const pPath = szPath; wchar_t* pEnd = pPath;
size_t sysPathOffset = 0; if (sysPath.size() >= MAX_PATH && isAbsolute(sysPath)
&& !o3tl::starts_with(sysPath, WSTR_LONG_PATH_PREFIX))
{ // Allow GetLongPathNameW consume long paths
std::u16string_view prefix = WSTR_LONG_PATH_PREFIX; if (startsWithSlashSlash(sysPath))
{
sysPathOffset = 2; // skip leading "\\"
prefix = WSTR_LONG_PATH_PREFIX_UNC;
}
pEnd = std::copy(prefix.begin(), prefix.end(), pEnd);
} wchar_t* const pStart = pEnd;
pEnd = std::copy(sysPath.begin() + sysPathOffset, sysPath.end(), pStart);
*pEnd = 0;
osl::LongPathBuffer<wchar_t> aBuf(EXTENDED_MAX_PATH); while (pEnd > pStart)
{
std::u16string_view curPath(o3tl::toU(pPath), pEnd - pPath); if (curPath == u"\\\\" || curPath == WSTR_SYSTEM_ROOT_PATH
|| curPath == WSTR_LONG_PATH_PREFIX
|| o3tl::equalsIgnoreAsciiCase(curPath, WSTR_LONG_PATH_PREFIX_UNC)) break; // Do not check if the special path prefix exists itself
DWORD nNewLen = GetLongPathNameW(pPath, aBuf, aBuf.getBufSizeInSymbols()); if (nNewLen == 0)
{ // Error? const DWORD err = GetLastError(); if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
{ // Check the base path; skip possible trailing separator
size_t sepPos = curPath.substr(0, curPath.size() - 1).rfind(u'\\'); if (sepPos != std::u16string_view::npos)
{
pEnd = pPath + sepPos;
*pEnd = 0; continue;
}
} else
{
SAL_WARN("sal.osl", "GetLongPathNameW: Windows error code "
<< err << " processing path " << OUString(curPath));
} break; // All other errors, or no separators left
}
assert(nNewLen < aBuf.getBufSizeInSymbols()); // Combine the case-correct leading part with the non-existing trailing part return OUString::Concat(std::u16string_view(o3tl::toU(aBuf), nNewLen))
+ sysPath.substr(pEnd - pStart + sysPathOffset);
}; return OUString(sysPath); // We found no existing parts - just assume it's OK
}
/* Indicates local root */ if ( nDecodedLen == nSkip )
sTempPath = WSTR_SYSTEM_ROOT_PATH; else
{ /* do not separate the directory and file case, so the maximal path length without prefix is MAX_PATH-12 */ if ( nDecodedLen - nSkip <= MAX_PATH - 12 )
{
sTempPath = sDecodedURL->subView(nSkip);
} else
{
sDecodedURL = GetCaseCorrectPathName(sDecodedURL->subView(nSkip)); if (sDecodedURL->getLength() <= MAX_PATH - 12
|| sDecodedURL->startsWith(WSTR_SYSTEM_ROOT_PATH)
|| sDecodedURL->startsWith(WSTR_LONG_PATH_PREFIX))
{
sTempPath = *sDecodedURL;
} elseif (sDecodedURL->startsWith("\\\\"))
{ /* it should be an UNC path, use the according prefix */
sTempPath = OUString::Concat(WSTR_LONG_PATH_PREFIX_UNC) + sDecodedURL->subView(2);
} else
{
sTempPath = WSTR_LONG_PATH_PREFIX + *sDecodedURL;
}
}
}
if (IsValidFilePath(sTempPath, VALIDATEPATH_ALLOW_ELLIPSE, &sTempPath))
nError = osl_File_E_None;
} elseif ( bAllowRelative ) /* This maybe a relative file URL */
{ /* In future the relative path could be converted to absolute if it is too long */
sTempPath = *sDecodedURL;
if (IsValidFilePath(sTempPath, VALIDATEPATH_ALLOW_RELATIVE | VALIDATEPATH_ALLOW_ELLIPSE, &sTempPath))
nError = osl_File_E_None;
} else
SAL_INFO_IF(nError, "sal.osl", "osl_getSystemPathFromFileURL: \"" << strURL << "\" is not an absolute FileURL");
}
if ( osl_File_E_None == nError )
rtl_uString_assign(pustrPath, sTempPath.pData);
SAL_INFO_IF(nError, "sal.osl", "osl_getSystemPathFromFileURL: \"" << strURL << "\" is not a FileURL");
if (strPath)
dwPathType = IsValidFilePath(OUString::unacquired(&strPath), VALIDATEPATH_ALLOW_RELATIVE, nullptr);
if (dwPathType)
{
OUString sTempPath; const OUString& sPath = OUString::unacquired(&strPath);
if ( dwPathType & PATHTYPE_IS_LONGPATH )
{ /* the path has the longpath prefix, let's remove it */ switch ( dwPathType & PATHTYPE_MASK_TYPE )
{ case PATHTYPE_ABSOLUTE_UNC:
static_assert(WSTR_LONG_PATH_PREFIX_UNC.size() == 8, "Unexpected long path UNC prefix!");
/* generate the normal UNC path */
sTempPath = "\\\\" + sPath.copy(8).replace('\\', '/'); break;
case PATHTYPE_ABSOLUTE_LOCAL:
static_assert(WSTR_LONG_PATH_PREFIX.size() == 4, "Unexpected long path prefix!");
/* generate the normal path */
sTempPath = sPath.copy(4).replace('\\', '/'); break;
/* First try to interpret the file name as a URL even a relative one */
error = osl_getSystemPathFromFileURL_(OUString::unacquired(&ustrFileName), &ustrUNCPath.pData, true);
/* So far we either have an UNC path or something invalid
Now create a system path */ if ( osl_File_E_None == error )
error = osl_getSystemPathFromFileURL_(ustrUNCPath, &ustrSysPath.pData, true);
/* Repeat calling SearchPath ... StartwithMAX_PATHforthebuffer.Inmostcasesthis
will be enough and does not force the loop to run twice */
dwResult = MAX_PATH;
do
{ /* If search path is empty use a nullptr pointer instead according to MSDN documentation of SearchPath */
LPCWSTR lpszSearchPath = ustrSystemSearchPath && ustrSystemSearchPath->length ? o3tl::toW(ustrSystemSearchPath->buffer) : nullptr;
LPCWSTR lpszSearchFile = o3tl::toW(ustrSysPath.getStr());
/* Allocate space for buffer according to previous returned count of required chars */ /* +1 is not necessary if we follow MSDN documentation but for robustness we do so */
nBufferLength = dwResult + 1;
lpBuffer = lpBuffer ? static_cast<LPWSTR>(realloc(lpBuffer, nBufferLength * sizeof(WCHAR))) : static_cast<LPWSTR>(malloc(nBufferLength * sizeof(WCHAR)));
if ( ustrBaseURL && ustrBaseURL->length )
{
eError = osl_getSystemPathFromFileURL_(OUString::unacquired(&ustrBaseURL), &ustrBaseSysPath.pData, false);
OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with relative or invalid base URL" );
} if (eError == osl_File_E_None)
{
eError = osl_getSystemPathFromFileURL_(OUString::unacquired(&ustrRelativeURL), &ustrRelSysPath.pData,
!ustrBaseSysPath.isEmpty());
OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with empty base URL and/or invalid relative URL" );
}
if ( !eError )
{
OUString sResultPath; /*@@@ToDo ThewholeFileURLimplementationshouldbemerged withthertl/uriclass.
*/ // If ustrRelSysPath is absolute, we don't need ustrBaseSysPath. if (!ustrBaseSysPath.isEmpty() && !isAbsolute(ustrRelSysPath))
{ // ustrBaseSysPath is known here to be a valid absolute path -> its first two characters // are ASCII (either alpha + colon, or double backslashes)
// Don't use SetCurrentDirectoryW together with GetFullPathNameW, because: // (a) it needs synchronization and may affect threads that may access relative paths; // (b) it would give wrong results for non-existing base path (allowed by RFC2396).
if (startsWithDriveColon(ustrRelSysPath))
{ // Special case: a path relative to a specific drive's current directory. // Should we error out here?
// If ustrBaseSysPath is on the same drive as ustrRelSysPath, then take base path // as is; otherwise, use current directory on ustrRelSysPath's drive as base path if (onSameDrive(ustrRelSysPath, ustrBaseSysPath))
{
sResultPath = combinePath(ustrBaseSysPath, ustrRelSysPath.subView(2));
} else
{ // Call GetFullPathNameW to get current directory on ustrRelSysPath's drive wchar_t baseDrive[3] = { ustrRelSysPath[0], ':', 0 }; // just "C:"
osl::LongPathBuffer<wchar_t> aBuf(EXTENDED_MAX_PATH);
DWORD dwResult
= GetFullPathNameW(baseDrive, aBuf.getBufSizeInSymbols(), aBuf, nullptr); if (dwResult)
{ if (dwResult >= aBuf.getBufSizeInSymbols())
eError = osl_File_E_INVAL; else
sResultPath = combinePath(o3tl::toU(aBuf), ustrRelSysPath.subView(2));
} else
eError = oslTranslateFileError(GetLastError());
}
} else
{ // Is this a rooted relative path (starting with a backslash)? // Then we need only root from base. E.g., // ustrBaseSysPath is "\\server\share\path1\" and ustrRelSysPath is "\path2\to\file" // => \\server\share\path2\to\file // ustrBaseSysPath is "D:\path1\" and ustrRelSysPath is "\path2\to\file" // => D:\path2\to\file auto sBaseView(pathView(ustrBaseSysPath, ustrRelSysPath.startsWith("\\")));
sResultPath = combinePath(sBaseView, ustrRelSysPath);
}
} else
sResultPath = ustrRelSysPath;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.16Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-30)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.