1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: file_url.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
33 #define _WIN32_WINNT_0x0500
34 #include "systools/win32/uwinapi.h"
37 #include "file_error.h"
39 #include "rtl/alloc.h"
40 #include "osl/diagnose.h"
42 #include "osl/mutex.h"
47 #if OSL_DEBUG_LEVEL > 0
48 #define OSL_ENSURE_FILE( cond, msg, file ) ( (cond) ? (void)0 : _osl_warnFile( msg, file ) )
50 #define OSL_ENSURE_FILE( cond, msg, file ) ((void)0)
53 #define ELEMENTS_OF_ARRAY(arr) (sizeof(arr)/(sizeof((arr)[0])))
55 //##################################################################
57 //##################################################################
59 extern "C" oslMutex g_CurrentDirectoryMutex
; /* Initialized in dllentry.c */
60 oslMutex g_CurrentDirectoryMutex
= 0;
62 //#####################################################
63 static BOOL
IsValidFilePathComponent(
64 LPCTSTR lpComponent
, LPCTSTR
*lppComponentEnd
, DWORD dwFlags
)
66 LPCTSTR lpComponentEnd
= NULL
;
67 LPCTSTR lpCurrent
= lpComponent
;
68 BOOL fValid
= TRUE
; /* Assume success */
71 /* Path component length must not exceed MAX_PATH */
73 while ( !lpComponentEnd
&& lpCurrent
&& lpCurrent
- lpComponent
< MAX_PATH
)
77 /* Both backslash and slash determine the end of a path component */
83 /* Component must not end with '.' or blank and can't be empty */
86 if ( dwFlags
& VALIDATEPATH_ALLOW_ELLIPSE
)
88 if ( (dwFlags
& VALIDATEPATH_ALLOW_INVALID_SPACE_AND_PERIOD
) ||
89 1 == lpCurrent
- lpComponent
)
91 /* Either do allow periods anywhere, or current directory */
92 lpComponentEnd
= lpCurrent
;
95 else if ( 2 == lpCurrent
- lpComponent
&& '.' == *lpComponent
)
97 /* Parent directory is O.K. */
98 lpComponentEnd
= lpCurrent
;
104 if ( dwFlags
& VALIDATEPATH_ALLOW_INVALID_SPACE_AND_PERIOD
)
105 lpComponentEnd
= lpCurrent
;
108 lpComponentEnd
= lpCurrent
- 1;
113 lpComponentEnd
= lpCurrent
;
117 /* '?' and '*' are valid wildcards but not valid file name characters */
120 if ( dwFlags
& VALIDATEPATH_ALLOW_WILDCARDS
)
122 /* The following characters are reserved */
128 lpComponentEnd
= lpCurrent
;
132 /* Characters below ASCII 32 are not allowed */
133 if ( *lpCurrent
< ' ' )
135 lpComponentEnd
= lpCurrent
;
140 cLast
= *lpCurrent
++;
143 /* If we don't reached the end of the component the length of the component was to long
144 ( See condition of while loop ) */
145 if ( !lpComponentEnd
)
148 lpComponentEnd
= lpCurrent
;
151 /* Test wether the component specifies a device name what is not allowed */
154 // This is very expensive. A lot of calls to _tcsicmp.
155 // in SRC6870m71 67.000 calls of this method while empty office start result into more than 1.500.00 calls of _tcsicmp!
156 // Possible optimizations
157 // - Array should be const static
158 // - Sorted array, use binary search
159 // - More intelligent check for com1-9, lpt1-9
160 // Maybe make szComponent upper case, don't search case intensitive
161 // 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.
165 LPCTSTR alpDeviceNames[] =
192 TCHAR szComponent[MAX_PATH];
193 int nComponentLength;
197 // A device name with an extension is also invalid
198 lpDot = _tcschr( lpComponent, '.' );
200 if ( !lpDot || lpDot > lpComponentEnd )
201 nComponentLength = lpComponentEnd - lpComponent;
203 nComponentLength = lpDot - lpComponent;
205 _tcsncpy( szComponent, lpComponent, nComponentLength );
206 szComponent[nComponentLength] = 0;
208 for ( i = 0; i < sizeof( alpDeviceNames ) / sizeof(LPCTSTR); i++ )
210 if ( 0 == _tcsicmp( szComponent, alpDeviceNames[i] ) )
212 lpComponentEnd = lpComponent;
222 // Empty components are not allowed
223 if ( lpComponentEnd
- lpComponent
< 1 )
226 // If we reached the end of the string NULL is returned
227 else if ( !*lpComponentEnd
)
228 lpComponentEnd
= NULL
;
232 if ( lppComponentEnd
)
233 *lppComponentEnd
= lpComponentEnd
;
238 //#####################################################
239 #define CHARSET_SEPARATOR TEXT("\\/")
241 DWORD
IsValidFilePath(rtl_uString
*path
, LPCTSTR
*lppError
, DWORD dwFlags
, rtl_uString
**corrected
)
243 LPCTSTR lpszPath
= reinterpret_cast< LPCTSTR
>(path
->buffer
);
246 DWORD dwPathType
= PATHTYPE_ERROR
;
248 if ( dwFlags
& VALIDATEPATH_ALLOW_RELATIVE
)
249 dwFlags
|= VALIDATEPATH_ALLOW_ELLIPSE
;
254 lpComponent
= lpszPath
;
257 /* Test for UNC path notation */
258 if ( 2 == _tcsspn( lpszPath
, CHARSET_SEPARATOR
) )
260 /* Place the pointer behind the leading to backslashes */
262 lpComponent
= lpszPath
+ 2;
264 fValid
= IsValidFilePathComponent( lpComponent
, &lpComponent
, VALIDATEPATH_ALLOW_ELLIPSE
);
266 /* So far we have a valid servername. Now let's see if we also have a network resource */
268 dwPathType
= PATHTYPE_ABSOLUTE_UNC
;
272 if ( lpComponent
&& !*++lpComponent
)
278 /* We only have a Server specification what is invalid */
280 lpComponent
= lpszPath
;
283 dwPathType
|= PATHTYPE_IS_SERVER
;
288 /* Now test the network resource */
290 fValid
= IsValidFilePathComponent( lpComponent
, &lpComponent
, 0 );
292 /* If we now reached the end of the path, everything is O.K. */
295 if ( fValid
&& (!lpComponent
|| lpComponent
&& !*++lpComponent
) )
298 dwPathType
|= PATHTYPE_IS_VOLUME
;
304 /* Local path verification. Must start with <drive>: */
305 else if ( _istalpha( lpszPath
[0] ) && ':' == lpszPath
[1] )
307 /* Place pointer behind correct drive specification */
309 lpComponent
= lpszPath
+ 2;
311 if ( 1 == _tcsspn( lpComponent
, CHARSET_SEPARATOR
) )
313 else if ( *lpComponent
)
316 dwPathType
= PATHTYPE_ABSOLUTE_LOCAL
;
318 /* Now we are behind the backslash or it was a simple drive without backslash */
320 if ( fValid
&& !*lpComponent
)
323 dwPathType
|= PATHTYPE_IS_VOLUME
;
327 /* Can be a relative path */
328 else if ( dwFlags
& VALIDATEPATH_ALLOW_RELATIVE
)
330 lpComponent
= lpszPath
;
332 /* Relative path can start with a backslash */
334 if ( 1 == _tcsspn( lpComponent
, CHARSET_SEPARATOR
) )
341 dwPathType
= PATHTYPE_RELATIVE
;
344 /* Anything else is an error */
348 lpComponent
= lpszPath
;
351 /* Now validate each component of the path */
352 while ( fValid
&& lpComponent
)
354 // Correct path by merging consecutive slashes:
355 if (*lpComponent
== '\\' && corrected
!= NULL
) {
356 sal_Int32 i
= lpComponent
- lpszPath
;
357 rtl_uString_newReplaceStrAt(corrected
, path
, i
, 1, NULL
);
358 //TODO: handle out-of-memory
359 lpszPath
= reinterpret_cast< LPCTSTR
>((*corrected
)->buffer
);
360 lpComponent
= lpszPath
+ i
;
363 fValid
= IsValidFilePathComponent( lpComponent
, &lpComponent
, dwFlags
| VALIDATEPATH_ALLOW_INVALID_SPACE_AND_PERIOD
);
365 if ( fValid
&& lpComponent
)
369 /* If the string behind the backslash is empty, we've done */
376 if ( fValid
&& _tcslen( lpszPath
) >= MAX_PATH
)
379 lpComponent
= lpszPath
+ MAX_PATH
;
383 *lppError
= lpComponent
;
385 return fValid
? dwPathType
: PATHTYPE_ERROR
;
388 //#############################################
389 //#####################################################
390 //Undocumented in SHELL32.DLL ordinal 35
391 static BOOL
PathRemoveFileSpec(LPTSTR lpPath
)
393 BOOL fSuccess
= FALSE
; // Assume failure
394 LPTSTR lpLastBkSlash
= _tcsrchr( lpPath
, '\\' );
395 LPTSTR lpLastSlash
= _tcsrchr( lpPath
, '/' );
396 LPTSTR lpLastDelimiter
= lpLastSlash
> lpLastBkSlash
? lpLastSlash
: lpLastBkSlash
;
398 if ( lpLastDelimiter
)
400 if ( 0 == *(lpLastDelimiter
+ 1) )
402 if ( lpLastDelimiter
> lpPath
&& *(lpLastDelimiter
- 1) != ':' )
404 *lpLastDelimiter
= 0;
410 *(++lpLastDelimiter
) = 0;
417 //#####################################################
418 // Undocumented in SHELL32.DLL ordinal 32
419 static LPTSTR
PathAddBackslash(LPTSTR lpPath
)
421 LPTSTR lpEndPath
= NULL
;
425 int nLen
= _tcslen(lpPath
);
427 if ( !nLen
|| lpPath
[nLen
-1] != '\\' && lpPath
[nLen
-1] != '/' && nLen
< MAX_PATH
- 1 )
429 lpEndPath
= lpPath
+ nLen
;
437 //#####################################################
438 // Same as GetLongPathName but also 95/NT4
439 static DWORD
GetCaseCorrectPathNameEx(
440 LPCTSTR lpszShortPath
, // file name
441 LPTSTR lpszLongPath
, // path buffer
442 DWORD cchBuffer
, // size of path buffer
446 TCHAR szPath
[MAX_PATH
];
449 cchBuffer
= cchBuffer
; /* avoid warnings */
451 _tcscpy( szPath
, lpszShortPath
);
453 fSuccess
= PathRemoveFileSpec( szPath
);
457 int nLen
= _tcslen( szPath
);
458 LPCTSTR lpszFileSpec
= lpszShortPath
+ nLen
;
461 if ( 0 == _tcscmp( lpszFileSpec
, TEXT("..") ) )
467 0 == _tcscmp( lpszFileSpec
, TEXT(".") ) ||
468 0 == _tcscmp( lpszFileSpec
, TEXT("\\") ) ||
469 0 == _tcscmp( lpszFileSpec
, TEXT("/") )
474 else if ( nSkipLevels
)
482 GetCaseCorrectPathNameEx( szPath
, szPath
, MAX_PATH
, nSkipLevels
);
484 PathAddBackslash( szPath
);
486 /* Analyze parent if not only a trailing backslash was cutted but a real file spec */
489 WIN32_FIND_DATA aFindFileData
;
490 HANDLE hFind
= FindFirstFile( lpszShortPath
, &aFindFileData
);
492 if ( IsValidHandle(hFind
) )
494 _tcscat( szPath
, aFindFileData
.cFileName
[0] ? aFindFileData
.cFileName
: aFindFileData
.cAlternateFileName
);
504 /* File specification can't be removed therefore the short path is either a drive
505 or a network share. If still levels to skip are left, the path specification
506 tries to travel below the file system root */
513 _tcscpy( lpszLongPath
, szPath
);
515 return _tcslen( lpszLongPath
);
518 //#####################################################
519 #define WSTR_SYSTEM_ROOT_PATH L"\\\\.\\"
521 DWORD
GetCaseCorrectPathName(
522 LPCTSTR lpszShortPath
, // file name
523 LPTSTR lpszLongPath
, // path buffer
524 DWORD cchBuffer
// size of path buffer
527 /* Special handling for "\\.\" as system root */
528 if ( lpszShortPath
&& 0 == wcscmp( lpszShortPath
, WSTR_SYSTEM_ROOT_PATH
) )
530 if ( cchBuffer
>= ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH
) )
532 wcscpy( lpszLongPath
, WSTR_SYSTEM_ROOT_PATH
);
533 return ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH
) - 1;
537 return ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH
) - 1;
542 return GetCaseCorrectPathNameEx( lpszShortPath
, lpszLongPath
, cchBuffer
, 0 );
546 //#############################################
547 static sal_Bool
_osl_decodeURL( rtl_String
* strUTF8
, rtl_uString
** pstrDecodedURL
)
550 const sal_Char
*pSrcEnd
;
551 const sal_Char
*pSrc
;
554 sal_Bool bValidEncoded
= sal_True
; /* Assume success */
556 /* The resulting decoded string length is shorter or equal to the source length */
558 nSrcLen
= rtl_string_getLength(strUTF8
);
559 pBuffer
= reinterpret_cast<sal_Char
*>(rtl_allocateMemory(nSrcLen
+ 1));
562 pSrc
= rtl_string_getStr(strUTF8
);
563 pSrcEnd
= pSrc
+ nSrcLen
;
565 /* Now decode the URL what should result in an UTF8 string */
566 while ( bValidEncoded
&& pSrc
< pSrcEnd
)
580 aChar
= (sal_Char
)strtoul( aToken
, NULL
, 16 );
582 /* The chars are path delimiters and must not be encoded */
584 if ( 0 == aChar
|| '\\' == aChar
|| '/' == aChar
|| ':' == aChar
)
585 bValidEncoded
= sal_False
;
600 rtl_string2UString( pstrDecodedURL
, pBuffer
, rtl_str_getLength(pBuffer
), RTL_TEXTENCODING_UTF8
, OUSTRING_TO_OSTRING_CVTFLAGS
);
601 OSL_ASSERT(*pstrDecodedURL
!= 0);
604 rtl_freeMemory( pBuffer
);
606 return bValidEncoded
;
609 //#############################################
610 static void _osl_encodeURL( rtl_uString
*strURL
, rtl_String
**pstrEncodedURL
)
612 /* Encode non ascii characters within the URL */
614 rtl_String
*strUTF8
= NULL
;
615 sal_Char
*pszEncodedURL
;
616 const sal_Char
*pURLScan
;
618 sal_Int32 nURLScanLen
;
619 sal_Int32 nURLScanCount
;
621 rtl_uString2String( &strUTF8
, rtl_uString_getStr( strURL
), rtl_uString_getLength( strURL
), RTL_TEXTENCODING_UTF8
, OUSTRING_TO_OSTRING_CVTFLAGS
);
623 pszEncodedURL
= (sal_Char
*) rtl_allocateMemory( (rtl_string_getLength( strUTF8
) * 3 + 1) * sizeof(sal_Char
) );
625 pURLDest
= pszEncodedURL
;
626 pURLScan
= rtl_string_getStr( strUTF8
);
627 nURLScanLen
= rtl_string_getLength( strUTF8
);
630 while ( nURLScanCount
< nURLScanLen
)
632 sal_Char cCurrent
= *pURLScan
;
636 if (!( ( cCurrent
>= 'a' && cCurrent
<= 'z' ) || ( cCurrent
>= 'A' && cCurrent
<= 'Z' ) || ( cCurrent
>= '0' && cCurrent
<= '9' ) ) )
638 sprintf( pURLDest
, "%%%02X", (unsigned char)cCurrent
);
661 *pURLDest
++ = cCurrent
;
673 rtl_string_release( strUTF8
);
674 rtl_string_newFromStr( pstrEncodedURL
, pszEncodedURL
);
675 rtl_freeMemory( pszEncodedURL
);
678 //#############################################
679 #define WSTR_SYSTEM_ROOT_PATH L"\\\\.\\"
681 oslFileError
_osl_getSystemPathFromFileURL( rtl_uString
*strURL
, rtl_uString
**pustrPath
, sal_Bool bAllowRelative
)
683 rtl_String
*strUTF8
= NULL
;
684 rtl_uString
*strDecodedURL
= NULL
;
685 rtl_uString
*strTempPath
= NULL
;
686 const sal_Unicode
*pDecodedURL
;
687 sal_uInt32 nDecodedLen
;
688 sal_Bool bValidEncoded
;
689 oslFileError nError
= osl_File_E_INVAL
; /* Assume failure */
691 /* If someone hasn't encoded the complete URL we convert it to UTF8 now to prevent from
692 having a mixed encoded URL later */
694 rtl_uString2String( &strUTF8
, rtl_uString_getStr( strURL
), rtl_uString_getLength( strURL
), RTL_TEXTENCODING_UTF8
, OUSTRING_TO_OSTRING_CVTFLAGS
);
696 /* If the length of strUTF8 and strURL differs it indicates that the URL was not correct encoded */
699 strUTF8
->length
== strURL
->length
||
700 0 != rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( strURL
->buffer
, strURL
->length
, "file:\\\\", 7 )
701 ,"osl_getSystemPathFromFileURL: \"%s\" is not encoded !!!", strURL
);
703 bValidEncoded
= _osl_decodeURL( strUTF8
, &strDecodedURL
);
705 /* Release the encoded UTF8 string */
706 rtl_string_release( strUTF8
);
710 /* Replace backslashes and pipes */
712 rtl_uString_newReplace( &strDecodedURL
, strDecodedURL
, '/', '\\' );
713 rtl_uString_newReplace( &strDecodedURL
, strDecodedURL
, '|', ':' );
715 pDecodedURL
= rtl_uString_getStr( strDecodedURL
);
716 nDecodedLen
= rtl_uString_getLength( strDecodedURL
);
718 /* Must start with "file://" */
719 if ( 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL
, nDecodedLen
, "file:\\\\", 7 ) )
723 if ( 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL
, nDecodedLen
, "file:\\\\\\", 8 ) )
726 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL
, nDecodedLen
, "file:\\\\localhost\\", 17 ) ||
727 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL
, nDecodedLen
, "file:\\\\127.0.0.1\\", 17 )
733 /* Indicates local root */
734 if ( nDecodedLen
== nSkip
)
735 rtl_uString_newFromStr_WithLength( &strTempPath
, reinterpret_cast<const sal_Unicode
*>(WSTR_SYSTEM_ROOT_PATH
), ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH
) - 1 );
737 rtl_uString_newFromStr_WithLength( &strTempPath
, pDecodedURL
+ nSkip
, nDecodedLen
- nSkip
);
739 if ( IsValidFilePath( strTempPath
, NULL
, VALIDATEPATH_ALLOW_ELLIPSE
, &strTempPath
) )
740 nError
= osl_File_E_None
;
742 else if ( bAllowRelative
) /* This maybe a relative file URL */
744 rtl_uString_assign( &strTempPath
, strDecodedURL
);
746 if ( IsValidFilePath( strTempPath
, NULL
, VALIDATEPATH_ALLOW_RELATIVE
| VALIDATEPATH_ALLOW_ELLIPSE
, &strTempPath
) )
747 nError
= osl_File_E_None
;
751 OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not an absolute FileURL !!!", strURL );
757 rtl_uString_release( strDecodedURL
);
759 if ( osl_File_E_None
== nError
)
760 rtl_uString_assign( pustrPath
, strTempPath
);
763 rtl_uString_release( strTempPath
);
766 OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not a FileURL !!!", strURL );
772 //#############################################
773 oslFileError
_osl_getFileURLFromSystemPath( rtl_uString
* strPath
, rtl_uString
** pstrURL
)
775 oslFileError nError
= osl_File_E_INVAL
; /* Assume failure */
776 rtl_uString
*strTempURL
= NULL
;
777 DWORD dwPathType
= PATHTYPE_ERROR
;
780 dwPathType
= IsValidFilePath(strPath
, NULL
, VALIDATEPATH_ALLOW_RELATIVE
, NULL
);
784 rtl_uString
*strTempPath
= NULL
;
786 /* Replace backslashes */
787 rtl_uString_newReplace( &strTempPath
, strPath
, '\\', '/' );
789 switch ( dwPathType
& PATHTYPE_MASK_TYPE
)
791 case PATHTYPE_RELATIVE
:
792 rtl_uString_assign( &strTempURL
, strTempPath
);
793 nError
= osl_File_E_None
;
795 case PATHTYPE_ABSOLUTE_UNC
:
796 rtl_uString_newFromAscii( &strTempURL
, "file:" );
797 rtl_uString_newConcat( &strTempURL
, strTempURL
, strTempPath
);
798 nError
= osl_File_E_None
;
800 case PATHTYPE_ABSOLUTE_LOCAL
:
801 rtl_uString_newFromAscii( &strTempURL
, "file:///" );
802 rtl_uString_newConcat( &strTempURL
, strTempURL
, strTempPath
);
803 nError
= osl_File_E_None
;
809 /* Release temp path */
810 rtl_uString_release( strTempPath
);
813 if ( osl_File_E_None
== nError
)
815 rtl_String
*strEncodedURL
= NULL
;
818 _osl_encodeURL( strTempURL
, &strEncodedURL
);
820 /* Provide URL via unicode string */
821 rtl_string2UString( pstrURL
, rtl_string_getStr(strEncodedURL
), rtl_string_getLength(strEncodedURL
), RTL_TEXTENCODING_ASCII_US
, OUSTRING_TO_OSTRING_CVTFLAGS
);
822 OSL_ASSERT(*pstrURL
!= 0);
823 rtl_string_release( strEncodedURL
);
826 /* Release temp URL */
828 rtl_uString_release( strTempURL
);
831 OSL_ENSURE_FILE( !nError, "osl_getFileURLFromSystemPath: \"%s\" is not a systemPath !!!", strPath );
836 //#####################################################
837 oslFileError SAL_CALL
osl_getFileURLFromSystemPath(
838 rtl_uString
* ustrPath
, rtl_uString
** pustrURL
)
840 return _osl_getFileURLFromSystemPath( ustrPath
, pustrURL
);
843 //#####################################################
844 oslFileError SAL_CALL
osl_getSystemPathFromFileURL(
845 rtl_uString
*ustrURL
, rtl_uString
**pustrPath
)
847 return _osl_getSystemPathFromFileURL( ustrURL
, pustrPath
, sal_True
);
850 //#####################################################
851 oslFileError SAL_CALL
osl_searchFileURL(
852 rtl_uString
*ustrFileName
,
853 rtl_uString
*ustrSystemSearchPath
,
854 rtl_uString
**pustrPath
)
856 rtl_uString
*ustrUNCPath
= NULL
;
857 rtl_uString
*ustrSysPath
= NULL
;
860 /* First try to interpret the file name as an URL even a relative one */
861 error
= _osl_getSystemPathFromFileURL( ustrFileName
, &ustrUNCPath
, sal_True
);
863 /* So far we either have an UNC path or something invalid
864 Now create a system path */
865 if ( osl_File_E_None
== error
)
866 error
= _osl_getSystemPathFromFileURL( ustrUNCPath
, &ustrSysPath
, sal_True
);
868 if ( osl_File_E_None
== error
)
872 LPTSTR lpBuffer
= NULL
;
875 /* Repeat calling SearchPath ...
876 Start with MAX_PATH for the buffer. In most cases this
877 will be enough and does not force the loop to runtwice */
882 /* If search path is empty use a NULL pointer instead according to MSDN documentation of SearchPath */
883 LPCTSTR lpszSearchPath
= ustrSystemSearchPath
&& ustrSystemSearchPath
->length
? reinterpret_cast<LPCTSTR
>(ustrSystemSearchPath
->buffer
) : NULL
;
884 LPCTSTR lpszSearchFile
= reinterpret_cast<LPCTSTR
>(ustrSysPath
->buffer
);
886 /* Allocate space for buffer according to previous returned count of required chars */
887 /* +1 is not neccessary if we follow MSDN documentation but for robustness we do so */
888 nBufferLength
= dwResult
+ 1;
889 lpBuffer
= lpBuffer
?
890 reinterpret_cast<LPTSTR
>(rtl_reallocateMemory(lpBuffer
, nBufferLength
* sizeof(TCHAR
))) :
891 reinterpret_cast<LPTSTR
>(rtl_allocateMemory(nBufferLength
* sizeof(TCHAR
)));
893 dwResult
= SearchPath( lpszSearchPath
, lpszSearchFile
, NULL
, nBufferLength
, lpBuffer
, &lpszFilePart
);
894 } while ( dwResult
&& dwResult
>= nBufferLength
);
896 /* ... until an error occures or buffer is large enough.
897 dwResult == nBufferLength can not happen according to documentation but lets be robust ;-) */
901 rtl_uString_newFromStr( &ustrSysPath
, reinterpret_cast<const sal_Unicode
*>(lpBuffer
) );
902 error
= osl_getFileURLFromSystemPath( ustrSysPath
, pustrPath
);
906 WIN32_FIND_DATA aFindFileData
;
909 /* Somthing went wrong, perhaps the path was absolute */
910 error
= oslTranslateFileError( GetLastError() );
912 hFind
= FindFirstFile( reinterpret_cast<LPCTSTR
>(ustrSysPath
->buffer
), &aFindFileData
);
914 if ( IsValidHandle(hFind
) )
916 error
= osl_getFileURLFromSystemPath( ustrSysPath
, pustrPath
);
921 rtl_freeMemory( lpBuffer
);
925 rtl_uString_release( ustrSysPath
);
928 rtl_uString_release( ustrUNCPath
);
933 //#####################################################
935 oslFileError SAL_CALL
osl_getAbsoluteFileURL( rtl_uString
* ustrBaseURL
, rtl_uString
* ustrRelativeURL
, rtl_uString
** pustrAbsoluteURL
)
938 rtl_uString
*ustrRelSysPath
= NULL
;
939 rtl_uString
*ustrBaseSysPath
= NULL
;
941 if ( ustrBaseURL
&& ustrBaseURL
->length
)
943 eError
= _osl_getSystemPathFromFileURL( ustrBaseURL
, &ustrBaseSysPath
, sal_False
);
944 OSL_ENSURE( osl_File_E_None
== eError
, "osl_getAbsoluteFileURL called with relative or invalid base URL" );
946 eError
= _osl_getSystemPathFromFileURL( ustrRelativeURL
, &ustrRelSysPath
, sal_True
);
950 eError
= _osl_getSystemPathFromFileURL( ustrRelativeURL
, &ustrRelSysPath
, sal_False
);
951 OSL_ENSURE( osl_File_E_None
== eError
, "osl_getAbsoluteFileURL called with empty base URL and/or invalid relative URL" );
956 TCHAR szBuffer
[MAX_PATH
];
957 TCHAR szCurrentDir
[MAX_PATH
];
958 LPTSTR lpFilePart
= NULL
;
962 Bad, bad hack, this only works if the base path
963 really exists which is not necessary according
965 The whole FileURL implementation should be merged
966 with the rtl/uri class.
968 if ( ustrBaseSysPath
)
970 osl_acquireMutex( g_CurrentDirectoryMutex
);
972 GetCurrentDirectory( MAX_PATH
, szCurrentDir
);
973 SetCurrentDirectory( reinterpret_cast<LPCTSTR
>(ustrBaseSysPath
->buffer
) );
976 dwResult
= GetFullPathName( reinterpret_cast<LPCTSTR
>(ustrRelSysPath
->buffer
), MAX_PATH
, szBuffer
, &lpFilePart
);
978 if ( ustrBaseSysPath
)
980 SetCurrentDirectory( szCurrentDir
);
982 osl_releaseMutex( g_CurrentDirectoryMutex
);
987 if ( dwResult
>= MAX_PATH
)
988 eError
= osl_File_E_INVAL
;
991 rtl_uString
*ustrAbsSysPath
= NULL
;
993 rtl_uString_newFromStr( &ustrAbsSysPath
, reinterpret_cast<const sal_Unicode
*>(szBuffer
) );
995 eError
= osl_getFileURLFromSystemPath( ustrAbsSysPath
, pustrAbsoluteURL
);
997 if ( ustrAbsSysPath
)
998 rtl_uString_release( ustrAbsSysPath
);
1002 eError
= oslTranslateFileError( GetLastError() );
1005 if ( ustrBaseSysPath
)
1006 rtl_uString_release( ustrBaseSysPath
);
1008 if ( ustrRelSysPath
)
1009 rtl_uString_release( ustrRelSysPath
);
1014 //#####################################################
1015 oslFileError SAL_CALL
osl_getCanonicalName( rtl_uString
*strRequested
, rtl_uString
**strValid
)
1017 rtl_uString_newFromString(strValid
, strRequested
);
1018 return osl_File_E_None
;