xref: /aoo41x/main/sal/osl/os2/file_url.cxx (revision 87d2adbc)
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