xref: /trunk/main/sal/osl/os2/file_url.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <ctype.h>
29 #include "system.h"
30 
31 #ifndef _LIMITS_H
32 #include <limits.h>
33 #endif
34 
35 #ifndef _ERRNO_H
36 #include <errno.h>
37 #endif
38 
39 #ifndef _STDLIB_H_
40 #include <stdlib.h>
41 #endif
42 
43 #ifndef _STRINGS_H
44 #include <strings.h>
45 #endif
46 
47 #ifndef _UNISTD_H
48 #include <unistd.h>
49 #endif
50 #include <osl/file.h>
51 #include <osl/security.h>
52 #include <rtl/uri.h>
53 #include <osl/diagnose.h>
54 #include <rtl/ustring.hxx>
55 #include <rtl/ustrbuf.h>
56 
57 #ifndef _OSL_TREAD_H_
58 #include <osl/thread.h>
59 #endif
60 #include <osl/file.hxx>
61 #include <osl/mutex.h>
62 #include <osl/process.h>
63 #include "file_error_transl.h"
64 
65 #ifndef _FILE_URL_H_
66 #include "file_url.h"
67 #endif
68 #include "file_path_helper.hxx"
69 
70 #ifndef _OSL_UUNXAPI_HXX_
71 #include "uunxapi.hxx"
72 #endif
73 
74 #include <wchar.h>
75 #include <wctype.h>
76 
77 /***************************************************
78 
79  General note
80 
81  This file contains the part that handles File URLs.
82 
83  File URLs as scheme specific notion of URIs
84  (RFC2396) may be handled platform independend, but
85  will not in osl which is considered wrong.
86  Future version of osl should handle File URLs this
87  way. In rtl/uri there is already an URI parser etc.
88  so this code should be consolidated.
89 
90  **************************************************/
91 
92 oslMutex g_CurrentDirectoryMutex;
93 
94 
95 /***************************************************
96  * forward
97  **************************************************/
98 
99 void _osl_warnFile(const char*, rtl_uString*);
100 rtl_uString*  oslMakeUStrFromPsz(const sal_Char* pszStr,rtl_uString** uStr);
101 
102 extern "C" int UnicodeToText(char *, size_t, const sal_Unicode *, sal_Int32);
103 extern "C" int TextToUnicode(const char* text, size_t text_buffer_size, sal_Unicode* unic_text, sal_Int32 unic_text_buffer_size);
104 
105 /***************************************************
106  * namespace directives
107  **************************************************/
108 
109 using namespace osl;
110 
111 /******************************************************************************
112  *
113  *                  Exported Module Functions
114  *
115  *****************************************************************************/
116 
117 /* a slightly modified version of Pchar in rtl/source/uri.c */
118 const sal_Bool uriCharClass[128] =
119 {
120   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */
121   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122   0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./  */
123   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */
124   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */
125   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */
126   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */
127   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0  /* pqrstuvwxyz{|}~  */
128 };
129 
130 
131 /* check for top wrong usage strings */
132 /*
133 static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len )
134 {
135     rtl_uString *pTmp = NULL;
136     sal_Bool bRet;
137 
138     rtl_uString_newFromStr_WithLength( &pTmp, path, len );
139 
140     rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length );
141 
142     bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) ||
143            ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) ||
144            ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) ||
145            ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) ||
146            ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) );
147 
148     rtl_uString_release( pTmp );
149     return bRet;
150 }
151 */
152 
153 
154 /****************************************************************************/
155 /*  osl_getFileURLFromSystemPath */
156 /****************************************************************************/
157 
158 BOOL WINAPI IsValidFilePathComponent(
159     LPCTSTR lpComponent, LPCTSTR *lppComponentEnd, DWORD dwFlags)
160 {
161     LPCTSTR lpComponentEnd = NULL;
162     LPCTSTR lpCurrent = lpComponent;
163     BOOL    fValid = TRUE;  /* Assume success */
164     TCHAR   cLast = 0;
165 
166     /* Path component length must not exceed MAX_PATH */
167 
168     while ( !lpComponentEnd && lpCurrent && lpCurrent - lpComponent < _MAX_PATH )
169     {
170         switch ( *lpCurrent )
171         {
172             /* Both backslash and slash determine the end of a path component */
173         case '\0':
174         case '/':
175         case '\\':
176             switch ( cLast )
177             {
178                 /* Component must not end with '.' or blank and can't be empty */
179 
180             case '.':
181                 if ( dwFlags & VALIDATEPATH_ALLOW_ELLIPSE )
182                 {
183                     if ( 1 == lpCurrent - lpComponent )
184                     {
185                         /* Current directory is O.K. */
186                         lpComponentEnd = lpCurrent;
187                         break;
188                     }
189                     else if ( 2 == lpCurrent - lpComponent && '.' == *lpComponent )
190                     {
191                         /* Parent directory is O.K. */
192                         lpComponentEnd = lpCurrent;
193                         break;
194                     }
195                 }
196             case 0:
197             case ' ':
198                 lpComponentEnd = lpCurrent - 1;
199                 fValid = FALSE;
200                 break;
201             default:
202                 lpComponentEnd = lpCurrent;
203                 break;
204             }
205             break;
206             /* '?' and '*' are valid wildcards but not valid file name characters */
207         case '?':
208         case '*':
209             if ( dwFlags & VALIDATEPATH_ALLOW_WILDCARDS )
210                 break;
211             /* The following characters are reserved */
212         case '<':
213         case '>':
214         case '\"':
215         case '|':
216         case ':':
217             lpComponentEnd = lpCurrent;
218             fValid = FALSE;
219             break;
220         default:
221             /* Characters below ASCII 32 are not allowed */
222             if ( *lpCurrent < ' ' )
223             {
224                 lpComponentEnd = lpCurrent;
225                 fValid = FALSE;
226             }
227             break;
228         }
229         cLast = *lpCurrent++;
230     }
231 
232     /*  If we don't reached the end of the component the length of the component was to long
233         ( See condition of while loop ) */
234     if ( !lpComponentEnd )
235     {
236         fValid = FALSE;
237         lpComponentEnd = lpCurrent;
238     }
239 
240     /* Test wether the component specifies a device name what is not allowed */
241 
242     // MT: PERFORMANCE:
243     // This is very expensive. A lot of calls to _tcsicmp.
244     // in SRC6870m71 67.000 calls of this method while empty office start result into more than 1.500.00 calls of _tcsicmp!
245     // Possible optimizations
246     // - Array should be const static
247     // - Sorted array, use binary search
248     // - More intelligent check for com1-9, lpt1-9
249     // Maybe make szComponent upper case, don't search case intensitive
250     // 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.
251     /*
252     if ( fValid )
253     {
254         LPCTSTR alpDeviceNames[] =
255         {
256             TEXT("CON"),
257             TEXT("PRN"),
258             TEXT("AUX"),
259             TEXT("CLOCK$"),
260             TEXT("NUL"),
261             TEXT("LPT1"),
262             TEXT("LPT2"),
263             TEXT("LPT3"),
264             TEXT("LPT4"),
265             TEXT("LPT5"),
266             TEXT("LPT6"),
267             TEXT("LPT7"),
268             TEXT("LPT8"),
269             TEXT("LPT9"),
270             TEXT("COM1"),
271             TEXT("COM2"),
272             TEXT("COM3"),
273             TEXT("COM4"),
274             TEXT("COM5"),
275             TEXT("COM6"),
276             TEXT("COM7"),
277             TEXT("COM8"),
278             TEXT("COM9")
279         };
280 
281         TCHAR   szComponent[MAX_PATH];
282         int     nComponentLength;
283         LPCTSTR lpDot;
284         int     i;
285 
286         // A device name with an extension is also invalid
287         lpDot = _tcschr( lpComponent, '.' );
288 
289         if ( !lpDot || lpDot > lpComponentEnd )
290             nComponentLength = lpComponentEnd - lpComponent;
291         else
292             nComponentLength = lpDot - lpComponent;
293 
294         _tcsncpy( szComponent, lpComponent, nComponentLength );
295         szComponent[nComponentLength] = 0;
296 
297         for ( i = 0; i < sizeof( alpDeviceNames ) / sizeof(LPCTSTR); i++ )
298         {
299             if ( 0 == _tcsicmp( szComponent, alpDeviceNames[i] ) )
300             {
301                 lpComponentEnd = lpComponent;
302                 fValid = FALSE;
303                 break;
304             }
305         }
306     }
307     */
308 
309     if ( fValid )
310     {
311         // Empty components are not allowed
312         if ( lpComponentEnd - lpComponent < 1 )
313             fValid = FALSE;
314 
315         // If we reached the end of the string NULL is returned
316         else if ( !*lpComponentEnd )
317             lpComponentEnd = NULL;
318 
319     }
320 
321     if ( lppComponentEnd )
322         *lppComponentEnd = lpComponentEnd;
323 
324     return fValid;
325 }
326 
327 //#####################################################
328 DWORD WINAPI IsValidFilePath(LPCTSTR lpszPath, LPCTSTR *lppError, DWORD dwFlags)
329 {
330     LPCTSTR lpComponent;
331     BOOL    fValid = TRUE;
332     DWORD   dwPathType = PATHTYPE_ERROR;
333 
334     if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
335         dwFlags |= VALIDATEPATH_ALLOW_ELLIPSE;
336 
337     if ( !lpszPath )
338     {
339         fValid = FALSE;
340         lpComponent = lpszPath;
341     }
342 
343     /* Test for UNC path notation */
344     if ( 2 == _tcsspn( lpszPath, CHARSET_SEPARATOR ) )
345     {
346         /* Place the pointer behind the leading to backslashes */
347 
348         lpComponent = lpszPath + 2;
349 
350         fValid = IsValidFilePathComponent( lpComponent, &lpComponent, VALIDATEPATH_ALLOW_ELLIPSE );
351 
352         /* So far we have a valid servername. Now let's see if we also have a network resource */
353 
354         dwPathType = PATHTYPE_ABSOLUTE_UNC;
355 
356         if ( fValid )
357         {
358             if ( lpComponent &&  !*++lpComponent )
359                 lpComponent = NULL;
360 
361             if ( !lpComponent )
362             {
363 #if 0
364                 /* We only have a Server specification what is invalid */
365 
366                 lpComponent = lpszPath;
367                 fValid = FALSE;
368 #else
369                 dwPathType |= PATHTYPE_IS_SERVER;
370 #endif
371             }
372             else
373             {
374                 /* Now test the network resource */
375 
376                 fValid = IsValidFilePathComponent( lpComponent, &lpComponent, 0 );
377 
378                 /* If we now reached the end of the path, everything is O.K. */
379 
380 
381                 if ( fValid && (!lpComponent || lpComponent && !*++lpComponent ) )
382                 {
383                     lpComponent = NULL;
384                     dwPathType |= PATHTYPE_IS_VOLUME;
385                 }
386             }
387         }
388     }
389 
390     /* Local path verification. Must start with <drive>: */
391     else if ( _istalpha( lpszPath[0] ) && ':' == lpszPath[1] )
392     {
393         /* Place pointer behind correct drive specification */
394 
395         lpComponent = lpszPath + 2;
396 
397         if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) )
398             lpComponent++;
399         else if ( *lpComponent )
400             fValid = FALSE;
401 
402         dwPathType = PATHTYPE_ABSOLUTE_LOCAL;
403 
404         /* Now we are behind the backslash or it was a simple drive without backslash */
405 
406         if ( fValid && !*lpComponent )
407         {
408             lpComponent = NULL;
409             dwPathType |= PATHTYPE_IS_VOLUME;
410         }
411     }
412 
413     /* Can be a relative path */
414     else if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
415     {
416         lpComponent = lpszPath;
417 
418         /* Relative path can start with a backslash */
419 
420         if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) )
421         {
422             lpComponent++;
423             if ( !*lpComponent )
424                 lpComponent = NULL;
425         }
426 
427         dwPathType = PATHTYPE_RELATIVE;
428     }
429 
430     /* Anything else is an error */
431     else
432     {
433         fValid = FALSE;
434         lpComponent = lpszPath;
435     }
436 
437     /* Now validate each component of the path */
438     while ( fValid && lpComponent )
439     {
440         fValid = IsValidFilePathComponent( lpComponent, &lpComponent, dwFlags );
441 
442         if ( fValid && lpComponent )
443         {
444             lpComponent++;
445 
446             /* If the string behind the backslash is empty, we've done */
447 
448             if ( !*lpComponent )
449                 lpComponent = NULL;
450         }
451     }
452 
453     if ( fValid && _tcslen( lpszPath ) >= _MAX_PATH )
454     {
455         fValid = FALSE;
456         lpComponent = lpszPath + _MAX_PATH;
457     }
458 
459     if ( lppError )
460         *lppError = lpComponent;
461 
462     return fValid ? dwPathType : PATHTYPE_ERROR;
463 }
464 
465 sal_Bool _osl_decodeURL( rtl_String* strUTF8, rtl_uString** pstrDecodedURL )
466 {
467     sal_Char        *pBuffer;
468     const sal_Char  *pSrcEnd;
469     const sal_Char  *pSrc;
470     sal_Char        *pDest;
471     sal_Int32       nSrcLen;
472     sal_Bool        bValidEncoded = sal_True;   /* Assume success */
473 
474     /* The resulting decoded string length is shorter or equal to the source length */
475 
476     nSrcLen = rtl_string_getLength(strUTF8);
477     pBuffer = reinterpret_cast<sal_Char*>(rtl_allocateMemory(nSrcLen + 1));
478 
479     pDest = pBuffer;
480     pSrc = rtl_string_getStr(strUTF8);
481     pSrcEnd = pSrc + nSrcLen;
482 
483     /* Now decode the URL what should result in an UTF8 string */
484     while ( bValidEncoded && pSrc < pSrcEnd )
485     {
486         switch ( *pSrc )
487         {
488         case '%':
489             {
490                 sal_Char    aToken[3];
491                 sal_Char    aChar;
492 
493                 pSrc++;
494                 aToken[0] = *pSrc++;
495                 aToken[1] = *pSrc++;
496                 aToken[2] = 0;
497 
498                 aChar = (sal_Char)strtoul( aToken, NULL, 16 );
499 
500                 /* The chars are path delimiters and must not be encoded */
501 
502                 if ( 0 == aChar || '\\' == aChar || '/' == aChar || ':' == aChar )
503                     bValidEncoded = sal_False;
504                 else
505                     *pDest++ = aChar;
506             }
507             break;
508         default:
509             *pDest++ = *pSrc++;
510             break;
511         }
512     }
513 
514     *pDest++ = 0;
515 
516     if ( bValidEncoded ) {
517         rtl_string2UString( pstrDecodedURL, pBuffer, rtl_str_getLength(pBuffer), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );
518         OSL_ASSERT(*pstrDecodedURL != 0);
519     }
520 
521     rtl_freeMemory( pBuffer );
522 
523     return bValidEncoded;
524 }
525 
526 //#############################################
527 void _osl_encodeURL( rtl_uString *strURL, rtl_String **pstrEncodedURL )
528 {
529     /* Encode non ascii characters within the URL */
530 
531     rtl_String      *strUTF8 = NULL;
532     sal_Char        *pszEncodedURL;
533     const sal_Char  *pURLScan;
534     sal_Char        *pURLDest;
535     sal_Int32       nURLScanLen;
536     sal_Int32       nURLScanCount;
537 
538     rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );
539 
540     pszEncodedURL = (sal_Char*) rtl_allocateMemory( (rtl_string_getLength( strUTF8 ) * 3 + 1)  * sizeof(sal_Char) );
541 
542     pURLDest = pszEncodedURL;
543     pURLScan = rtl_string_getStr( strUTF8 );
544     nURLScanLen = rtl_string_getLength( strUTF8 );
545     nURLScanCount = 0;
546 
547     while ( nURLScanCount < nURLScanLen )
548     {
549         sal_Char    cCurrent = *pURLScan;
550 
551         switch ( cCurrent )
552         {
553         default:
554             if (!( ( cCurrent >= 'a' && cCurrent <= 'z' ) || ( cCurrent >= 'A' && cCurrent <= 'Z' ) || ( cCurrent >= '0' && cCurrent <= '9' ) ) )
555             {
556                 sprintf( pURLDest, "%%%02X", (unsigned char)cCurrent );
557                 pURLDest += 3;
558                 break;
559             }
560         case '!':
561         case '\'':
562         case '(':
563         case ')':
564         case '*':
565         case '-':
566         case '.':
567         case '_':
568         case '~':
569         case '$':
570         case '&':
571         case '+':
572         case ',':
573         case '=':
574         case '@':
575         case ':':
576         case '/':
577         case '\\':
578         case '|':
579             *pURLDest++ = cCurrent;
580             break;
581         case 0:
582             break;
583         }
584 
585         pURLScan++;
586         nURLScanCount++;
587     }
588 
589 
590     *pURLDest = 0;
591 
592     rtl_string_release( strUTF8 );
593     rtl_string_newFromStr( pstrEncodedURL, pszEncodedURL );
594     rtl_freeMemory( pszEncodedURL );
595 }
596 
597 //#############################################
598 oslFileError SAL_CALL _osl_getFileURLFromSystemPath( rtl_uString* strPath, rtl_uString** pstrURL )
599 {
600     oslFileError nError = osl_File_E_INVAL; /* Assume failure */
601     rtl_uString *strTempURL = NULL;
602     DWORD dwPathType = PATHTYPE_ERROR;
603 
604     if (strPath)
605         dwPathType = IsValidFilePath(strPath->buffer, NULL, VALIDATEPATH_ALLOW_RELATIVE);
606 
607     if (dwPathType)
608     {
609         rtl_uString *strTempPath = NULL;
610 
611         /* Replace backslashes */
612 
613         rtl_uString_newReplace( &strTempPath, strPath, '\\', '/' );
614 
615         switch ( dwPathType & PATHTYPE_MASK_TYPE )
616         {
617         case PATHTYPE_RELATIVE:
618             rtl_uString_assign( &strTempURL, strTempPath );
619             nError = osl_File_E_None;
620             break;
621         case PATHTYPE_ABSOLUTE_UNC:
622             rtl_uString_newFromAscii( &strTempURL, "file:" );
623             rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath );
624             nError = osl_File_E_None;
625             break;
626         case PATHTYPE_ABSOLUTE_LOCAL:
627             rtl_uString_newFromAscii( &strTempURL, "file:///" );
628             rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath );
629             nError = osl_File_E_None;
630             break;
631         default:
632             break;
633         }
634 
635         /* Release temp path */
636 
637         rtl_uString_release( strTempPath );
638     }
639 
640     if ( osl_File_E_None == nError )
641     {
642         rtl_String  *strEncodedURL = NULL;
643 
644         /* Encode the URL */
645 
646         _osl_encodeURL( strTempURL, &strEncodedURL );
647 
648         /* Provide URL via unicode string */
649 
650         rtl_string2UString( pstrURL, rtl_string_getStr(strEncodedURL), rtl_string_getLength(strEncodedURL), RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS );
651         OSL_ASSERT(*pstrURL != 0);
652         rtl_string_release( strEncodedURL );
653     }
654 
655     /* Release temp URL */
656 
657     if ( strTempURL )
658         rtl_uString_release( strTempURL );
659 
660     /*
661     OSL_ENSURE_FILE( !nError, "osl_getFileURLFromSystemPath: \"%s\" is not a systemPath !!!", strPath );
662     */
663 
664     return nError;
665 }
666 
667 oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL )
668 {
669     return _osl_getFileURLFromSystemPath( ustrSystemPath, pustrFileURL );
670 #if 0
671     static const sal_Unicode pDoubleSlash[2] = { '/', '/' };
672 
673     rtl_uString *pTmp = NULL;
674     sal_Int32 nIndex;
675 
676     if( 0 == ustrSystemPath->length )
677         return osl_File_E_INVAL;
678 
679     /* YD convert '\' to '/' */
680     rtl_ustr_replaceChar( ustrSystemPath->buffer, '\\', '/' );
681 
682     /* temporary hack: if already file url, return ustrSystemPath */
683     if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) )
684     {
685     /*
686         if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) )
687         {
688             OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" );
689             rtl_uString_assign( pustrFileURL, ustrSystemPath );
690         }
691         else
692         {
693             rtl_uString *pTmp2 = NULL;
694 
695             OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" );
696             rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 );
697             rtl_uString_newFromAscii( &pTmp2, "file://" );
698             rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 );
699             rtl_uString_release( pTmp2 );
700         }
701         return osl_File_E_None;
702         */
703         return osl_File_E_INVAL;
704     }
705 
706 
707     /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
708     if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] )
709     {
710         /* check if another user is specified */
711         if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) )
712         {
713             /* osl_getHomeDir returns file URL */
714             osl_getHomeDir( osl_getCurrentSecurity(), &pTmp );
715 
716             /* remove "file://" prefix */
717             rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 );
718 
719             /* replace '~' in original string */
720             rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp );
721         }
722 
723         else
724         {
725             /* FIXME: replace ~user with users home directory */
726             return osl_File_E_INVAL;
727         }
728     }
729 
730     /* check if initial string contains double instances of '/' */
731     nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 );
732     if( -1 != nIndex )
733     {
734         sal_Int32 nSrcIndex;
735         sal_Int32 nDeleted = 0;
736 
737         /* if pTmp is not already allocated, copy ustrSystemPath for modification */
738         if( NULL == pTmp )
739             rtl_uString_newFromString( &pTmp, ustrSystemPath );
740 
741         /* adapt index to pTmp */
742         nIndex += pTmp->length - ustrSystemPath->length;
743 
744         /* remove all occurances of '//' */
745         for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ )
746         {
747             if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) )
748                 nDeleted++;
749             else
750                 pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex];
751         }
752 
753         /* adjust length member */
754         pTmp->length -= nDeleted;
755     }
756 
757     if( NULL == pTmp )
758         rtl_uString_assign( &pTmp, ustrSystemPath );
759 
760     /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */
761     /*
762     OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
763     */
764 
765     /* file URLs must be URI encoded */
766     rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL );
767 
768     rtl_uString_release( pTmp );
769 
770     /* absolute urls should start with 'file://' */
771     if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] )
772     {
773         rtl_uString *pProtocol = NULL;
774 
775         rtl_uString_newFromAscii( &pProtocol, "file://" );
776         rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL );
777         rtl_uString_release( pProtocol );
778     }
779 
780     return osl_File_E_None;
781 #endif
782 }
783 
784 //#############################################
785 oslFileError SAL_CALL _osl_getSystemPathFromFileURL( rtl_uString *strURL, rtl_uString **pustrPath, sal_Bool bAllowRelative )
786 {
787     rtl_String          *strUTF8 = NULL;
788     rtl_uString         *strDecodedURL = NULL;
789     rtl_uString         *strTempPath = NULL;
790     const sal_Unicode   *pDecodedURL;
791     sal_uInt32          nDecodedLen;
792     sal_Bool            bValidEncoded;
793     oslFileError        nError = osl_File_E_INVAL;  /* Assume failure */
794 
795     /*  If someone hasn't encoded the complete URL we convert it to UTF8 now to prevent from
796         having a mixed encoded URL later */
797 
798     rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );
799 
800     /* If the length of strUTF8 and strURL differs it indicates that the URL was not correct encoded */
801 
802     OSL_ENSURE_FILE(
803         strUTF8->length == strURL->length ||
804         0 != rtl_ustr_ascii_shortenedCompare_WithLength( strURL->buffer, strURL->length, "file:\\\\", 7 )
805         ,"osl_getSystemPathFromFileURL: \"%s\" is not encoded !!!", strURL );
806 
807     bValidEncoded = _osl_decodeURL( strUTF8, &strDecodedURL );
808 
809     /* Release the encoded UTF8 string */
810 
811     rtl_string_release( strUTF8 );
812 
813 
814     if ( bValidEncoded )
815     {
816         /* Replace backslashes and pipes */
817 
818         rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '/', '\\' );
819         rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '|', ':' );
820 
821         pDecodedURL = rtl_uString_getStr( strDecodedURL );
822         nDecodedLen = rtl_uString_getLength( strDecodedURL );
823 
824         /* Must start with "file://" */
825 
826         if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\", 7 ) )
827         {
828             sal_uInt32  nSkip;
829 
830             if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\\\", 8 ) )
831                 nSkip = 8;
832             else if (
833                 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\localhost\\", 17 ) ||
834                 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\127.0.0.1\\", 17 )
835             )
836                 nSkip = 17;
837             else
838                 nSkip = 5;
839 
840             /* Indicates local root */
841             if ( nDecodedLen == nSkip )
842                 rtl_uString_newFromStr_WithLength( &strTempPath, (const sal_Unicode*)WSTR_SYSTEM_ROOT_PATH, ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1 );
843             else
844                 rtl_uString_newFromStr_WithLength( &strTempPath, pDecodedURL + nSkip, nDecodedLen - nSkip );
845 
846             if ( IsValidFilePath( strTempPath->buffer, NULL, VALIDATEPATH_ALLOW_ELLIPSE ) )
847                 nError = osl_File_E_None;
848         }
849         else if ( bAllowRelative )  /* This maybe a relative file URL */
850         {
851             rtl_uString_assign( &strTempPath, strDecodedURL );
852 
853             if ( IsValidFilePath( strTempPath->buffer, NULL, VALIDATEPATH_ALLOW_RELATIVE | VALIDATEPATH_ALLOW_ELLIPSE ) )
854                 nError = osl_File_E_None;
855         }
856     /*
857         else
858             OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not an absolute FileURL !!!", strURL );
859      */
860 
861     }
862 
863     if ( strDecodedURL )
864         rtl_uString_release( strDecodedURL );
865 
866     if ( osl_File_E_None == nError )
867         rtl_uString_assign( pustrPath, strTempPath );
868 
869     if ( strTempPath )
870         rtl_uString_release( strTempPath );
871 
872     /*
873     OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not a FileURL !!!", strURL );
874     */
875 
876     return nError;
877 }
878 
879 /****************************************************************************/
880 /*  osl_getSystemPathFromFileURL */
881 /****************************************************************************/
882 
883 oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath )
884 {
885     return _osl_getSystemPathFromFileURL( ustrFileURL, pustrSystemPath, sal_True );
886 #if 0
887     sal_Int32 nIndex = 0;
888     rtl_uString * pTmp = NULL;
889 
890     sal_Unicode encodedSlash[3] = { '%', '2', 'F' };
891 
892     /* temporary hack: if already system path, return ustrFileURL */
893     /*
894     if( (sal_Unicode) '/' == ustrFileURL->buffer[0] )
895     {
896         OSL_ENSURE( 0, "osl_getSystemPathFromFileURL: input is already system path" );
897         rtl_uString_assign( pustrSystemPath, ustrFileURL );
898         return osl_File_E_None;
899     }
900     */
901 
902     /* a valid file url may not start with '/' */
903     if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) )
904     {
905         return osl_File_E_INVAL;
906     }
907 
908     /* search for encoded slashes (%2F) and decode every single token if we find one */
909     if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) )
910     {
911         rtl_uString * ustrPathToken = NULL;
912         sal_Int32 nOffset = 7;
913 
914         do
915         {
916             nOffset += nIndex;
917 
918             /* break url down in '/' devided tokens tokens */
919             nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, (sal_Unicode) '/' );
920 
921             /* copy token to new string */
922             rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset,
923                 -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ );
924 
925             /* decode token */
926             rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
927 
928             /* the result should not contain any '/' */
929             if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, (sal_Unicode) '/' ) )
930             {
931                 rtl_uString_release( pTmp );
932                 rtl_uString_release( ustrPathToken );
933 
934                 return osl_File_E_INVAL;
935             }
936 
937         } while( -1 != nIndex );
938 
939         /* release temporary string and restore index variable */
940         rtl_uString_release( ustrPathToken );
941         nIndex = 0;
942     }
943 
944     /* protocol and server should not be encoded, so decode the whole string */
945     rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
946 
947     /* check if file protocol specified */
948     /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
949     if( 7 <= pTmp->length )
950     {
951         rtl_uString * pProtocol = NULL;
952         rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 );
953 
954         /* protocol is case insensitive */
955         rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length );
956 
957         if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) )
958             nIndex = 7;
959 
960         rtl_uString_release( pProtocol );
961     }
962 
963     /* skip "localhost" or "127.0.0.1" if "file://" is specified */
964     /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
965     if( nIndex && ( 10 <= pTmp->length - nIndex ) )
966     {
967         rtl_uString * pServer = NULL;
968         rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 );
969 
970         /* server is case insensitive */
971         rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length );
972 
973         if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) ||
974             ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) )
975         {
976             /* don't exclude the '/' */
977             nIndex += 9;
978         }
979 
980         rtl_uString_release( pServer );
981     }
982 
983     if( nIndex )
984         rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex );
985 
986     /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
987     if( (sal_Unicode) '~' == pTmp->buffer[0] )
988     {
989         /* check if another user is specified */
990         if( ( 1 == pTmp->length ) || ( (sal_Unicode)'/' == pTmp->buffer[1] ) )
991         {
992             rtl_uString *pTmp2 = NULL;
993 
994             /* osl_getHomeDir returns file URL */
995             osl_getHomeDir( osl_getCurrentSecurity(), &pTmp2 );
996 
997             /* remove "file://" prefix */
998             rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 );
999 
1000             /* replace '~' in original string */
1001             rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 );
1002             rtl_uString_release( pTmp2 );
1003         }
1004 
1005         else
1006         {
1007             /* FIXME: replace ~user with users home directory */
1008             return osl_File_E_INVAL;
1009         }
1010     }
1011 
1012     /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */
1013     /*
1014     OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
1015     */
1016 
1017     *pustrSystemPath = pTmp;
1018     return osl_File_E_None;
1019 #endif // 0
1020 }
1021 
1022 
1023 /****************************************************************************
1024  * osl_getSystemPathFromFileURL_Ex - helper function
1025  * clients may specify if they want to accept relative
1026  * URLs or not
1027  ****************************************************************************/
1028 
1029 oslFileError osl_getSystemPathFromFileURL_Ex(
1030     rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative)
1031 {
1032     return _osl_getSystemPathFromFileURL( ustrFileURL, pustrSystemPath, bAllowRelative);
1033 #if 0
1034     rtl_uString* temp = 0;
1035     oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp);
1036 
1037     if (osl_File_E_None == osl_error)
1038     {
1039         if (bAllowRelative
1040             || (UNICHAR_SLASH == temp->buffer[0])
1041             || (UNICHAR_COLON == temp->buffer[1] && UNICHAR_SLASH == temp->buffer[2]))
1042         {
1043             *pustrSystemPath = temp;
1044         }
1045         else
1046         {
1047             rtl_uString_release(temp);
1048             osl_error = osl_File_E_INVAL;
1049         }
1050     }
1051 
1052     return osl_error;
1053 #endif
1054 }
1055 
1056 namespace /* private */
1057 {
1058 
1059 #if 0 // YD
1060 
1061     /******************************************************
1062      * Helper function, return a pinter to the final '\0'
1063      * of a string
1064      ******************************************************/
1065 
1066     sal_Unicode* ustrtoend(sal_Unicode* pStr)
1067     {
1068         return (pStr + rtl_ustr_getLength(pStr));
1069     }
1070 
1071     /*********************************************
1072 
1073      ********************************************/
1074     sal_Unicode* ustrcpy(const sal_Unicode* s, sal_Unicode* d)
1075     {
1076         const sal_Unicode* sc = s;
1077         sal_Unicode*       dc = d;
1078 
1079         while ((*dc++ = *sc++))
1080             /**/;
1081 
1082         return d;
1083     }
1084 
1085     /*********************************************
1086 
1087      ********************************************/
1088 
1089     sal_Unicode* ustrncpy(const sal_Unicode* s, sal_Unicode* d, unsigned int n)
1090     {
1091         const sal_Unicode* sc = s;
1092         sal_Unicode*       dc = d;
1093         unsigned int       i  = n;
1094 
1095         while (i--)
1096             *dc++ = *sc++;
1097 
1098         if (n)
1099             *dc = 0;
1100 
1101         return d;
1102     }
1103 
1104     /*********************************************
1105 
1106      ********************************************/
1107 
1108     sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d)
1109     {
1110         sal_Unicode* p = ustrtoend(d);
1111         *p++ = chr;
1112         *p   = 0;
1113         return d;
1114     }
1115 
1116     /*********************************************
1117 
1118      ********************************************/
1119 
1120     sal_Unicode* ustrcat(const sal_Unicode* s, sal_Unicode* d)
1121     {
1122         sal_Unicode* dc = ustrtoend(d);
1123         ustrcpy(s, dc);
1124         return d;
1125     }
1126 
1127     /******************************************************
1128      *
1129      ******************************************************/
1130 
1131     bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr)
1132     {
1133         sal_Unicode* p = ustrtoend(pStr);
1134         if (p > pStr)
1135             p--;
1136         return (*p == Chr);
1137     }
1138 
1139     /******************************************************
1140      * Ensure that the given string has the specified last
1141      * character if necessary append it
1142      ******************************************************/
1143 
1144     sal_Unicode* _strensurelast(sal_Unicode* pStr, sal_Unicode Chr)
1145     {
1146         if (!_islastchr(pStr, Chr))
1147             ustrchrcat(Chr, pStr);
1148         return pStr;
1149     }
1150 
1151     /******************************************************
1152      * Remove the last part of a path, a path that has
1153      * only a '/' or no '/' at all will be returned
1154      * unmodified
1155      ******************************************************/
1156 
1157     sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath)
1158     {
1159         /*  we always may skip -2 because we
1160             may at least stand on a '/' but
1161             either there is no other character
1162             before this '/' or it's another
1163             character than the '/'
1164         */
1165         sal_Unicode* p = ustrtoend(aPath) - 2;
1166 
1167         // move back to the next path separator
1168         // or to the start of the string
1169         while ((p > aPath) && (*p != UNICHAR_SLASH))
1170             p--;
1171 
1172         if (p >= aPath)
1173         {
1174             if (UNICHAR_SLASH == *p)
1175             {
1176                 p++;
1177                *p = '\0';
1178             }
1179             else
1180             {
1181                 *p = '\0';
1182             }
1183         }
1184 
1185         return aPath;
1186     }
1187 
1188     /******************************************************
1189      *
1190      ******************************************************/
1191 
1192     oslFileError _osl_resolvepath(
1193         /*inout*/ sal_Unicode* path,
1194         /*inout*/ sal_Unicode* current_pos,
1195         /*in   */ sal_Unicode* sentinel,
1196         /*inout*/ bool* failed)
1197     {
1198         oslFileError ferr = osl_File_E_None;
1199 
1200         if (!*failed)
1201         {
1202             char unresolved_path[PATH_MAX];
1203             if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path)))
1204                 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1205 
1206             char resolved_path[PATH_MAX];
1207             if (realpath(unresolved_path, resolved_path))
1208             {
1209                 if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX))
1210                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1211 
1212                 current_pos = ustrtoend(path) - 1;
1213             }
1214             else
1215             {
1216                 if (EACCES == errno || ENOTDIR == errno || ENOENT == errno)
1217                     *failed = true;
1218                 else
1219                     ferr = oslTranslateFileError(OSL_FET_ERROR, errno);
1220             }
1221         }
1222 
1223         return ferr;
1224     }
1225 
1226     /******************************************************
1227      * Works even with non existing paths. The resulting
1228      * path must not exceed PATH_MAX else
1229      * osl_File_E_NAMETOOLONG is the result
1230      ******************************************************/
1231 
1232     oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path)
1233     {
1234         // the given unresolved path must not exceed PATH_MAX
1235         if (unresolved_path.getLength() >= (PATH_MAX - 2))
1236             return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1237 
1238         sal_Unicode        path_resolved_so_far[PATH_MAX];
1239         const sal_Unicode* punresolved = unresolved_path.getStr();
1240         sal_Unicode*       presolvedsf = path_resolved_so_far;
1241 
1242         // reserve space for leading '/' and trailing '\0'
1243         // do not exceed this limit
1244         sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2;
1245 
1246         // if realpath fails with error ENOTDIR, EACCES or ENOENT
1247         // we will not call it again, because _osl_realpath should also
1248         // work with non existing directories etc.
1249         bool realpath_failed = false;
1250         oslFileError ferr;
1251 
1252         path_resolved_so_far[0] = '\0';
1253 
1254         while (*punresolved != '\0')
1255         {
1256             // ignore '/.' , skip one part back when '/..'
1257 
1258             if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf))
1259             {
1260                 if ('\0' == *(punresolved + 1))
1261                 {
1262                     punresolved++;
1263                     continue;
1264                 }
1265                 else if (UNICHAR_SLASH == *(punresolved + 1))
1266                 {
1267                     punresolved += 2;
1268                     continue;
1269                 }
1270                 else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2))))
1271                 {
1272                     _rmlastpathtoken(path_resolved_so_far);
1273 
1274                     presolvedsf = ustrtoend(path_resolved_so_far) - 1;
1275 
1276                     if (UNICHAR_SLASH == *(punresolved + 2))
1277                         punresolved += 3;
1278                     else
1279                         punresolved += 2;
1280 
1281                     continue;
1282                 }
1283                 else // a file or directory name may start with '.'
1284                 {
1285                     if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
1286                         return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1287 
1288                     ustrchrcat(*punresolved++, path_resolved_so_far);
1289 
1290                     if ('\0' == *punresolved && !realpath_failed)
1291                     {
1292                         ferr = _osl_resolvepath(
1293                             path_resolved_so_far,
1294                             presolvedsf,
1295                             sentinel,
1296                             &realpath_failed);
1297 
1298                         if (osl_File_E_None != ferr)
1299                             return ferr;
1300                     }
1301                 }
1302             }
1303             else if (UNICHAR_SLASH == *punresolved)
1304             {
1305                 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
1306                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1307 
1308                 ustrchrcat(*punresolved++, path_resolved_so_far);
1309 
1310                 if (!realpath_failed)
1311                 {
1312                     ferr = _osl_resolvepath(
1313                         path_resolved_so_far,
1314                         presolvedsf,
1315                         sentinel,
1316                         &realpath_failed);
1317 
1318                     if (osl_File_E_None != ferr)
1319                         return ferr;
1320 
1321                     if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH))
1322                     {
1323                         if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
1324                             return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1325 
1326                         ustrchrcat(UNICHAR_SLASH, path_resolved_so_far);
1327                     }
1328                 }
1329             }
1330             else // any other character
1331             {
1332                 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
1333                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
1334 
1335                 ustrchrcat(*punresolved++, path_resolved_so_far);
1336 
1337                 if ('\0' == *punresolved && !realpath_failed)
1338                 {
1339                     ferr = _osl_resolvepath(
1340                         path_resolved_so_far,
1341                         presolvedsf,
1342                         sentinel,
1343                         &realpath_failed);
1344 
1345                     if (osl_File_E_None != ferr)
1346                         return ferr;
1347                 }
1348             }
1349         }
1350 
1351         sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far);
1352 
1353         OSL_ASSERT(len < PATH_MAX);
1354 
1355         resolved_path = rtl::OUString(path_resolved_so_far, len);
1356 
1357         return osl_File_E_None;
1358     }
1359 
1360 #endif // 0 // YD
1361 
1362 } // end namespace private
1363 
1364 #if OSL_DEBUG_LEVEL > 0
1365 
1366     //#####################################################
1367     void _osl_warnFile( const char *message, rtl_uString *ustrFile )
1368     {
1369         char szBuffer[2048];
1370 
1371         if (ustrFile)
1372         {
1373             rtl_String  *strFile = NULL;
1374 
1375             rtl_uString2String( &strFile, rtl_uString_getStr( ustrFile ), rtl_uString_getLength( ustrFile ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
1376             snprintf( szBuffer, sizeof(szBuffer), message, strFile->buffer );
1377             rtl_string_release( strFile );
1378 
1379             message = szBuffer;
1380         }
1381         OSL_ENSURE( 0, message );
1382     }
1383 
1384 #endif // OSL_DEBUG_LEVEL > 0
1385 
1386 /******************************************************
1387  * osl_getAbsoluteFileURL
1388  ******************************************************/
1389 
1390 //oslFileError osl_getAbsoluteFileURL(rtl_uString*  ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL)
1391 oslFileError SAL_CALL osl_getAbsoluteFileURL( rtl_uString* ustrBaseURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL )
1392 {
1393     oslFileError    eError;
1394     rtl_uString     *ustrRelSysPath = NULL;
1395     rtl_uString     *ustrBaseSysPath = NULL;
1396 
1397     if ( ustrBaseURL && ustrBaseURL->length )
1398     {
1399         eError = _osl_getSystemPathFromFileURL( ustrBaseURL, &ustrBaseSysPath, sal_False );
1400         OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with relative or invalid base URL" );
1401 
1402         eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_True );
1403     }
1404     else
1405     {
1406         eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_False );
1407         OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with empty base URL and/or invalid relative URL" );
1408     }
1409 
1410     if ( !eError )
1411     {
1412         CHAR    szBuffer[_MAX_PATH];
1413         CHAR    szRelSysPath[_MAX_PATH];
1414         CHAR    szCurrentDir[_MAX_PATH];
1415         int     result;
1416         char*   cwd;
1417         int     rc;
1418 
1419 /*@@@ToDo
1420   Bad, bad hack, this only works if the base path
1421   really exists which is not necessary according
1422   to RFC2396
1423   The whole FileURL implementation should be merged
1424   with the rtl/uri class.
1425 */
1426         if ( ustrBaseSysPath )
1427         {
1428             CHAR    szBaseSysPath[_MAX_PATH];
1429 
1430             if (!g_CurrentDirectoryMutex)
1431                 g_CurrentDirectoryMutex = osl_createMutex();
1432 
1433             osl_acquireMutex( g_CurrentDirectoryMutex );
1434 
1435             cwd = getcwd( szCurrentDir, sizeof(szCurrentDir) );
1436             UnicodeToText( szBaseSysPath, sizeof(szBaseSysPath), ustrBaseSysPath->buffer, ustrBaseSysPath->length);
1437             rc = chdir( szBaseSysPath);
1438         }
1439 
1440         UnicodeToText( szRelSysPath, sizeof(szRelSysPath), ustrRelSysPath->buffer, ustrRelSysPath->length);
1441         result = !_abspath( szBuffer, szRelSysPath, sizeof(szBuffer));
1442 
1443         if ( ustrBaseSysPath )
1444         {
1445             rc = chdir( szCurrentDir );
1446 
1447             osl_releaseMutex( g_CurrentDirectoryMutex );
1448         }
1449 
1450         if ( result )
1451         {
1452                 rtl_uString *ustrAbsSysPath = NULL;
1453 
1454                 oslMakeUStrFromPsz( szBuffer, &ustrAbsSysPath);
1455 
1456                 eError = osl_getFileURLFromSystemPath( ustrAbsSysPath, pustrAbsoluteURL );
1457 
1458                 if ( ustrAbsSysPath )
1459                     rtl_uString_release( ustrAbsSysPath );
1460         }
1461         else
1462             eError = osl_File_E_INVAL;
1463     }
1464 
1465     if ( ustrBaseSysPath )
1466         rtl_uString_release( ustrBaseSysPath );
1467 
1468     if ( ustrRelSysPath )
1469         rtl_uString_release( ustrRelSysPath );
1470 
1471     return  eError;
1472 #if 0
1473     FileBase::RC  rc;
1474     rtl::OUString unresolved_path;
1475 
1476     rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path);
1477 
1478     if(FileBase::E_None != rc)
1479         return oslFileError(rc);
1480 
1481     if (systemPathIsRelativePath(unresolved_path))
1482     {
1483         rtl::OUString base_path;
1484         rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False);
1485 
1486         if (FileBase::E_None != rc)
1487             return oslFileError(rc);
1488 
1489         rtl::OUString abs_path;
1490         systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path);
1491 
1492         unresolved_path = abs_path;
1493     }
1494 
1495     rtl::OUString resolved_path;
1496     rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
1497 
1498     if (FileBase::E_None == rc)
1499     {
1500         rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL);
1501         OSL_ASSERT(FileBase::E_None == rc);
1502     }
1503 
1504     return oslFileError(rc);
1505 #endif // 0
1506 }
1507 
1508 
1509 namespace /* private */
1510 {
1511 
1512     /*********************************************
1513      No separate error code if unicode to text
1514      conversion or getenv fails because for the
1515      caller there is no difference why a file
1516      could not be found in $PATH
1517      ********************************************/
1518 
1519     bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result)
1520     {
1521         bool          bfound = false;
1522         rtl::OUString path   = rtl::OUString::createFromAscii("PATH");
1523         rtl::OUString env_path;
1524 
1525         if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData))
1526             bfound = osl::searchPath(file_path, env_path, result);
1527 
1528         return bfound;
1529     }
1530 
1531     /*********************************************
1532      No separate error code if unicode to text
1533      conversion or getcwd fails because for the
1534      caller there is no difference why a file
1535      could not be found in CDW
1536      ********************************************/
1537 
1538     bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result)
1539     {
1540         bool bfound = false;
1541         rtl::OUString cwd_url;
1542 
1543         if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
1544         {
1545             rtl::OUString cwd;
1546             FileBase::getSystemPathFromFileURL(cwd_url, cwd);
1547             bfound = osl::searchPath(file_path, cwd, result);
1548         }
1549         return bfound;
1550     }
1551 
1552     /*********************************************
1553 
1554      ********************************************/
1555 
1556     bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result)
1557     {
1558         return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result));
1559     }
1560 
1561 } // end namespace private
1562 
1563 
1564 /****************************************************************************
1565  *  osl_searchFileURL
1566  ***************************************************************************/
1567 
1568 oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL)
1569 {
1570     OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter");
1571 
1572     FileBase::RC  rc;
1573     rtl::OUString file_path;
1574 
1575     // try to interpret search path as file url else assume it's a system path list
1576     rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path);
1577     if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc))
1578         file_path = ustrFilePath;
1579     else if (FileBase::E_None != rc)
1580         return oslFileError(rc);
1581 
1582     bool          bfound = false;
1583     rtl::OUString result;
1584 
1585     if (find_in_searchPath(file_path, ustrSearchPath, result) ||
1586         find_in_PATH(file_path, result) ||
1587         find_in_CWD(file_path, result))
1588     {
1589         rtl::OUString resolved;
1590 
1591         if (osl::realpath(result, resolved))
1592         {
1593 #if OSL_DEBUG_LEVEL > 0
1594             oslFileError osl_error =
1595 #endif
1596                 osl_getFileURLFromSystemPath(resolved.pData, pustrURL);
1597             OSL_ASSERT(osl_File_E_None == osl_error);
1598             bfound = true;
1599         }
1600     }
1601     return bfound ? osl_File_E_None : osl_File_E_NOENT;
1602 }
1603 
1604 
1605 /****************************************************************************
1606  * FileURLToPath
1607  ***************************************************************************/
1608 
1609 oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL)
1610 {
1611     rtl_uString* ustrSystemPath = NULL;
1612     oslFileError osl_error      = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath);
1613 
1614     if(osl_File_E_None != osl_error)
1615         return osl_error;
1616 
1617     osl_systemPathRemoveSeparator(ustrSystemPath);
1618 
1619     /* convert unicode path to text */
1620     if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length))
1621         osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
1622 
1623     rtl_uString_release(ustrSystemPath);
1624 
1625     return osl_error;
1626 }
1627