2009-09-09 04:38:41 -05:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
*
|
2010-02-12 08:01:35 -06:00
|
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
2009-09-09 04:38:41 -05:00
|
|
|
*
|
|
|
|
* 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"
|
|
|
|
|
2010-01-29 09:56:48 -06:00
|
|
|
#include "path_helper.hxx"
|
|
|
|
|
2009-09-09 04:38:41 -05:00
|
|
|
#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])))
|
|
|
|
|
2010-01-26 10:42:23 -06:00
|
|
|
#define WSTR_SYSTEM_ROOT_PATH L"\\\\.\\"
|
|
|
|
#define WSTR_LONG_PATH_PREFIX L"\\\\?\\"
|
|
|
|
#define WSTR_LONG_PATH_PREFIX_UNC L"\\\\?\\UNC\\"
|
|
|
|
|
|
|
|
|
2009-09-09 04:38:41 -05:00
|
|
|
//##################################################################
|
|
|
|
// 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;
|
|
|
|
|
2010-01-26 10:42:23 -06:00
|
|
|
/* Path component length must not exceed MAX_PATH even if long path with "\\?\" prefix is used */
|
2009-09-09 04:38:41 -05:00
|
|
|
|
|
|
|
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);
|
2010-01-26 10:42:23 -06:00
|
|
|
LPCTSTR lpComponent = lpszPath;
|
2009-09-09 04:38:41 -05:00
|
|
|
BOOL fValid = TRUE;
|
|
|
|
DWORD dwPathType = PATHTYPE_ERROR;
|
2010-01-26 10:42:23 -06:00
|
|
|
sal_Int32 nLength = rtl_uString_getLength( path );
|
2009-09-09 04:38:41 -05:00
|
|
|
|
|
|
|
if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
|
|
|
|
dwFlags |= VALIDATEPATH_ALLOW_ELLIPSE;
|
|
|
|
|
|
|
|
if ( !lpszPath )
|
|
|
|
fValid = FALSE;
|
|
|
|
|
2010-01-26 10:42:23 -06:00
|
|
|
DWORD dwCandidatPathType = PATHTYPE_ERROR;
|
|
|
|
|
2010-03-24 05:21:47 -05:00
|
|
|
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 ) )
|
2010-01-26 10:42:23 -06:00
|
|
|
{
|
|
|
|
/* 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;
|
|
|
|
}
|
2010-03-24 05:21:47 -05:00
|
|
|
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 ) )
|
2009-09-09 04:38:41 -05:00
|
|
|
{
|
2010-01-26 10:42:23 -06:00
|
|
|
/* This is long path */
|
|
|
|
lpComponent = lpszPath + ELEMENTS_OF_ARRAY(WSTR_LONG_PATH_PREFIX) - 1;
|
2009-09-09 04:38:41 -05:00
|
|
|
|
2010-01-26 10:42:23 -06:00
|
|
|
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 */
|
2009-09-09 04:38:41 -05:00
|
|
|
lpComponent = lpszPath + 2;
|
2010-01-26 10:42:23 -06:00
|
|
|
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;
|
|
|
|
}
|
2009-09-09 04:38:41 -05:00
|
|
|
|
2010-01-26 10:42:23 -06:00
|
|
|
if ( ( dwCandidatPathType & PATHTYPE_MASK_TYPE ) == PATHTYPE_ABSOLUTE_UNC )
|
|
|
|
{
|
2009-09-09 04:38:41 -05:00
|
|
|
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 */
|
|
|
|
|
2010-01-26 10:42:23 -06:00
|
|
|
dwPathType = dwCandidatPathType;
|
2009-09-09 04:38:41 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-01-26 10:42:23 -06:00
|
|
|
else if ( ( dwCandidatPathType & PATHTYPE_MASK_TYPE ) == PATHTYPE_ABSOLUTE_LOCAL )
|
2009-09-09 04:38:41 -05:00
|
|
|
{
|
|
|
|
if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) )
|
|
|
|
lpComponent++;
|
|
|
|
else if ( *lpComponent )
|
|
|
|
fValid = FALSE;
|
|
|
|
|
2010-01-26 10:42:23 -06:00
|
|
|
dwPathType = dwCandidatPathType;
|
2009-09-09 04:38:41 -05:00
|
|
|
|
|
|
|
/* 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 )
|
|
|
|
{
|
2010-01-26 10:42:23 -06:00
|
|
|
/* Can be a relative path */
|
2009-09-09 04:38:41 -05:00
|
|
|
lpComponent = lpszPath;
|
|
|
|
|
|
|
|
/* Relative path can start with a backslash */
|
|
|
|
|
|
|
|
if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) )
|
|
|
|
{
|
|
|
|
lpComponent++;
|
|
|
|
if ( !*lpComponent )
|
|
|
|
lpComponent = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
dwPathType = PATHTYPE_RELATIVE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-01-26 10:42:23 -06:00
|
|
|
/* Anything else is an error */
|
2009-09-09 04:38:41 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-27 03:26:25 -06:00
|
|
|
/* 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 )
|
2009-09-09 04:38:41 -05:00
|
|
|
{
|
|
|
|
fValid = FALSE;
|
|
|
|
lpComponent = lpszPath + MAX_PATH;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( lppError )
|
|
|
|
*lppError = lpComponent;
|
|
|
|
|
|
|
|
return fValid ? dwPathType : PATHTYPE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
//#####################################################
|
2010-01-29 09:56:48 -06:00
|
|
|
static sal_Int32 PathRemoveFileSpec(LPTSTR lpPath, LPTSTR lpFileName, sal_Int32 nFileBufLen )
|
2009-09-09 04:38:41 -05:00
|
|
|
{
|
2010-01-29 09:56:48 -06:00
|
|
|
sal_Int32 nRemoved = 0;
|
2009-09-09 04:38:41 -05:00
|
|
|
|
2010-01-29 09:56:48 -06:00
|
|
|
if ( nFileBufLen )
|
2009-09-09 04:38:41 -05:00
|
|
|
{
|
2010-01-29 09:56:48 -06:00
|
|
|
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 )
|
2009-09-09 04:38:41 -05:00
|
|
|
{
|
2010-01-29 09:56:48 -06:00
|
|
|
if ( lpLastDelimiter > lpPath && *(lpLastDelimiter - 1) != ':' )
|
|
|
|
{
|
|
|
|
*lpLastDelimiter = 0;
|
|
|
|
*lpFileName = 0;
|
|
|
|
nRemoved = nDelLen;
|
|
|
|
}
|
2009-09-09 04:38:41 -05:00
|
|
|
}
|
2010-01-29 09:56:48 -06:00
|
|
|
else if ( nDelLen && nDelLen - 1 < nFileBufLen )
|
|
|
|
{
|
|
|
|
_tcscpy( lpFileName, lpLastDelimiter + 1 );
|
|
|
|
*(++lpLastDelimiter) = 0;
|
|
|
|
nRemoved = nDelLen - 1;
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 04:38:41 -05:00
|
|
|
}
|
2010-01-29 09:56:48 -06:00
|
|
|
|
|
|
|
return nRemoved;
|
2009-09-09 04:38:41 -05:00
|
|
|
}
|
|
|
|
|
2010-01-28 06:56:00 -06:00
|
|
|
//#####################################################
|
|
|
|
// 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(
|
2010-01-29 09:56:48 -06:00
|
|
|
LPTSTR lpszPath, // path buffer to convert
|
2010-01-28 06:56:00 -06:00
|
|
|
DWORD cchBuffer, // size of path buffer
|
|
|
|
DWORD nSkipLevels,
|
|
|
|
BOOL bCheckExistence )
|
|
|
|
{
|
2010-03-24 05:21:47 -05:00
|
|
|
::osl::LongPathBuffer< WCHAR > szFile( MAX_PATH + 1 );
|
2010-01-29 09:56:48 -06:00
|
|
|
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;
|
|
|
|
}
|
2010-01-28 06:56:00 -06:00
|
|
|
|
2010-01-29 09:56:48 -06:00
|
|
|
if ( nRemoved )
|
2010-01-28 06:56:00 -06:00
|
|
|
{
|
2010-01-29 09:56:48 -06:00
|
|
|
BOOL bSkipThis = FALSE;
|
2010-01-28 06:56:00 -06:00
|
|
|
|
2010-01-29 09:56:48 -06:00
|
|
|
if ( 0 == _tcscmp( szFile, TEXT("..") ) )
|
2010-01-28 06:56:00 -06:00
|
|
|
{
|
|
|
|
bSkipThis = TRUE;
|
|
|
|
nSkipLevels += 1;
|
|
|
|
}
|
2010-01-29 09:56:48 -06:00
|
|
|
else if ( 0 == _tcscmp( szFile, TEXT(".") ) )
|
2010-01-28 06:56:00 -06:00
|
|
|
{
|
|
|
|
bSkipThis = TRUE;
|
|
|
|
}
|
|
|
|
else if ( nSkipLevels )
|
|
|
|
{
|
|
|
|
bSkipThis = TRUE;
|
|
|
|
nSkipLevels--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
bSkipThis = FALSE;
|
|
|
|
|
2010-01-29 09:56:48 -06:00
|
|
|
GetCaseCorrectPathNameEx( lpszPath, cchBuffer, nSkipLevels, bCheckExistence );
|
2010-01-28 06:56:00 -06:00
|
|
|
|
2010-01-29 09:56:48 -06:00
|
|
|
PathAddBackslash( lpszPath, cchBuffer );
|
2010-01-28 06:56:00 -06:00
|
|
|
|
|
|
|
/* Analyze parent if not only a trailing backslash was cutted but a real file spec */
|
|
|
|
if ( !bSkipThis )
|
|
|
|
{
|
|
|
|
if ( bCheckExistence )
|
|
|
|
{
|
2010-03-24 05:21:47 -05:00
|
|
|
::osl::LongPathBuffer< WCHAR > aShortPath( MAX_LONG_PATH );
|
2010-01-29 09:56:48 -06:00
|
|
|
_tcscpy( aShortPath, lpszPath );
|
|
|
|
_tcscat( aShortPath, szFile );
|
|
|
|
|
2010-01-28 06:56:00 -06:00
|
|
|
WIN32_FIND_DATA aFindFileData;
|
2010-01-29 09:56:48 -06:00
|
|
|
HANDLE hFind = FindFirstFile( aShortPath, &aFindFileData );
|
2010-01-28 06:56:00 -06:00
|
|
|
|
|
|
|
if ( IsValidHandle(hFind) )
|
|
|
|
{
|
2010-01-29 09:56:48 -06:00
|
|
|
_tcscat( lpszPath, aFindFileData.cFileName[0] ? aFindFileData.cFileName : aFindFileData.cAlternateFileName );
|
2010-01-28 06:56:00 -06:00
|
|
|
|
|
|
|
FindClose( hFind );
|
|
|
|
}
|
|
|
|
else
|
2010-01-29 09:56:48 -06:00
|
|
|
lpszPath[0] = 0;
|
2010-01-28 06:56:00 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* add the segment name back */
|
2010-01-29 09:56:48 -06:00
|
|
|
_tcscat( lpszPath, szFile );
|
2010-01-28 06:56:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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 )
|
2010-01-29 09:56:48 -06:00
|
|
|
lpszPath[0] = 0;
|
|
|
|
else
|
|
|
|
_tcsupr( lpszPath );
|
2010-01-28 06:56:00 -06:00
|
|
|
}
|
|
|
|
|
2010-01-29 09:56:48 -06:00
|
|
|
return _tcslen( lpszPath );
|
2010-01-28 06:56:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//#####################################################
|
|
|
|
#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;
|
|
|
|
}
|
|
|
|
}
|
2010-01-29 09:56:48 -06:00
|
|
|
else if ( lpszShortPath )
|
2010-01-28 06:56:00 -06:00
|
|
|
{
|
2010-01-29 09:56:48 -06:00
|
|
|
if ( _tcslen( lpszShortPath ) <= cchBuffer )
|
|
|
|
{
|
|
|
|
_tcscpy( lpszLongPath, lpszShortPath );
|
|
|
|
return GetCaseCorrectPathNameEx( lpszLongPath, cchBuffer, 0, bCheckExistence );
|
|
|
|
}
|
2010-01-28 06:56:00 -06:00
|
|
|
}
|
2010-01-29 09:56:48 -06:00
|
|
|
|
|
|
|
return 0;
|
2010-01-28 06:56:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-09 04:38:41 -05:00
|
|
|
//#############################################
|
|
|
|
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
|
2010-01-26 10:42:23 -06:00
|
|
|
{
|
|
|
|
/* 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
|
|
|
|
{
|
2010-02-02 09:56:25 -06:00
|
|
|
::osl::LongPathBuffer< sal_Unicode > aBuf( MAX_LONG_PATH );
|
2010-03-24 05:21:47 -05:00
|
|
|
sal_uInt32 nNewLen = GetCaseCorrectPathName( reinterpret_cast<LPCTSTR>(pDecodedURL + nSkip),
|
|
|
|
::osl::mingw_reinterpret_cast<LPTSTR>(aBuf),
|
2010-02-02 09:56:25 -06:00
|
|
|
aBuf.getBufSizeInSymbols(),
|
|
|
|
sal_False );
|
|
|
|
|
|
|
|
if ( nNewLen <= MAX_PATH - 12
|
2010-03-24 05:21:47 -05:00
|
|
|
|| 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 ) )
|
2010-01-26 10:42:23 -06:00
|
|
|
{
|
2010-02-02 09:56:25 -06:00
|
|
|
rtl_uString_newFromStr_WithLength( &strTempPath, aBuf, nNewLen );
|
2010-01-26 10:42:23 -06:00
|
|
|
}
|
|
|
|
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;
|
2010-03-24 05:21:47 -05:00
|
|
|
rtl_uString_newFromStr_WithLength( &strPrefix, reinterpret_cast<const sal_Unicode*>(WSTR_LONG_PATH_PREFIX_UNC), ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX_UNC ) - 1 );
|
2010-02-02 09:56:25 -06:00
|
|
|
rtl_uString_newFromStr_WithLength( &strSuffix, aBuf + 2, nNewLen - 2 );
|
2010-01-26 10:42:23 -06:00
|
|
|
|
|
|
|
rtl_uString_newConcat( &strTempPath, strPrefix, strSuffix );
|
|
|
|
|
|
|
|
rtl_uString_release( strPrefix );
|
|
|
|
rtl_uString_release( strSuffix );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rtl_uString *strSuffix = NULL;
|
|
|
|
rtl_uString *strPrefix = NULL;
|
2010-03-24 05:21:47 -05:00
|
|
|
rtl_uString_newFromStr_WithLength( &strPrefix, reinterpret_cast<const sal_Unicode*>(WSTR_LONG_PATH_PREFIX), ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX ) - 1 );
|
2010-02-02 09:56:25 -06:00
|
|
|
rtl_uString_newFromStr_WithLength( &strSuffix, aBuf, nNewLen );
|
2010-01-26 10:42:23 -06:00
|
|
|
|
|
|
|
rtl_uString_newConcat( &strTempPath, strPrefix, strSuffix );
|
|
|
|
|
|
|
|
rtl_uString_release( strPrefix );
|
|
|
|
rtl_uString_release( strSuffix );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 04:38:41 -05:00
|
|
|
|
|
|
|
if ( IsValidFilePath( strTempPath, NULL, VALIDATEPATH_ALLOW_ELLIPSE, &strTempPath ) )
|
|
|
|
nError = osl_File_E_None;
|
|
|
|
}
|
|
|
|
else if ( bAllowRelative ) /* This maybe a relative file URL */
|
|
|
|
{
|
2010-01-26 10:42:23 -06:00
|
|
|
/* In future the relative path could be converted to absolute if it is too long */
|
2009-09-09 04:38:41 -05:00
|
|
|
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;
|
|
|
|
|
2010-01-26 10:42:23 -06:00
|
|
|
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:
|
2010-01-27 03:26:25 -06:00
|
|
|
nIgnore = ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX_UNC ) - 1;
|
2010-01-26 10:42:23 -06:00
|
|
|
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:
|
2010-01-27 03:26:25 -06:00
|
|
|
nIgnore = ELEMENTS_OF_ARRAY( WSTR_LONG_PATH_PREFIX ) - 1;
|
2010-01-26 10:42:23 -06:00
|
|
|
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, '\\', '/' );
|
|
|
|
}
|
2009-09-09 04:38:41 -05:00
|
|
|
|
|
|
|
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 )
|
|
|
|
{
|
2010-01-29 09:56:48 -06:00
|
|
|
::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
|
|
|
|
::osl::LongPathBuffer< sal_Unicode > aCurrentDir( MAX_LONG_PATH );
|
2009-09-09 04:38:41 -05:00
|
|
|
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 );
|
|
|
|
|
2010-03-24 05:21:47 -05:00
|
|
|
GetCurrentDirectoryW( aCurrentDir.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aCurrentDir) );
|
|
|
|
SetCurrentDirectoryW( reinterpret_cast<LPCWSTR>(ustrBaseSysPath->buffer) );
|
2009-09-09 04:38:41 -05:00
|
|
|
}
|
|
|
|
|
2010-03-24 05:21:47 -05:00
|
|
|
dwResult = GetFullPathNameW( reinterpret_cast<LPCWSTR>(ustrRelSysPath->buffer), aBuffer.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), &lpFilePart );
|
2009-09-09 04:38:41 -05:00
|
|
|
|
|
|
|
if ( ustrBaseSysPath )
|
|
|
|
{
|
2010-03-24 05:21:47 -05:00
|
|
|
SetCurrentDirectoryW( ::osl::mingw_reinterpret_cast<LPCWSTR>(aCurrentDir) );
|
2009-09-09 04:38:41 -05:00
|
|
|
|
|
|
|
osl_releaseMutex( g_CurrentDirectoryMutex );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( dwResult )
|
|
|
|
{
|
2010-01-29 09:56:48 -06:00
|
|
|
if ( dwResult >= aBuffer.getBufSizeInSymbols() )
|
2009-09-09 04:38:41 -05:00
|
|
|
eError = osl_File_E_INVAL;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rtl_uString *ustrAbsSysPath = NULL;
|
|
|
|
|
2010-01-29 09:56:48 -06:00
|
|
|
rtl_uString_newFromStr( &ustrAbsSysPath, aBuffer );
|
2009-09-09 04:38:41 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|