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