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