summaryrefslogtreecommitdiff
path: root/sal/osl/w32/file_url.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sal/osl/w32/file_url.cxx')
-rw-r--r--sal/osl/w32/file_url.cxx1143
1 files changed, 1143 insertions, 0 deletions
diff --git a/sal/osl/w32/file_url.cxx b/sal/osl/w32/file_url.cxx
new file mode 100644
index 000000000000..90140cda97c6
--- /dev/null
+++ b/sal/osl/w32/file_url.cxx
@@ -0,0 +1,1143 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#define UNICODE
+#define _UNICODE
+#define _WIN32_WINNT_0x0500
+#include "systools/win32/uwinapi.h"
+
+#include "file_url.h"
+#include "file_error.h"
+
+#include "rtl/alloc.h"
+#include "osl/diagnose.h"
+#include "osl/file.h"
+#include "osl/mutex.h"
+
+#include "path_helper.hxx"
+
+#include <stdio.h>
+#include <tchar.h>
+
+#if OSL_DEBUG_LEVEL > 0
+#define OSL_ENSURE_FILE( cond, msg, file ) ( (cond) ? (void)0 : _osl_warnFile( msg, file ) )
+#else
+#define OSL_ENSURE_FILE( cond, msg, file ) ((void)0)
+#endif
+
+#define ELEMENTS_OF_ARRAY(arr) (sizeof(arr)/(sizeof((arr)[0])))
+
+#define WSTR_SYSTEM_ROOT_PATH L"\\\\.\\"
+#define WSTR_LONG_PATH_PREFIX L"\\\\?\\"
+#define WSTR_LONG_PATH_PREFIX_UNC L"\\\\?\\UNC\\"
+
+
+//##################################################################
+// FileURL functions
+//##################################################################
+
+extern "C" oslMutex g_CurrentDirectoryMutex; /* Initialized in dllentry.c */
+oslMutex g_CurrentDirectoryMutex = 0;
+
+//#####################################################
+static BOOL IsValidFilePathComponent(
+ LPCTSTR lpComponent, LPCTSTR *lppComponentEnd, DWORD dwFlags)
+{
+ LPCTSTR lpComponentEnd = NULL;
+ LPCTSTR lpCurrent = lpComponent;
+ BOOL fValid = TRUE; /* Assume success */
+ TCHAR cLast = 0;
+
+ /* Path component length must not exceed MAX_PATH even if long path with "\\?\" prefix is used */
+
+ while ( !lpComponentEnd && lpCurrent && lpCurrent - lpComponent < MAX_PATH )
+ {
+ 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 ( 1 == lpCurrent - lpComponent )
+ {
+ /* Current directory is O.K. */
+ lpComponentEnd = lpCurrent;
+ break;
+ }
+ else if ( 2 == lpCurrent - lpComponent && '.' == *lpComponent )
+ {
+ /* Parent directory is O.K. */
+ lpComponentEnd = lpCurrent;
+ break;
+ }
+ }
+ case 0:
+ case ' ':
+ lpComponentEnd = lpCurrent - 1;
+ fValid = FALSE;
+ break;
+ default:
+ lpComponentEnd = lpCurrent;
+ break;
+ }
+ break;
+ /* '?' and '*' are valid wildcards but not valid file name characters */
+ case '?':
+ case '*':
+ if ( dwFlags & VALIDATEPATH_ALLOW_WILDCARDS )
+ break;
+ /* The following characters are reserved */
+ case '<':
+ case '>':
+ case '\"':
+ case '|':
+ case ':':
+ lpComponentEnd = lpCurrent;
+ fValid = FALSE;
+ break;
+ default:
+ /* Characters below ASCII 32 are not allowed */
+ if ( *lpCurrent < ' ' )
+ {
+ lpComponentEnd = lpCurrent;
+ fValid = FALSE;
+ }
+ break;
+ }
+ cLast = *lpCurrent++;
+ }
+
+ /* If we don't reached the end of the component the length of the component was to long
+ ( See condition of while loop ) */
+ if ( !lpComponentEnd )
+ {
+ fValid = FALSE;
+ lpComponentEnd = lpCurrent;
+ }
+
+ /* Test wether the component specifies a device name what is not allowed */
+
+ // MT: PERFORMANCE:
+ // This is very expensive. A lot of calls to _tcsicmp.
+ // in SRC6870m71 67.000 calls of this method while empty office start result into more than 1.500.00 calls of _tcsicmp!
+ // Possible optimizations
+ // - Array should be const static
+ // - Sorted array, use binary search
+ // - More intelligent check for com1-9, lpt1-9
+ // Maybe make szComponent upper case, don't search case intensitive
+ // Talked to HRO: Could be removed. Shouldn't be used in OOo, and if used for something like a filename, it will lead to an error anyway.
+ /*
+ if ( fValid )
+ {
+ LPCTSTR alpDeviceNames[] =
+ {
+ TEXT("CON"),
+ TEXT("PRN"),
+ TEXT("AUX"),
+ TEXT("CLOCK$"),
+ TEXT("NUL"),
+ TEXT("LPT1"),
+ TEXT("LPT2"),
+ TEXT("LPT3"),
+ TEXT("LPT4"),
+ TEXT("LPT5"),
+ TEXT("LPT6"),
+ TEXT("LPT7"),
+ TEXT("LPT8"),
+ TEXT("LPT9"),
+ TEXT("COM1"),
+ TEXT("COM2"),
+ TEXT("COM3"),
+ TEXT("COM4"),
+ TEXT("COM5"),
+ TEXT("COM6"),
+ TEXT("COM7"),
+ TEXT("COM8"),
+ TEXT("COM9")
+ };
+
+ TCHAR szComponent[MAX_PATH];
+ int nComponentLength;
+ LPCTSTR lpDot;
+ int i;
+
+ // A device name with an extension is also invalid
+ lpDot = _tcschr( lpComponent, '.' );
+
+ if ( !lpDot || lpDot > lpComponentEnd )
+ nComponentLength = lpComponentEnd - lpComponent;
+ else
+ nComponentLength = lpDot - lpComponent;
+
+ _tcsncpy( szComponent, lpComponent, nComponentLength );
+ szComponent[nComponentLength] = 0;
+
+ for ( i = 0; i < sizeof( alpDeviceNames ) / sizeof(LPCTSTR); i++ )
+ {
+ if ( 0 == _tcsicmp( szComponent, alpDeviceNames[i] ) )
+ {
+ lpComponentEnd = lpComponent;
+ fValid = FALSE;
+ break;
+ }
+ }
+ }
+ */
+
+ if ( fValid )
+ {
+ // Empty components are not allowed
+ if ( lpComponentEnd - lpComponent < 1 )
+ fValid = FALSE;
+
+ // If we reached the end of the string NULL is returned
+ else if ( !*lpComponentEnd )
+ lpComponentEnd = NULL;
+
+ }
+
+ if ( lppComponentEnd )
+ *lppComponentEnd = lpComponentEnd;
+
+ return fValid;
+}
+
+//#####################################################
+#define CHARSET_SEPARATOR TEXT("\\/")
+
+DWORD IsValidFilePath(rtl_uString *path, LPCTSTR *lppError, DWORD dwFlags, rtl_uString **corrected)
+{
+ LPCTSTR lpszPath = reinterpret_cast< LPCTSTR >(path->buffer);
+ LPCTSTR lpComponent = lpszPath;
+ BOOL fValid = TRUE;
+ DWORD dwPathType = PATHTYPE_ERROR;
+ sal_Int32 nLength = rtl_uString_getLength( path );
+
+ if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
+ dwFlags |= VALIDATEPATH_ALLOW_ELLIPSE;
+
+ if ( !lpszPath )
+ fValid = FALSE;
+
+ DWORD dwCandidatPathType = PATHTYPE_ERROR;
+
+ if ( 0 == rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( path->buffer, nLength, reinterpret_cast<const sal_Unicode *>(WSTR_LONG_PATH_PREFIX_UNC), ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX_UNC) - 1, ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX_UNC) - 1 ) )
+ {
+ /* This is long path in UNC notation */
+ lpComponent = lpszPath + ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX_UNC) - 1;
+ dwCandidatPathType = PATHTYPE_ABSOLUTE_UNC | PATHTYPE_IS_LONGPATH;
+ }
+ else if ( 0 == rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( path->buffer, nLength, reinterpret_cast<const sal_Unicode *>(WSTR_LONG_PATH_PREFIX), ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1, ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1 ) )
+ {
+ /* This is long path */
+ lpComponent = lpszPath + ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1;
+
+ if ( _istalpha( lpComponent[0] ) && ':' == lpComponent[1] )
+ {
+ lpComponent += 2;
+ dwCandidatPathType = PATHTYPE_ABSOLUTE_LOCAL | PATHTYPE_IS_LONGPATH;
+ }
+ }
+ else if ( 2 == _tcsspn( lpszPath, CHARSET_SEPARATOR ) )
+ {
+ /* The UNC path notation */
+ lpComponent = lpszPath + 2;
+ dwCandidatPathType = PATHTYPE_ABSOLUTE_UNC;
+ }
+ else if ( _istalpha( lpszPath[0] ) && ':' == lpszPath[1] )
+ {
+ /* Local path verification. Must start with <drive>: */
+ lpComponent = lpszPath + 2;
+ dwCandidatPathType = PATHTYPE_ABSOLUTE_LOCAL;
+ }
+
+ if ( ( dwCandidatPathType & PATHTYPE_MASK_TYPE ) == PATHTYPE_ABSOLUTE_UNC )
+ {
+ fValid = IsValidFilePathComponent( lpComponent, &lpComponent, VALIDATEPATH_ALLOW_ELLIPSE );
+
+ /* So far we have a valid servername. Now let's see if we also have a network resource */
+
+ dwPathType = dwCandidatPathType;
+
+ if ( fValid )
+ {
+ if ( lpComponent && !*++lpComponent )
+ lpComponent = NULL;
+
+ if ( !lpComponent )
+ {
+ #if 0
+ /* We only have a Server specification what is invalid */
+
+ lpComponent = lpszPath;
+ fValid = FALSE;
+ #else
+ dwPathType |= PATHTYPE_IS_SERVER;
+ #endif
+ }
+ else
+ {
+ /* Now test the network resource */
+
+ fValid = IsValidFilePathComponent( lpComponent, &lpComponent, 0 );
+
+ /* If we now reached the end of the path, everything is O.K. */
+
+
+ if ( fValid && (!lpComponent || lpComponent && !*++lpComponent ) )
+ {
+ lpComponent = NULL;
+ dwPathType |= PATHTYPE_IS_VOLUME;
+ }
+ }
+ }
+ }
+ else if ( ( dwCandidatPathType & PATHTYPE_MASK_TYPE ) == PATHTYPE_ABSOLUTE_LOCAL )
+ {
+ if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) )
+ lpComponent++;
+ else if ( *lpComponent )
+ fValid = FALSE;
+
+ dwPathType = dwCandidatPathType;
+
+ /* Now we are behind the backslash or it was a simple drive without backslash */
+
+ if ( fValid && !*lpComponent )
+ {
+ lpComponent = NULL;
+ dwPathType |= PATHTYPE_IS_VOLUME;
+ }
+ }
+ else if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
+ {
+ /* Can be a relative path */
+ lpComponent = lpszPath;
+
+ /* Relative path can start with a backslash */
+
+ if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) )
+ {
+ lpComponent++;
+ if ( !*lpComponent )
+ lpComponent = NULL;
+ }
+
+ dwPathType = PATHTYPE_RELATIVE;
+ }
+ else
+ {
+ /* Anything else is an error */
+ fValid = FALSE;
+ lpComponent = lpszPath;
+ }
+
+ /* Now validate each component of the path */
+ while ( fValid && lpComponent )
+ {
+ // Correct path by merging consecutive slashes:
+ if (*lpComponent == '\\' && corrected != NULL) {
+ sal_Int32 i = lpComponent - lpszPath;
+ rtl_uString_newReplaceStrAt(corrected, path, i, 1, NULL);
+ //TODO: handle out-of-memory
+ lpszPath = reinterpret_cast< LPCTSTR >((*corrected)->buffer);
+ lpComponent = lpszPath + i;
+ }
+
+ fValid = IsValidFilePathComponent( lpComponent, &lpComponent, dwFlags );
+
+ if ( fValid && lpComponent )
+ {
+ lpComponent++;
+
+ /* If the string behind the backslash is empty, we've done */
+
+ if ( !*lpComponent )
+ lpComponent = NULL;
+ }
+ }
+
+ /* The path can be longer than MAX_PATH only in case it has the longpath prefix */
+ if ( fValid && !( dwPathType & PATHTYPE_IS_LONGPATH ) && _tcslen( lpszPath ) >= MAX_PATH )
+ {
+ fValid = FALSE;
+ lpComponent = lpszPath + MAX_PATH;
+ }
+
+ if ( lppError )
+ *lppError = lpComponent;
+
+ return fValid ? dwPathType : PATHTYPE_ERROR;
+}
+
+//#####################################################
+static sal_Int32 PathRemoveFileSpec(LPTSTR lpPath, LPTSTR lpFileName, sal_Int32 nFileBufLen )
+{
+ sal_Int32 nRemoved = 0;
+
+ if ( nFileBufLen )
+ {
+ lpFileName[0] = 0;
+ LPTSTR lpLastBkSlash = _tcsrchr( lpPath, '\\' );
+ LPTSTR lpLastSlash = _tcsrchr( lpPath, '/' );
+ LPTSTR lpLastDelimiter = lpLastSlash > lpLastBkSlash ? lpLastSlash : lpLastBkSlash;
+
+ if ( lpLastDelimiter )
+ {
+ sal_Int32 nDelLen = _tcslen( lpLastDelimiter );
+ if ( 1 == nDelLen )
+ {
+ if ( lpLastDelimiter > lpPath && *(lpLastDelimiter - 1) != ':' )
+ {
+ *lpLastDelimiter = 0;
+ *lpFileName = 0;
+ nRemoved = nDelLen;
+ }
+ }
+ else if ( nDelLen && nDelLen - 1 < nFileBufLen )
+ {
+ _tcscpy( lpFileName, lpLastDelimiter + 1 );
+ *(++lpLastDelimiter) = 0;
+ nRemoved = nDelLen - 1;
+ }
+ }
+ }
+
+ return nRemoved;
+}
+
+//#####################################################
+// Undocumented in SHELL32.DLL ordinal 32
+static LPTSTR PathAddBackslash(LPTSTR lpPath, sal_Int32 nBufLen)
+{
+ LPTSTR lpEndPath = NULL;
+
+ if ( lpPath )
+ {
+ int nLen = _tcslen(lpPath);
+
+ if ( !nLen || lpPath[nLen-1] != '\\' && lpPath[nLen-1] != '/' && nLen < nBufLen - 1 )
+ {
+ lpEndPath = lpPath + nLen;
+ *lpEndPath++ = '\\';
+ *lpEndPath = 0;
+ }
+ }
+ return lpEndPath;
+}
+
+//#####################################################
+// Same as GetLongPathName but also 95/NT4
+static DWORD GetCaseCorrectPathNameEx(
+ LPTSTR lpszPath, // path buffer to convert
+ DWORD cchBuffer, // size of path buffer
+ DWORD nSkipLevels,
+ BOOL bCheckExistence )
+{
+ ::osl::LongPathBuffer< WCHAR > szFile( MAX_PATH + 1 );
+ sal_Int32 nRemoved = PathRemoveFileSpec( lpszPath, szFile, MAX_PATH + 1 );
+ sal_Int32 nLastStepRemoved = nRemoved;
+ while ( nLastStepRemoved && szFile[0] == 0 )
+ {
+ // remove separators
+ nLastStepRemoved = PathRemoveFileSpec( lpszPath, szFile, MAX_PATH + 1 );
+ nRemoved += nLastStepRemoved;
+ }
+
+ if ( nRemoved )
+ {
+ BOOL bSkipThis = FALSE;
+
+ if ( 0 == _tcscmp( szFile, TEXT("..") ) )
+ {
+ bSkipThis = TRUE;
+ nSkipLevels += 1;
+ }
+ else if ( 0 == _tcscmp( szFile, TEXT(".") ) )
+ {
+ bSkipThis = TRUE;
+ }
+ else if ( nSkipLevels )
+ {
+ bSkipThis = TRUE;
+ nSkipLevels--;
+ }
+ else
+ bSkipThis = FALSE;
+
+ GetCaseCorrectPathNameEx( lpszPath, cchBuffer, nSkipLevels, bCheckExistence );
+
+ PathAddBackslash( lpszPath, cchBuffer );
+
+ /* Analyze parent if not only a trailing backslash was cutted but a real file spec */
+ if ( !bSkipThis )
+ {
+ if ( bCheckExistence )
+ {
+ ::osl::LongPathBuffer< WCHAR > aShortPath( MAX_LONG_PATH );
+ _tcscpy( aShortPath, lpszPath );
+ _tcscat( aShortPath, szFile );
+
+ WIN32_FIND_DATA aFindFileData;
+ HANDLE hFind = FindFirstFile( aShortPath, &aFindFileData );
+
+ if ( IsValidHandle(hFind) )
+ {
+ _tcscat( lpszPath, aFindFileData.cFileName[0] ? aFindFileData.cFileName : aFindFileData.cAlternateFileName );
+
+ FindClose( hFind );
+ }
+ else
+ lpszPath[0] = 0;
+ }
+ else
+ {
+ /* add the segment name back */
+ _tcscat( lpszPath, szFile );
+ }
+ }
+ }
+ else
+ {
+ /* File specification can't be removed therefore the short path is either a drive
+ or a network share. If still levels to skip are left, the path specification
+ tries to travel below the file system root */
+ if ( nSkipLevels )
+ lpszPath[0] = 0;
+ else
+ _tcsupr( lpszPath );
+ }
+
+ return _tcslen( lpszPath );
+}
+
+//#####################################################
+#define WSTR_SYSTEM_ROOT_PATH L"\\\\.\\"
+
+DWORD GetCaseCorrectPathName(
+ LPCTSTR lpszShortPath, // file name
+ LPTSTR lpszLongPath, // path buffer
+ DWORD cchBuffer, // size of path buffer
+ BOOL bCheckExistence
+)
+{
+ /* Special handling for "\\.\" as system root */
+ if ( lpszShortPath && 0 == wcscmp( lpszShortPath, WSTR_SYSTEM_ROOT_PATH ) )
+ {
+ if ( cchBuffer >= ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) )
+ {
+ wcscpy( lpszLongPath, WSTR_SYSTEM_ROOT_PATH );
+ return ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1;
+ }
+ else
+ {
+ return ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1;
+ }
+ }
+ else if ( lpszShortPath )
+ {
+ if ( _tcslen( lpszShortPath ) <= cchBuffer )
+ {
+ _tcscpy( lpszLongPath, lpszShortPath );
+ return GetCaseCorrectPathNameEx( lpszLongPath, cchBuffer, 0, bCheckExistence );
+ }
+ }
+
+ return 0;
+}
+
+
+//#############################################
+static sal_Bool _osl_decodeURL( rtl_String* strUTF8, rtl_uString** pstrDecodedURL )
+{
+ sal_Char *pBuffer;
+ const sal_Char *pSrcEnd;
+ const sal_Char *pSrc;
+ sal_Char *pDest;
+ sal_Int32 nSrcLen;
+ sal_Bool bValidEncoded = sal_True; /* Assume success */
+
+ /* The resulting decoded string length is shorter or equal to the source length */
+
+ nSrcLen = rtl_string_getLength(strUTF8);
+ pBuffer = reinterpret_cast<sal_Char*>(rtl_allocateMemory(nSrcLen + 1));
+
+ pDest = pBuffer;
+ pSrc = rtl_string_getStr(strUTF8);
+ pSrcEnd = pSrc + nSrcLen;
+
+ /* Now decode the URL what should result in an UTF8 string */
+ while ( bValidEncoded && pSrc < pSrcEnd )
+ {
+ switch ( *pSrc )
+ {
+ case '%':
+ {
+ sal_Char aToken[3];
+ sal_Char aChar;
+
+ pSrc++;
+ aToken[0] = *pSrc++;
+ aToken[1] = *pSrc++;
+ aToken[2] = 0;
+
+ aChar = (sal_Char)strtoul( aToken, NULL, 16 );
+
+ /* The chars are path delimiters and must not be encoded */
+
+ if ( 0 == aChar || '\\' == aChar || '/' == aChar || ':' == aChar )
+ bValidEncoded = sal_False;
+ else
+ *pDest++ = aChar;
+ }
+ break;
+ default:
+ *pDest++ = *pSrc++;
+ break;
+ }
+ }
+
+ *pDest++ = 0;
+
+ if ( bValidEncoded )
+ {
+ rtl_string2UString( pstrDecodedURL, pBuffer, rtl_str_getLength(pBuffer), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );
+ OSL_ASSERT(*pstrDecodedURL != 0);
+ }
+
+ rtl_freeMemory( pBuffer );
+
+ return bValidEncoded;
+}
+
+//#############################################
+static void _osl_encodeURL( rtl_uString *strURL, rtl_String **pstrEncodedURL )
+{
+ /* Encode non ascii characters within the URL */
+
+ rtl_String *strUTF8 = NULL;
+ sal_Char *pszEncodedURL;
+ const sal_Char *pURLScan;
+ sal_Char *pURLDest;
+ sal_Int32 nURLScanLen;
+ sal_Int32 nURLScanCount;
+
+ rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );
+
+ pszEncodedURL = (sal_Char*) rtl_allocateMemory( (rtl_string_getLength( strUTF8 ) * 3 + 1) * sizeof(sal_Char) );
+
+ pURLDest = pszEncodedURL;
+ pURLScan = rtl_string_getStr( strUTF8 );
+ nURLScanLen = rtl_string_getLength( strUTF8 );
+ nURLScanCount = 0;
+
+ while ( nURLScanCount < nURLScanLen )
+ {
+ sal_Char cCurrent = *pURLScan;
+ switch ( cCurrent )
+ {
+ default:
+ if (!( ( cCurrent >= 'a' && cCurrent <= 'z' ) || ( cCurrent >= 'A' && cCurrent <= 'Z' ) || ( cCurrent >= '0' && cCurrent <= '9' ) ) )
+ {
+ sprintf( pURLDest, "%%%02X", (unsigned char)cCurrent );
+ pURLDest += 3;
+ break;
+ }
+ case '!':
+ case '\'':
+ case '(':
+ case ')':
+ case '*':
+ case '-':
+ case '.':
+ case '_':
+ case '~':
+ case '$':
+ case '&':
+ case '+':
+ case ',':
+ case '=':
+ case '@':
+ case ':':
+ case '/':
+ case '\\':
+ case '|':
+ *pURLDest++ = cCurrent;
+ break;
+ case 0:
+ break;
+ }
+
+ pURLScan++;
+ nURLScanCount++;
+ }
+
+ *pURLDest = 0;
+
+ rtl_string_release( strUTF8 );
+ rtl_string_newFromStr( pstrEncodedURL, pszEncodedURL );
+ rtl_freeMemory( pszEncodedURL );
+}
+
+//#############################################
+
+oslFileError _osl_getSystemPathFromFileURL( rtl_uString *strURL, rtl_uString **pustrPath, sal_Bool bAllowRelative )
+{
+ rtl_String *strUTF8 = NULL;
+ rtl_uString *strDecodedURL = NULL;
+ rtl_uString *strTempPath = NULL;
+ const sal_Unicode *pDecodedURL;
+ sal_uInt32 nDecodedLen;
+ sal_Bool bValidEncoded;
+ oslFileError nError = osl_File_E_INVAL; /* Assume failure */
+
+ /* If someone hasn't encoded the complete URL we convert it to UTF8 now to prevent from
+ having a mixed encoded URL later */
+
+ rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );
+
+ /* If the length of strUTF8 and strURL differs it indicates that the URL was not correct encoded */
+
+ OSL_ENSURE_FILE(
+ strUTF8->length == strURL->length ||
+ 0 != rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( strURL->buffer, strURL->length, "file:\\\\", 7 )
+ ,"osl_getSystemPathFromFileURL: \"%s\" is not encoded !!!", strURL );
+
+ bValidEncoded = _osl_decodeURL( strUTF8, &strDecodedURL );
+
+ /* Release the encoded UTF8 string */
+ rtl_string_release( strUTF8 );
+
+ if ( bValidEncoded )
+ {
+ /* Replace backslashes and pipes */
+
+ rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '/', '\\' );
+ rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '|', ':' );
+
+ pDecodedURL = rtl_uString_getStr( strDecodedURL );
+ nDecodedLen = rtl_uString_getLength( strDecodedURL );
+
+ /* Must start with "file://" */
+ if ( 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL, nDecodedLen, "file:\\\\", 7 ) )
+ {
+ sal_uInt32 nSkip;
+
+ if ( 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL, nDecodedLen, "file:\\\\\\", 8 ) )
+ nSkip = 8;
+ else if (
+ 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL, nDecodedLen, "file:\\\\localhost\\", 17 ) ||
+ 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL, nDecodedLen, "file:\\\\127.0.0.1\\", 17 )
+ )
+ nSkip = 17;
+ else
+ nSkip = 5;
+
+ /* Indicates local root */
+ if ( nDecodedLen == nSkip )
+ rtl_uString_newFromStr_WithLength( &strTempPath, reinterpret_cast<const sal_Unicode*>(WSTR_SYSTEM_ROOT_PATH), ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1 );
+ else
+ {
+ /* do not separate the directory and file case, so the maximal path lengs without prefix is MAX_PATH-12 */
+ if ( nDecodedLen - nSkip <= MAX_PATH - 12 )
+ {
+ rtl_uString_newFromStr_WithLength( &strTempPath, pDecodedURL + nSkip, nDecodedLen - nSkip );
+ }
+ else
+ {
+ ::osl::LongPathBuffer< sal_Unicode > aBuf( MAX_LONG_PATH );
+ sal_uInt32 nNewLen = GetCaseCorrectPathName( reinterpret_cast<LPCTSTR>(pDecodedURL + nSkip),
+ ::osl::mingw_reinterpret_cast<LPTSTR>(aBuf),
+ aBuf.getBufSizeInSymbols(),
+ sal_False );
+
+ if ( nNewLen <= MAX_PATH - 12
+ || 0 == rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL + nSkip, nDecodedLen - nSkip, reinterpret_cast<const sal_Unicode*>(WSTR_SYSTEM_ROOT_PATH), ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1, ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1 )
+ || 0 == rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL + nSkip, nDecodedLen - nSkip, reinterpret_cast<const sal_Unicode*>(WSTR_LONG_PATH_PREFIX), ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1, ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1 ) )
+ {
+ rtl_uString_newFromStr_WithLength( &strTempPath, aBuf, nNewLen );
+ }
+ else if ( pDecodedURL[nSkip] == (sal_Unicode)'\\' && pDecodedURL[nSkip+1] == (sal_Unicode)'\\' )
+ {
+ /* it should be an UNC path, use the according prefix */
+ rtl_uString *strSuffix = NULL;
+ rtl_uString *strPrefix = NULL;
+ rtl_uString_newFromStr_WithLength( &strPrefix, reinterpret_cast<const sal_Unicode*>(WSTR_LONG_PATH_PREFIX_UNC), ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX_UNC ) - 1 );
+ rtl_uString_newFromStr_WithLength( &strSuffix, aBuf + 2, nNewLen - 2 );
+
+ rtl_uString_newConcat( &strTempPath, strPrefix, strSuffix );
+
+ rtl_uString_release( strPrefix );
+ rtl_uString_release( strSuffix );
+ }
+ else
+ {
+ rtl_uString *strSuffix = NULL;
+ rtl_uString *strPrefix = NULL;
+ rtl_uString_newFromStr_WithLength( &strPrefix, reinterpret_cast<const sal_Unicode*>(WSTR_LONG_PATH_PREFIX), ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX ) - 1 );
+ rtl_uString_newFromStr_WithLength( &strSuffix, aBuf, nNewLen );
+
+ rtl_uString_newConcat( &strTempPath, strPrefix, strSuffix );
+
+ rtl_uString_release( strPrefix );
+ rtl_uString_release( strSuffix );
+ }
+ }
+ }
+
+ if ( IsValidFilePath( strTempPath, NULL, VALIDATEPATH_ALLOW_ELLIPSE, &strTempPath ) )
+ nError = osl_File_E_None;
+ }
+ else if ( bAllowRelative ) /* This maybe a relative file URL */
+ {
+ /* In future the relative path could be converted to absolute if it is too long */
+ rtl_uString_assign( &strTempPath, strDecodedURL );
+
+ if ( IsValidFilePath( strTempPath, NULL, VALIDATEPATH_ALLOW_RELATIVE | VALIDATEPATH_ALLOW_ELLIPSE, &strTempPath ) )
+ nError = osl_File_E_None;
+ }
+ /*
+ else
+ OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not an absolute FileURL !!!", strURL );
+ */
+
+ }
+
+ if ( strDecodedURL )
+ rtl_uString_release( strDecodedURL );
+
+ if ( osl_File_E_None == nError )
+ rtl_uString_assign( pustrPath, strTempPath );
+
+ if ( strTempPath )
+ rtl_uString_release( strTempPath );
+
+ /*
+ OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not a FileURL !!!", strURL );
+ */
+
+ return nError;
+}
+
+//#############################################
+oslFileError _osl_getFileURLFromSystemPath( rtl_uString* strPath, rtl_uString** pstrURL )
+{
+ oslFileError nError = osl_File_E_INVAL; /* Assume failure */
+ rtl_uString *strTempURL = NULL;
+ DWORD dwPathType = PATHTYPE_ERROR;
+
+ if (strPath)
+ dwPathType = IsValidFilePath(strPath, NULL, VALIDATEPATH_ALLOW_RELATIVE, NULL);
+
+ if (dwPathType)
+ {
+ rtl_uString *strTempPath = NULL;
+
+ if ( dwPathType & PATHTYPE_IS_LONGPATH )
+ {
+ rtl_uString *strBuffer = NULL;
+ sal_uInt32 nIgnore = 0;
+ sal_uInt32 nLength = 0;
+
+ /* the path has the longpath prefix, lets remove it */
+ switch ( dwPathType & PATHTYPE_MASK_TYPE )
+ {
+ case PATHTYPE_ABSOLUTE_UNC:
+ nIgnore = ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX_UNC ) - 1;
+ OSL_ENSURE( nIgnore == 8, "Unexpected long path UNC prefix!" );
+
+ /* generate the normal UNC path */
+ nLength = rtl_uString_getLength( strPath );
+ rtl_uString_newFromStr_WithLength( &strBuffer, strPath->buffer + nIgnore - 2, nLength - nIgnore + 2 );
+ strBuffer->buffer[0] = '\\';
+
+ rtl_uString_newReplace( &strTempPath, strBuffer, '\\', '/' );
+ rtl_uString_release( strBuffer );
+ break;
+
+ case PATHTYPE_ABSOLUTE_LOCAL:
+ nIgnore = ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX ) - 1;
+ OSL_ENSURE( nIgnore == 4, "Unexpected long path prefix!" );
+
+ /* generate the normal path */
+ nLength = rtl_uString_getLength( strPath );
+ rtl_uString_newFromStr_WithLength( &strBuffer, strPath->buffer + nIgnore, nLength - nIgnore );
+
+ rtl_uString_newReplace( &strTempPath, strBuffer, '\\', '/' );
+ rtl_uString_release( strBuffer );
+ break;
+
+ default:
+ OSL_ASSERT( "Unexpected long path format!" );
+ rtl_uString_newReplace( &strTempPath, strPath, '\\', '/' );
+ break;
+ }
+ }
+ else
+ {
+ /* Replace backslashes */
+ rtl_uString_newReplace( &strTempPath, strPath, '\\', '/' );
+ }
+
+ switch ( dwPathType & PATHTYPE_MASK_TYPE )
+ {
+ case PATHTYPE_RELATIVE:
+ rtl_uString_assign( &strTempURL, strTempPath );
+ nError = osl_File_E_None;
+ break;
+ case PATHTYPE_ABSOLUTE_UNC:
+ rtl_uString_newFromAscii( &strTempURL, "file:" );
+ rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath );
+ nError = osl_File_E_None;
+ break;
+ case PATHTYPE_ABSOLUTE_LOCAL:
+ rtl_uString_newFromAscii( &strTempURL, "file:///" );
+ rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath );
+ nError = osl_File_E_None;
+ break;
+ default:
+ break;
+ }
+
+ /* Release temp path */
+ rtl_uString_release( strTempPath );
+ }
+
+ if ( osl_File_E_None == nError )
+ {
+ rtl_String *strEncodedURL = NULL;
+
+ /* Encode the URL */
+ _osl_encodeURL( strTempURL, &strEncodedURL );
+
+ /* Provide URL via unicode string */
+ rtl_string2UString( pstrURL, rtl_string_getStr(strEncodedURL), rtl_string_getLength(strEncodedURL), RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS );
+ OSL_ASSERT(*pstrURL != 0);
+ rtl_string_release( strEncodedURL );
+ }
+
+ /* Release temp URL */
+ if ( strTempURL )
+ rtl_uString_release( strTempURL );
+
+ /*
+ OSL_ENSURE_FILE( !nError, "osl_getFileURLFromSystemPath: \"%s\" is not a systemPath !!!", strPath );
+ */
+ return nError;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_getFileURLFromSystemPath(
+ rtl_uString* ustrPath, rtl_uString** pustrURL )
+{
+ return _osl_getFileURLFromSystemPath( ustrPath, pustrURL );
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_getSystemPathFromFileURL(
+ rtl_uString *ustrURL, rtl_uString **pustrPath)
+{
+ return _osl_getSystemPathFromFileURL( ustrURL, pustrPath, sal_True );
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_searchFileURL(
+ rtl_uString *ustrFileName,
+ rtl_uString *ustrSystemSearchPath,
+ rtl_uString **pustrPath)
+{
+ rtl_uString *ustrUNCPath = NULL;
+ rtl_uString *ustrSysPath = NULL;
+ oslFileError error;
+
+ /* First try to interpret the file name as an URL even a relative one */
+ error = _osl_getSystemPathFromFileURL( ustrFileName, &ustrUNCPath, sal_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, sal_True );
+
+ if ( osl_File_E_None == error )
+ {
+ DWORD nBufferLength;
+ DWORD dwResult;
+ LPTSTR lpBuffer = NULL;
+ LPTSTR lpszFilePart;
+
+ /* Repeat calling SearchPath ...
+ Start with MAX_PATH for the buffer. In most cases this
+ will be enough and does not force the loop to runtwice */
+ dwResult = MAX_PATH;
+
+ do
+ {
+ /* If search path is empty use a NULL pointer instead according to MSDN documentation of SearchPath */
+ LPCTSTR lpszSearchPath = ustrSystemSearchPath && ustrSystemSearchPath->length ? reinterpret_cast<LPCTSTR>(ustrSystemSearchPath->buffer) : NULL;
+ LPCTSTR lpszSearchFile = reinterpret_cast<LPCTSTR>(ustrSysPath->buffer);
+
+ /* Allocate space for buffer according to previous returned count of required chars */
+ /* +1 is not neccessary if we follow MSDN documentation but for robustness we do so */
+ nBufferLength = dwResult + 1;
+ lpBuffer = lpBuffer ?
+ reinterpret_cast<LPTSTR>(rtl_reallocateMemory(lpBuffer, nBufferLength * sizeof(TCHAR))) :
+ reinterpret_cast<LPTSTR>(rtl_allocateMemory(nBufferLength * sizeof(TCHAR)));
+
+ dwResult = SearchPath( lpszSearchPath, lpszSearchFile, NULL, nBufferLength, lpBuffer, &lpszFilePart );
+ } while ( dwResult && dwResult >= nBufferLength );
+
+ /* ... until an error occures or buffer is large enough.
+ dwResult == nBufferLength can not happen according to documentation but lets be robust ;-) */
+
+ if ( dwResult )
+ {
+ rtl_uString_newFromStr( &ustrSysPath, reinterpret_cast<const sal_Unicode*>(lpBuffer) );
+ error = osl_getFileURLFromSystemPath( ustrSysPath, pustrPath );
+ }
+ else
+ {
+ WIN32_FIND_DATA aFindFileData;
+ HANDLE hFind;
+
+ /* Somthing went wrong, perhaps the path was absolute */
+ error = oslTranslateFileError( GetLastError() );
+
+ hFind = FindFirstFile( reinterpret_cast<LPCTSTR>(ustrSysPath->buffer), &aFindFileData );
+
+ if ( IsValidHandle(hFind) )
+ {
+ error = osl_getFileURLFromSystemPath( ustrSysPath, pustrPath );
+ FindClose( hFind );
+ }
+ }
+
+ rtl_freeMemory( lpBuffer );
+ }
+
+ if ( ustrSysPath )
+ rtl_uString_release( ustrSysPath );
+
+ if ( ustrUNCPath )
+ rtl_uString_release( ustrUNCPath );
+
+ return error;
+}
+
+//#####################################################
+
+oslFileError SAL_CALL osl_getAbsoluteFileURL( rtl_uString* ustrBaseURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL )
+{
+ oslFileError eError;
+ rtl_uString *ustrRelSysPath = NULL;
+ rtl_uString *ustrBaseSysPath = NULL;
+
+ if ( ustrBaseURL && ustrBaseURL->length )
+ {
+ eError = _osl_getSystemPathFromFileURL( ustrBaseURL, &ustrBaseSysPath, sal_False );
+ OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with relative or invalid base URL" );
+
+ eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_True );
+ }
+ else
+ {
+ eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_False );
+ OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with empty base URL and/or invalid relative URL" );
+ }
+
+ if ( !eError )
+ {
+ ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
+ ::osl::LongPathBuffer< sal_Unicode > aCurrentDir( MAX_LONG_PATH );
+ LPTSTR lpFilePart = NULL;
+ DWORD dwResult;
+
+/*@@@ToDo
+ Bad, bad hack, this only works if the base path
+ really exists which is not necessary according
+ to RFC2396
+ The whole FileURL implementation should be merged
+ with the rtl/uri class.
+*/
+ if ( ustrBaseSysPath )
+ {
+ osl_acquireMutex( g_CurrentDirectoryMutex );
+
+ GetCurrentDirectoryW( aCurrentDir.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aCurrentDir) );
+ SetCurrentDirectoryW( reinterpret_cast<LPCWSTR>(ustrBaseSysPath->buffer) );
+ }
+
+ dwResult = GetFullPathNameW( reinterpret_cast<LPCWSTR>(ustrRelSysPath->buffer), aBuffer.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), &lpFilePart );
+
+ if ( ustrBaseSysPath )
+ {
+ SetCurrentDirectoryW( ::osl::mingw_reinterpret_cast<LPCWSTR>(aCurrentDir) );
+
+ osl_releaseMutex( g_CurrentDirectoryMutex );
+ }
+
+ if ( dwResult )
+ {
+ if ( dwResult >= aBuffer.getBufSizeInSymbols() )
+ eError = osl_File_E_INVAL;
+ else
+ {
+ rtl_uString *ustrAbsSysPath = NULL;
+
+ rtl_uString_newFromStr( &ustrAbsSysPath, aBuffer );
+
+ eError = osl_getFileURLFromSystemPath( ustrAbsSysPath, pustrAbsoluteURL );
+
+ if ( ustrAbsSysPath )
+ rtl_uString_release( ustrAbsSysPath );
+ }
+ }
+ else
+ eError = oslTranslateFileError( GetLastError() );
+ }
+
+ if ( ustrBaseSysPath )
+ rtl_uString_release( ustrBaseSysPath );
+
+ if ( ustrRelSysPath )
+ rtl_uString_release( ustrRelSysPath );
+
+ return eError;
+}
+
+//#####################################################
+oslFileError SAL_CALL osl_getCanonicalName( rtl_uString *strRequested, rtl_uString **strValid )
+{
+ rtl_uString_newFromString(strValid, strRequested);
+ return osl_File_E_None;
+}