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