merge the formfield patch from ooo-build
[ooovba.git] / sal / osl / w32 / file_url.cxx
blobfe916de838ceab906495b45d8d44436dc1fa9786
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: file_url.cxx,v $
10 * $Revision: 1.0 $
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 ************************************************************************/
31 #define UNICODE
32 #define _UNICODE
33 #define _WIN32_WINNT_0x0500
34 #include "systools/win32/uwinapi.h"
36 #include "file_url.h"
37 #include "file_error.h"
39 #include "rtl/alloc.h"
40 #include "osl/diagnose.h"
41 #include "osl/file.h"
42 #include "osl/mutex.h"
44 #include <stdio.h>
45 #include <tchar.h>
47 #if OSL_DEBUG_LEVEL > 0
48 #define OSL_ENSURE_FILE( cond, msg, file ) ( (cond) ? (void)0 : _osl_warnFile( msg, file ) )
49 #else
50 #define OSL_ENSURE_FILE( cond, msg, file ) ((void)0)
51 #endif
53 #define ELEMENTS_OF_ARRAY(arr) (sizeof(arr)/(sizeof((arr)[0])))
55 //##################################################################
56 // FileURL functions
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 */
69 TCHAR cLast = 0;
71 /* Path component length must not exceed MAX_PATH */
73 while ( !lpComponentEnd && lpCurrent && lpCurrent - lpComponent < MAX_PATH )
75 switch ( *lpCurrent )
77 /* Both backslash and slash determine the end of a path component */
78 case '\0':
79 case '/':
80 case '\\':
81 switch ( cLast )
83 /* Component must not end with '.' or blank and can't be empty */
85 case '.':
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;
93 break;
95 else if ( 2 == lpCurrent - lpComponent && '.' == *lpComponent )
97 /* Parent directory is O.K. */
98 lpComponentEnd = lpCurrent;
99 break;
102 case 0:
103 case ' ':
104 if ( dwFlags & VALIDATEPATH_ALLOW_INVALID_SPACE_AND_PERIOD )
105 lpComponentEnd = lpCurrent;
106 else
108 lpComponentEnd = lpCurrent - 1;
109 fValid = FALSE;
111 break;
112 default:
113 lpComponentEnd = lpCurrent;
114 break;
116 break;
117 /* '?' and '*' are valid wildcards but not valid file name characters */
118 case '?':
119 case '*':
120 if ( dwFlags & VALIDATEPATH_ALLOW_WILDCARDS )
121 break;
122 /* The following characters are reserved */
123 case '<':
124 case '>':
125 case '\"':
126 case '|':
127 case ':':
128 lpComponentEnd = lpCurrent;
129 fValid = FALSE;
130 break;
131 default:
132 /* Characters below ASCII 32 are not allowed */
133 if ( *lpCurrent < ' ' )
135 lpComponentEnd = lpCurrent;
136 fValid = FALSE;
138 break;
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 )
147 fValid = FALSE;
148 lpComponentEnd = lpCurrent;
151 /* Test wether the component specifies a device name what is not allowed */
153 // MT: PERFORMANCE:
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.
163 if ( fValid )
165 LPCTSTR alpDeviceNames[] =
167 TEXT("CON"),
168 TEXT("PRN"),
169 TEXT("AUX"),
170 TEXT("CLOCK$"),
171 TEXT("NUL"),
172 TEXT("LPT1"),
173 TEXT("LPT2"),
174 TEXT("LPT3"),
175 TEXT("LPT4"),
176 TEXT("LPT5"),
177 TEXT("LPT6"),
178 TEXT("LPT7"),
179 TEXT("LPT8"),
180 TEXT("LPT9"),
181 TEXT("COM1"),
182 TEXT("COM2"),
183 TEXT("COM3"),
184 TEXT("COM4"),
185 TEXT("COM5"),
186 TEXT("COM6"),
187 TEXT("COM7"),
188 TEXT("COM8"),
189 TEXT("COM9")
192 TCHAR szComponent[MAX_PATH];
193 int nComponentLength;
194 LPCTSTR lpDot;
195 int i;
197 // A device name with an extension is also invalid
198 lpDot = _tcschr( lpComponent, '.' );
200 if ( !lpDot || lpDot > lpComponentEnd )
201 nComponentLength = lpComponentEnd - lpComponent;
202 else
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;
213 fValid = FALSE;
214 break;
220 if ( fValid )
222 // Empty components are not allowed
223 if ( lpComponentEnd - lpComponent < 1 )
224 fValid = FALSE;
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;
235 return fValid;
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);
244 LPCTSTR lpComponent;
245 BOOL fValid = TRUE;
246 DWORD dwPathType = PATHTYPE_ERROR;
248 if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
249 dwFlags |= VALIDATEPATH_ALLOW_ELLIPSE;
251 if ( !lpszPath )
253 fValid = FALSE;
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;
270 if ( fValid )
272 if ( lpComponent && !*++lpComponent )
273 lpComponent = NULL;
275 if ( !lpComponent )
277 #if 0
278 /* We only have a Server specification what is invalid */
280 lpComponent = lpszPath;
281 fValid = FALSE;
282 #else
283 dwPathType |= PATHTYPE_IS_SERVER;
284 #endif
286 else
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 ) )
297 lpComponent = NULL;
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 ) )
312 lpComponent++;
313 else if ( *lpComponent )
314 fValid = FALSE;
316 dwPathType = PATHTYPE_ABSOLUTE_LOCAL;
318 /* Now we are behind the backslash or it was a simple drive without backslash */
320 if ( fValid && !*lpComponent )
322 lpComponent = NULL;
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 ) )
336 lpComponent++;
337 if ( !*lpComponent )
338 lpComponent = NULL;
341 dwPathType = PATHTYPE_RELATIVE;
344 /* Anything else is an error */
345 else
347 fValid = FALSE;
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 )
367 lpComponent++;
369 /* If the string behind the backslash is empty, we've done */
371 if ( !*lpComponent )
372 lpComponent = NULL;
376 if ( fValid && _tcslen( lpszPath ) >= MAX_PATH )
378 fValid = FALSE;
379 lpComponent = lpszPath + MAX_PATH;
382 if ( lppError )
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;
405 fSuccess = TRUE;
408 else
410 *(++lpLastDelimiter) = 0;
411 fSuccess = TRUE;
414 return fSuccess;
417 //#####################################################
418 // Undocumented in SHELL32.DLL ordinal 32
419 static LPTSTR PathAddBackslash(LPTSTR lpPath)
421 LPTSTR lpEndPath = NULL;
423 if ( lpPath )
425 int nLen = _tcslen(lpPath);
427 if ( !nLen || lpPath[nLen-1] != '\\' && lpPath[nLen-1] != '/' && nLen < MAX_PATH - 1 )
429 lpEndPath = lpPath + nLen;
430 *lpEndPath++ = '\\';
431 *lpEndPath = 0;
434 return lpEndPath;
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
443 DWORD nSkipLevels
446 TCHAR szPath[MAX_PATH];
447 BOOL fSuccess;
449 cchBuffer = cchBuffer; /* avoid warnings */
451 _tcscpy( szPath, lpszShortPath );
453 fSuccess = PathRemoveFileSpec( szPath );
455 if ( fSuccess )
457 int nLen = _tcslen( szPath );
458 LPCTSTR lpszFileSpec = lpszShortPath + nLen;
459 BOOL bSkipThis;
461 if ( 0 == _tcscmp( lpszFileSpec, TEXT("..") ) )
463 bSkipThis = TRUE;
464 nSkipLevels += 1;
466 else if (
467 0 == _tcscmp( lpszFileSpec, TEXT(".") ) ||
468 0 == _tcscmp( lpszFileSpec, TEXT("\\") ) ||
469 0 == _tcscmp( lpszFileSpec, TEXT("/") )
472 bSkipThis = TRUE;
474 else if ( nSkipLevels )
476 bSkipThis = TRUE;
477 nSkipLevels--;
479 else
480 bSkipThis = FALSE;
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 */
487 if ( !bSkipThis )
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 );
496 FindClose( hFind );
498 else
499 return 0;
502 else
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 */
507 if ( nSkipLevels )
508 return 0;
510 _tcsupr( szPath );
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;
535 else
537 return ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1;
540 else
542 return GetCaseCorrectPathNameEx( lpszShortPath, lpszLongPath, cchBuffer, 0 );
546 //#############################################
547 static sal_Bool _osl_decodeURL( rtl_String* strUTF8, rtl_uString** pstrDecodedURL )
549 sal_Char *pBuffer;
550 const sal_Char *pSrcEnd;
551 const sal_Char *pSrc;
552 sal_Char *pDest;
553 sal_Int32 nSrcLen;
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));
561 pDest = pBuffer;
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 )
568 switch ( *pSrc )
570 case '%':
572 sal_Char aToken[3];
573 sal_Char aChar;
575 pSrc++;
576 aToken[0] = *pSrc++;
577 aToken[1] = *pSrc++;
578 aToken[2] = 0;
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;
586 else
587 *pDest++ = aChar;
589 break;
590 default:
591 *pDest++ = *pSrc++;
592 break;
596 *pDest++ = 0;
598 if ( bValidEncoded )
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;
617 sal_Char *pURLDest;
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 );
628 nURLScanCount = 0;
630 while ( nURLScanCount < nURLScanLen )
632 sal_Char cCurrent = *pURLScan;
633 switch ( cCurrent )
635 default:
636 if (!( ( cCurrent >= 'a' && cCurrent <= 'z' ) || ( cCurrent >= 'A' && cCurrent <= 'Z' ) || ( cCurrent >= '0' && cCurrent <= '9' ) ) )
638 sprintf( pURLDest, "%%%02X", (unsigned char)cCurrent );
639 pURLDest += 3;
640 break;
642 case '!':
643 case '\'':
644 case '(':
645 case ')':
646 case '*':
647 case '-':
648 case '.':
649 case '_':
650 case '~':
651 case '$':
652 case '&':
653 case '+':
654 case ',':
655 case '=':
656 case '@':
657 case ':':
658 case '/':
659 case '\\':
660 case '|':
661 *pURLDest++ = cCurrent;
662 break;
663 case 0:
664 break;
667 pURLScan++;
668 nURLScanCount++;
671 *pURLDest = 0;
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 */
698 OSL_ENSURE_FILE(
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 );
708 if ( bValidEncoded )
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 ) )
721 sal_uInt32 nSkip;
723 if ( 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pDecodedURL, nDecodedLen, "file:\\\\\\", 8 ) )
724 nSkip = 8;
725 else if (
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 )
729 nSkip = 17;
730 else
731 nSkip = 5;
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 );
736 else
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;
750 else
751 OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not an absolute FileURL !!!", strURL );
756 if ( strDecodedURL )
757 rtl_uString_release( strDecodedURL );
759 if ( osl_File_E_None == nError )
760 rtl_uString_assign( pustrPath, strTempPath );
762 if ( strTempPath )
763 rtl_uString_release( strTempPath );
766 OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not a FileURL !!!", strURL );
769 return nError;
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;
779 if (strPath)
780 dwPathType = IsValidFilePath(strPath, NULL, VALIDATEPATH_ALLOW_RELATIVE, NULL);
782 if (dwPathType)
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;
794 break;
795 case PATHTYPE_ABSOLUTE_UNC:
796 rtl_uString_newFromAscii( &strTempURL, "file:" );
797 rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath );
798 nError = osl_File_E_None;
799 break;
800 case PATHTYPE_ABSOLUTE_LOCAL:
801 rtl_uString_newFromAscii( &strTempURL, "file:///" );
802 rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath );
803 nError = osl_File_E_None;
804 break;
805 default:
806 break;
809 /* Release temp path */
810 rtl_uString_release( strTempPath );
813 if ( osl_File_E_None == nError )
815 rtl_String *strEncodedURL = NULL;
817 /* Encode the URL */
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 */
827 if ( strTempURL )
828 rtl_uString_release( strTempURL );
831 OSL_ENSURE_FILE( !nError, "osl_getFileURLFromSystemPath: \"%s\" is not a systemPath !!!", strPath );
833 return nError;
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;
858 oslFileError error;
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 )
870 DWORD nBufferLength;
871 DWORD dwResult;
872 LPTSTR lpBuffer = NULL;
873 LPTSTR lpszFilePart;
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 */
878 dwResult = MAX_PATH;
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 ;-) */
899 if ( dwResult )
901 rtl_uString_newFromStr( &ustrSysPath, reinterpret_cast<const sal_Unicode*>(lpBuffer) );
902 error = osl_getFileURLFromSystemPath( ustrSysPath, pustrPath );
904 else
906 WIN32_FIND_DATA aFindFileData;
907 HANDLE hFind;
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 );
917 FindClose( hFind );
921 rtl_freeMemory( lpBuffer );
924 if ( ustrSysPath )
925 rtl_uString_release( ustrSysPath );
927 if ( ustrUNCPath )
928 rtl_uString_release( ustrUNCPath );
930 return error;
933 //#####################################################
935 oslFileError SAL_CALL osl_getAbsoluteFileURL( rtl_uString* ustrBaseURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL )
937 oslFileError eError;
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 );
948 else
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" );
954 if ( !eError )
956 TCHAR szBuffer[MAX_PATH];
957 TCHAR szCurrentDir[MAX_PATH];
958 LPTSTR lpFilePart = NULL;
959 DWORD dwResult;
961 /*@@@ToDo
962 Bad, bad hack, this only works if the base path
963 really exists which is not necessary according
964 to RFC2396
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 );
985 if ( dwResult )
987 if ( dwResult >= MAX_PATH )
988 eError = osl_File_E_INVAL;
989 else
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 );
1001 else
1002 eError = oslTranslateFileError( GetLastError() );
1005 if ( ustrBaseSysPath )
1006 rtl_uString_release( ustrBaseSysPath );
1008 if ( ustrRelSysPath )
1009 rtl_uString_release( ustrRelSysPath );
1011 return eError;
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;