/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



#include <ctype.h>
#include "system.h"

#ifndef _LIMITS_H
#include <limits.h>
#endif

#ifndef _ERRNO_H
#include <errno.h>
#endif

#ifndef _STDLIB_H_
#include <stdlib.h>
#endif

#ifndef _STRINGS_H
#include <strings.h>
#endif

#ifndef _UNISTD_H
#include <unistd.h>
#endif
#include <osl/file.h>
#include <osl/security.h>
#include <rtl/uri.h>
#include <osl/diagnose.h>
#include <rtl/ustring.hxx>
#include <rtl/ustrbuf.h>

#ifndef _OSL_TREAD_H_
#include <osl/thread.h>
#endif
#include <osl/file.hxx>
#include <osl/mutex.h>
#include <osl/process.h>
#include "file_error_transl.h"

#ifndef _FILE_URL_H_
#include "file_url.h"
#endif
#include "file_path_helper.hxx"
 
#ifndef _OSL_UUNXAPI_HXX_
#include "uunxapi.hxx"
#endif

#include <wchar.h>
#include <wctype.h>

/***************************************************
 
 General note
 
 This file contains the part that handles File URLs.
 
 File URLs as scheme specific notion of URIs 
 (RFC2396) may be handled platform independend, but
 will not in osl which is considered wrong.
 Future version of osl should handle File URLs this
 way. In rtl/uri there is already an URI parser etc.
 so this code should be consolidated.
 
 **************************************************/
 
oslMutex g_CurrentDirectoryMutex;
 
 
/***************************************************
 * forward
 **************************************************/
 
void _osl_warnFile(const char*, rtl_uString*);
rtl_uString*  oslMakeUStrFromPsz(const sal_Char* pszStr,rtl_uString** uStr);
 
extern "C" int UnicodeToText(char *, size_t, const sal_Unicode *, sal_Int32);
extern "C" int TextToUnicode(const char* text, size_t text_buffer_size, sal_Unicode* unic_text, sal_Int32 unic_text_buffer_size);

#define CHAR_POINTER(THE_OUSTRING) ::rtl::OUStringToOString (THE_OUSTRING, RTL_TEXTENCODING_UTF8).pData->buffer

/***************************************************
 * namespace directives
 **************************************************/
 
using namespace osl;

/******************************************************************************
 *
 *                  Exported Module Functions
 *
 *****************************************************************************/

/* a slightly modified version of Pchar in rtl/source/uri.c */
const sal_Bool uriCharClass[128] =  
{ 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./  */
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */
  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0  /* pqrstuvwxyz{|}~  */
};


/* check for top wrong usage strings */
/*
static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len )
{
    rtl_uString *pTmp = NULL;
    sal_Bool bRet;
    
    rtl_uString_newFromStr_WithLength( &pTmp, path, len );
    
    rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length );
        
    bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) ||
           ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) ||
           ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) ||
           ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) ||
           ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) );
           
    rtl_uString_release( pTmp );
    return bRet;
}
*/


/****************************************************************************/
/*	osl_getFileURLFromSystemPath */
/****************************************************************************/

BOOL WINAPI IsValidFilePathComponent(
	LPCTSTR lpComponent, LPCTSTR *lppComponentEnd, DWORD dwFlags)
{
	LPCTSTR	lpComponentEnd = NULL;
	LPCTSTR	lpCurrent = lpComponent;
	BOOL	fValid = TRUE;	/* Assume success */
	TCHAR	cLast = 0;

	/* Path component length must not exceed MAX_PATH */

	while ( !lpComponentEnd && lpCurrent && lpCurrent - lpComponent < _MAX_PATH )
	{
		switch ( *lpCurrent )
		{
			/* Both backslash and slash determine the end of a path component */
		case '\0':
		case '/':
		case '\\':
			switch ( cLast )
			{
				/* Component must not end with '.' or blank and can't be empty */

			case '.':
				if ( dwFlags & VALIDATEPATH_ALLOW_ELLIPSE )
				{
					if ( 1 == lpCurrent - lpComponent )
					{
						/* Current directory is O.K. */
						lpComponentEnd = lpCurrent;
						break;
					}
					else if ( 2 == lpCurrent - lpComponent && '.' == *lpComponent )
					{
						/* Parent directory is O.K. */
						lpComponentEnd = lpCurrent;
						break;
					}
				}
			case 0:
			case ' ':
				lpComponentEnd = lpCurrent - 1;
				fValid = FALSE;
				break;
			default:
				lpComponentEnd = lpCurrent;
				break;
			}
			break;
			/* '?' and '*' are valid wildcards but not valid file name characters */
		case '?':
		case '*':
			if ( dwFlags & VALIDATEPATH_ALLOW_WILDCARDS )
				break;
			/* The following characters are reserved */
		case '<':
		case '>':
		case '\"':
		case '|':
		case ':':
			lpComponentEnd = lpCurrent;
			fValid = FALSE;
			break;
		default:
			/* Characters below ASCII 32 are not allowed */
			if ( *lpCurrent < ' ' )
			{
				lpComponentEnd = lpCurrent;
				fValid = FALSE;
			}
			break;
		}
		cLast = *lpCurrent++;
	}

	/*	If we don't reached the end of the component the length of the component was to long 
		( See condition of while loop ) */
	if ( !lpComponentEnd )
	{
		fValid = FALSE;
		lpComponentEnd = lpCurrent;
	}

	/* Test wether the component specifies a device name what is not allowed */
	
	// MT: PERFORMANCE: 
	// This is very expensive. A lot of calls to _tcsicmp.
	// in SRC6870m71 67.000 calls of this method while empty office start result into more than 1.500.00 calls of _tcsicmp!
	// Possible optimizations
	// - Array should be const static
	// - Sorted array, use binary search
	// - More intelligent check for com1-9, lpt1-9
	// Maybe make szComponent upper case, don't search case intensitive
	// 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.
	/*
	if ( fValid )
	{
		LPCTSTR	alpDeviceNames[] =
		{
			TEXT("CON"),
			TEXT("PRN"),
			TEXT("AUX"),
			TEXT("CLOCK$"),
			TEXT("NUL"),
			TEXT("LPT1"),
			TEXT("LPT2"),
			TEXT("LPT3"),
			TEXT("LPT4"),
			TEXT("LPT5"),
			TEXT("LPT6"),
			TEXT("LPT7"),
			TEXT("LPT8"),
			TEXT("LPT9"),
			TEXT("COM1"),
			TEXT("COM2"),
			TEXT("COM3"),
			TEXT("COM4"),
			TEXT("COM5"),
			TEXT("COM6"),
			TEXT("COM7"),
			TEXT("COM8"),
			TEXT("COM9")
		};
		
		TCHAR	szComponent[MAX_PATH];
		int		nComponentLength;
		LPCTSTR	lpDot;
		int		i;

		// A device name with an extension is also invalid
		lpDot = _tcschr( lpComponent, '.' );

		if ( !lpDot || lpDot > lpComponentEnd )
			nComponentLength = lpComponentEnd - lpComponent;
		else
			nComponentLength = lpDot - lpComponent;

		_tcsncpy( szComponent, lpComponent, nComponentLength );
		szComponent[nComponentLength] = 0;

		for ( i = 0; i < sizeof( alpDeviceNames ) / sizeof(LPCTSTR); i++ )
		{
			if ( 0 == _tcsicmp( szComponent, alpDeviceNames[i] ) )
			{
				lpComponentEnd = lpComponent;
				fValid = FALSE;
				break;
			}
		}
	}
	*/

	if ( fValid )
	{
		// Empty components are not allowed
		if ( lpComponentEnd - lpComponent < 1 )
			fValid = FALSE;

		// If we reached the end of the string NULL is returned
		else if ( !*lpComponentEnd )
			lpComponentEnd = NULL;

	}

	if ( lppComponentEnd )
		*lppComponentEnd = lpComponentEnd;

	return fValid;
}

//##################################################### 
DWORD WINAPI IsValidFilePath(LPCTSTR lpszPath, LPCTSTR *lppError, DWORD dwFlags)
{
	LPCTSTR	lpComponent;
	BOOL	fValid = TRUE;
	DWORD	dwPathType = PATHTYPE_ERROR;

	if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
		dwFlags |= VALIDATEPATH_ALLOW_ELLIPSE;

	if ( !lpszPath )
	{
		fValid = FALSE;
		lpComponent = lpszPath;
	}

	/* Test for UNC path notation */
	if ( 2 == _tcsspn( lpszPath, CHARSET_SEPARATOR ) )
	{
		/* Place the pointer behind the leading to backslashes */

		lpComponent = lpszPath + 2;

		fValid = IsValidFilePathComponent( lpComponent, &lpComponent, VALIDATEPATH_ALLOW_ELLIPSE );

		/* So far we have a valid servername. Now let's see if we also have a network resource */

		dwPathType = PATHTYPE_ABSOLUTE_UNC;

		if ( fValid )
		{
			if ( lpComponent &&	 !*++lpComponent )
				lpComponent = NULL;
			
			if ( !lpComponent )
			{
#if 0
				/* We only have a Server specification what is invalid */

				lpComponent = lpszPath;
				fValid = FALSE;
#else
				dwPathType |= PATHTYPE_IS_SERVER;
#endif
			}
			else
			{
				/* Now test the network resource */

				fValid = IsValidFilePathComponent( lpComponent, &lpComponent, 0 );

				/* If we now reached the end of the path, everything is O.K. */


				if ( fValid && (!lpComponent || lpComponent && !*++lpComponent ) )
				{
					lpComponent = NULL;
					dwPathType |= PATHTYPE_IS_VOLUME;
				}
			}
		}
	}

	/* Local path verification. Must start with <drive>: */
	else if ( _istalpha( lpszPath[0] ) && ':' == lpszPath[1] )
	{
		/* Place pointer behind correct drive specification */

		lpComponent = lpszPath + 2;

		if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) )
			lpComponent++;
		else if ( *lpComponent )
			fValid = FALSE;

		dwPathType = PATHTYPE_ABSOLUTE_LOCAL;

		/* Now we are behind the backslash or it was a simple drive without backslash */

		if ( fValid && !*lpComponent )
		{
			lpComponent = NULL;
			dwPathType |= PATHTYPE_IS_VOLUME;
		}
	}

	/* Can be a relative path */
	else if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE )
	{
		lpComponent = lpszPath;

		/* Relative path can start with a backslash */

		if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) )
		{
			lpComponent++;
			if ( !*lpComponent )
				lpComponent = NULL;
		}

		dwPathType = PATHTYPE_RELATIVE;
	}

	/* Anything else is an error */
	else
	{
		fValid = FALSE;
		lpComponent = lpszPath;
	}

	/* Now validate each component of the path */
	while ( fValid && lpComponent )
	{
		fValid = IsValidFilePathComponent( lpComponent, &lpComponent, dwFlags );

		if ( fValid && lpComponent )
		{
			lpComponent++;

			/* If the string behind the backslash is empty, we've done */

			if ( !*lpComponent )
				lpComponent = NULL;
		}
	}
	
	if ( fValid && _tcslen( lpszPath ) >= _MAX_PATH )
	{
		fValid = FALSE;
		lpComponent = lpszPath + _MAX_PATH;
	}

	if ( lppError )
		*lppError = lpComponent;

	return fValid ? dwPathType : PATHTYPE_ERROR;
}

sal_Bool _osl_decodeURL( rtl_String* strUTF8, rtl_uString** pstrDecodedURL )
{
	sal_Char		*pBuffer;
	const sal_Char	*pSrcEnd;
	const sal_Char	*pSrc;
	sal_Char		*pDest;
	sal_Int32		nSrcLen;
	sal_Bool		bValidEncoded = sal_True;	/* Assume success */

	/* The resulting decoded string length is shorter or equal to the source length */

	nSrcLen = rtl_string_getLength(strUTF8);
	pBuffer = reinterpret_cast<sal_Char*>(rtl_allocateMemory(nSrcLen + 1));

	pDest = pBuffer;
	pSrc = rtl_string_getStr(strUTF8);
	pSrcEnd = pSrc + nSrcLen;

	/* Now decode the URL what should result in an UTF8 string */
	while ( bValidEncoded && pSrc < pSrcEnd )
	{
		switch ( *pSrc )
		{
		case '%':
			{
				sal_Char	aToken[3];
				sal_Char	aChar;

				pSrc++;
				aToken[0] = *pSrc++;
				aToken[1] = *pSrc++;
				aToken[2] = 0;

				aChar = (sal_Char)strtoul( aToken, NULL, 16 );

				/* The chars are path delimiters and must not be encoded */

				if ( 0 == aChar || '\\' == aChar || '/' == aChar || ':' == aChar )
					bValidEncoded = sal_False;
				else
					*pDest++ = aChar;
			}
			break;
		default:
			*pDest++ = *pSrc++;
			break;
		}
	}

	*pDest++ = 0;
	
	if ( bValidEncoded ) {
		rtl_string2UString( pstrDecodedURL, pBuffer, rtl_str_getLength(pBuffer), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );
		OSL_ASSERT(*pstrDecodedURL != 0);
	}
	
	rtl_freeMemory( pBuffer );

	return bValidEncoded;
}

//############################################# 
void _osl_encodeURL( rtl_uString *strURL, rtl_String **pstrEncodedURL )
{
	/* Encode non ascii characters within the URL */

	rtl_String		*strUTF8 = NULL;
	sal_Char		*pszEncodedURL;
	const sal_Char	*pURLScan;
	sal_Char		*pURLDest;
	sal_Int32		nURLScanLen;
	sal_Int32		nURLScanCount;
	
	rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );

	pszEncodedURL = (sal_Char*) rtl_allocateMemory( (rtl_string_getLength( strUTF8 ) * 3 + 1)  * sizeof(sal_Char) );

	pURLDest = pszEncodedURL;
	pURLScan = rtl_string_getStr( strUTF8 );
	nURLScanLen = rtl_string_getLength( strUTF8 );
	nURLScanCount = 0;

	while ( nURLScanCount < nURLScanLen )
	{
		sal_Char	cCurrent = *pURLScan;

		switch ( cCurrent )
		{
		default:
			if (!( ( cCurrent >= 'a' && cCurrent <= 'z' ) || ( cCurrent >= 'A' && cCurrent <= 'Z' ) || ( cCurrent >= '0' && cCurrent <= '9' ) ) )
			{
				sprintf( pURLDest, "%%%02X", (unsigned char)cCurrent );
				pURLDest += 3;
				break;
			}
		case '!':
		case '\'':
		case '(':
		case ')':
		case '*':
		case '-':
		case '.':
		case '_':
		case '~':
		case '$':
		case '&':
		case '+':
		case ',':
		case '=':
		case '@':
		case ':':
		case '/':
		case '\\':
		case '|':
			*pURLDest++ = cCurrent;
			break;
		case 0:
			break;
		}

		pURLScan++;
		nURLScanCount++;
	}


	*pURLDest = 0;	    

	rtl_string_release( strUTF8 );        	  
	rtl_string_newFromStr( pstrEncodedURL, pszEncodedURL );	    
	rtl_freeMemory( pszEncodedURL );
}

//#############################################      
oslFileError SAL_CALL _osl_getFileURLFromSystemPath( rtl_uString* strPath, rtl_uString** pstrURL )
{
	oslFileError nError = osl_File_E_INVAL; /* Assume failure */
	rtl_uString	*strTempURL = NULL;
	DWORD dwPathType = PATHTYPE_ERROR;

	if (strPath)
		dwPathType = IsValidFilePath(strPath->buffer, NULL, VALIDATEPATH_ALLOW_RELATIVE);
			
	if (dwPathType)
	{
		rtl_uString	*strTempPath = NULL;

		/* Replace backslashes */

		rtl_uString_newReplace( &strTempPath, strPath, '\\', '/' );

		switch ( dwPathType & PATHTYPE_MASK_TYPE )
		{
		case PATHTYPE_RELATIVE:
			rtl_uString_assign( &strTempURL, strTempPath );
			nError = osl_File_E_None;
			break;
		case PATHTYPE_ABSOLUTE_UNC:
			rtl_uString_newFromAscii( &strTempURL, "file:" );
			rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath );
			nError = osl_File_E_None;
			break;
		case PATHTYPE_ABSOLUTE_LOCAL:
			rtl_uString_newFromAscii( &strTempURL, "file:///" );
			rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath );
			nError = osl_File_E_None;
			break;
		default:
			break;
		}

		/* Release temp path */

		rtl_uString_release( strTempPath );
	}

	if ( osl_File_E_None == nError )
	{
		rtl_String	*strEncodedURL = NULL;

		/* Encode the URL */

		_osl_encodeURL( strTempURL, &strEncodedURL );

		/* Provide URL via unicode string */

		rtl_string2UString( pstrURL, rtl_string_getStr(strEncodedURL), rtl_string_getLength(strEncodedURL), RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS );
		OSL_ASSERT(*pstrURL != 0);
		rtl_string_release( strEncodedURL );
	}

	/* Release temp URL */

	if ( strTempURL )
		rtl_uString_release( strTempURL );

	/*
	OSL_ENSURE_FILE( !nError, "osl_getFileURLFromSystemPath: \"%s\" is not a systemPath !!!", strPath );
	*/

	return nError;
}

oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL )
{
	return _osl_getFileURLFromSystemPath( ustrSystemPath, pustrFileURL );
#if 0	
    static const sal_Unicode pDoubleSlash[2] = { '/', '/' };
    
    rtl_uString *pTmp = NULL;
    sal_Int32 nIndex;

    if( 0 == ustrSystemPath->length )
        return osl_File_E_INVAL;

	/* YD convert '\' to '/' */
	rtl_ustr_replaceChar( ustrSystemPath->buffer, '\\', '/' );
	
    /* temporary hack: if already file url, return ustrSystemPath */
    if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) )
    {
	/*
        if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) )
        {
            OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" );
            rtl_uString_assign( pustrFileURL, ustrSystemPath );
        }
        else
        {
            rtl_uString *pTmp2 = NULL;

            OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" );
            rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 );
            rtl_uString_newFromAscii( &pTmp2, "file://" );
            rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 );
            rtl_uString_release( pTmp2 );
        }
        return osl_File_E_None;
		*/
		return osl_File_E_INVAL;
    }
	
        
    /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
    if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] )
    {
        /* check if another user is specified */
        if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) )
        {
            /* osl_getHomeDir returns file URL */
            osl_getHomeDir( osl_getCurrentSecurity(), &pTmp );

            /* remove "file://" prefix */
            rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 );

            /* replace '~' in original string */             
            rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp );
        }

        else
        {
            /* FIXME: replace ~user with users home directory */
            return osl_File_E_INVAL;
        }
    }
    
    /* check if initial string contains double instances of '/' */ 
    nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 );
    if( -1 != nIndex )
    {
        sal_Int32 nSrcIndex;
        sal_Int32 nDeleted = 0;
        
        /* if pTmp is not already allocated, copy ustrSystemPath for modification */
        if( NULL == pTmp )
            rtl_uString_newFromString( &pTmp, ustrSystemPath );
        
        /* adapt index to pTmp */
        nIndex += pTmp->length - ustrSystemPath->length;
        
        /* remove all occurances of '//' */
        for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ )
        {
            if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) )
                nDeleted++;
            else
                pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex];
        }
        
        /* adjust length member */
        pTmp->length -= nDeleted;
    }               
    
    if( NULL == pTmp )
        rtl_uString_assign( &pTmp, ustrSystemPath ); 

    /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */
	/*
    OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
	*/
        
    /* file URLs must be URI encoded */
    rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL );
    
    rtl_uString_release( pTmp );    
    
    /* absolute urls should start with 'file://' */
    if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] )
    {
        rtl_uString *pProtocol = NULL;
        
        rtl_uString_newFromAscii( &pProtocol, "file://" );
        rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL );
        rtl_uString_release( pProtocol );
    }

    return osl_File_E_None;
#endif
}

//#############################################      
oslFileError SAL_CALL _osl_getSystemPathFromFileURL( rtl_uString *strURL, rtl_uString **pustrPath, sal_Bool bAllowRelative )
{
	rtl_String			*strUTF8 = NULL;
	rtl_uString			*strDecodedURL = NULL;
	rtl_uString			*strTempPath = NULL;
	const sal_Unicode	*pDecodedURL;
	sal_uInt32			nDecodedLen;
	sal_Bool			bValidEncoded;
	oslFileError		nError = osl_File_E_INVAL;	/* Assume failure */

	/*  If someone hasn't encoded the complete URL we convert it to UTF8 now to prevent from
		having a mixed encoded URL later */

	rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS );

	/* If the length of strUTF8 and strURL differs it indicates that the URL was not correct encoded */

	OSL_ENSURE_FILE( 
		strUTF8->length == strURL->length || 
		0 != rtl_ustr_ascii_shortenedCompare_WithLength( strURL->buffer, strURL->length, "file:\\\\", 7 )
		,"osl_getSystemPathFromFileURL: \"%s\" is not encoded !!!", strURL );

	bValidEncoded = _osl_decodeURL( strUTF8, &strDecodedURL );

	/* Release the encoded UTF8 string */

	rtl_string_release( strUTF8 );


	if ( bValidEncoded )
	{
		/* Replace backslashes and pipes */

		rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '/', '\\' );
		rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '|', ':' );

		pDecodedURL = rtl_uString_getStr( strDecodedURL );
		nDecodedLen = rtl_uString_getLength( strDecodedURL );

		/* Must start with "file://" */

		if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\", 7 ) )
		{
			sal_uInt32	nSkip;

			if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\\\", 8 ) )
				nSkip = 8;
			else if ( 
				0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\localhost\\", 17 ) ||
				0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\127.0.0.1\\", 17 ) 
			)
				nSkip = 17;
			else 
				nSkip = 7;

			/* Indicates local root */
			if ( nDecodedLen == nSkip )
				rtl_uString_newFromStr_WithLength( &strTempPath, (const sal_Unicode*)WSTR_SYSTEM_ROOT_PATH, ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1 );
			else
				rtl_uString_newFromStr_WithLength( &strTempPath, pDecodedURL + nSkip, nDecodedLen - nSkip );

			if ( IsValidFilePath( strTempPath->buffer, NULL, VALIDATEPATH_ALLOW_ELLIPSE ) )
				nError = osl_File_E_None;
		}
		else if ( bAllowRelative )	/* This maybe a relative file URL */
		{
			rtl_uString_assign( &strTempPath, strDecodedURL );

			if ( IsValidFilePath( strTempPath->buffer, NULL, VALIDATEPATH_ALLOW_RELATIVE | VALIDATEPATH_ALLOW_ELLIPSE ) )
				nError = osl_File_E_None;
		}
	/*
		else
			OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not an absolute FileURL !!!", strURL );
	 */

	}
	
	if ( strDecodedURL )
		rtl_uString_release( strDecodedURL );
		
	if ( osl_File_E_None == nError )
		rtl_uString_assign( pustrPath, strTempPath );
  
	if ( strTempPath )
		rtl_uString_release( strTempPath );

	/*
	OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not a FileURL !!!", strURL );
	*/

	return nError;
}

/****************************************************************************/
/*	osl_getSystemPathFromFileURL */
/****************************************************************************/

oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath )
{
	return _osl_getSystemPathFromFileURL( ustrFileURL, pustrSystemPath, sal_True );
#if 0
    sal_Int32 nIndex = 0;
    rtl_uString * pTmp = NULL;

    sal_Unicode encodedSlash[3] = { '%', '2', 'F' };

    /* temporary hack: if already system path, return ustrFileURL */
	/*
    if( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) 
    {
        OSL_ENSURE( 0, "osl_getSystemPathFromFileURL: input is already system path" );
        rtl_uString_assign( pustrSystemPath, ustrFileURL );
        return osl_File_E_None;
    }
	*/
        
    /* a valid file url may not start with '/' */
    if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) )
    {
        return osl_File_E_INVAL;
    }

    /* search for encoded slashes (%2F) and decode every single token if we find one */
    if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) )
    {
        rtl_uString * ustrPathToken = NULL;
        sal_Int32 nOffset = 7;
        
        do
        {
            nOffset += nIndex;

            /* break url down in '/' devided tokens tokens */
            nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, (sal_Unicode) '/' );
            
            /* copy token to new string */
            rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset, 
                -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ );

            /* decode token */
            rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
            
            /* the result should not contain any '/' */
            if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, (sal_Unicode) '/' ) )
            {
                rtl_uString_release( pTmp );
                rtl_uString_release( ustrPathToken );

                return osl_File_E_INVAL;
            }
                
        } while( -1 != nIndex );

        /* release temporary string and restore index variable */
        rtl_uString_release( ustrPathToken );
        nIndex = 0;        
    }
 
    /* protocol and server should not be encoded, so decode the whole string */
    rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
    
    /* check if file protocol specified */    
    /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
    if( 7 <= pTmp->length )
    {
        rtl_uString * pProtocol = NULL;
        rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 );
        
        /* protocol is case insensitive */
        rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length );
        
        if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) )
            nIndex = 7;
            
        rtl_uString_release( pProtocol );
    }
     
    /* skip "localhost" or "127.0.0.1" if "file://" is specified */
    /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
    if( nIndex && ( 10 <= pTmp->length - nIndex ) )
    {
        rtl_uString * pServer = NULL;
        rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 );

        /* server is case insensitive */
        rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length );
        
        if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) ||
            ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) )
        {
            /* don't exclude the '/' */
            nIndex += 9;
        }

        rtl_uString_release( pServer );
    }
                
    if( nIndex )
        rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex );

    /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
    if( (sal_Unicode) '~' == pTmp->buffer[0] )
    {
        /* check if another user is specified */
        if( ( 1 == pTmp->length ) || ( (sal_Unicode)'/' == pTmp->buffer[1] ) )
        {
            rtl_uString *pTmp2 = NULL;

            /* osl_getHomeDir returns file URL */
            osl_getHomeDir( osl_getCurrentSecurity(), &pTmp2 );

            /* remove "file://" prefix */
            rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 );

            /* replace '~' in original string */             
            rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 );
            rtl_uString_release( pTmp2 );
        }

        else
        {
            /* FIXME: replace ~user with users home directory */
            return osl_File_E_INVAL;
        }
    }

    /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */
	/*
    OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
	*/
        
    *pustrSystemPath = pTmp;
    return osl_File_E_None;
#endif // 0
}

		
/****************************************************************************
 * osl_getSystemPathFromFileURL_Ex - helper function                          
 * clients may specify if they want to accept relative                      
 * URLs or not                                                              
 ****************************************************************************/

oslFileError osl_getSystemPathFromFileURL_Ex(
    rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative)
{
	return _osl_getSystemPathFromFileURL( ustrFileURL, pustrSystemPath, bAllowRelative);
#if 0
	rtl_uString* temp = 0;
    oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp);
    
    if (osl_File_E_None == osl_error)
    {
    	if (bAllowRelative
    	    || (UNICHAR_SLASH == temp->buffer[0])
    	    || (UNICHAR_COLON == temp->buffer[1] && UNICHAR_SLASH == temp->buffer[2]))
        {
            *pustrSystemPath = temp;
        }
        else
        {
            rtl_uString_release(temp);
            osl_error = osl_File_E_INVAL;                  
        }
    }
    
    return osl_error;
#endif
}

namespace /* private */
{

#if 0 // YD

	/******************************************************
	 * Helper function, return a pinter to the final '\0'
	 * of a string
	 ******************************************************/
 
	sal_Unicode* ustrtoend(sal_Unicode* pStr)
	{		
		return (pStr + rtl_ustr_getLength(pStr));
	}
	
	/*********************************************

	 ********************************************/
	sal_Unicode* ustrcpy(const sal_Unicode* s, sal_Unicode* d)
	{
		const sal_Unicode* sc = s;
		sal_Unicode*       dc = d;
		
		while ((*dc++ = *sc++))
			/**/;
			
		return d;
	}
	
	/*********************************************

	 ********************************************/
	 
	sal_Unicode* ustrncpy(const sal_Unicode* s, sal_Unicode* d, unsigned int n)
	{
		const sal_Unicode* sc = s;
		sal_Unicode*       dc = d;
		unsigned int       i  = n;		
		
		while (i--)	
			*dc++ = *sc++;
		
		if (n)
			*dc = 0;
			
		return d;
	}
	
	/*********************************************

	 ********************************************/
	 
	sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d)
	{
		sal_Unicode* p = ustrtoend(d);
		*p++ = chr;
		*p   = 0;		
		return d;	
	}

	/*********************************************

	 ********************************************/
	 
	sal_Unicode* ustrcat(const sal_Unicode* s, sal_Unicode* d)
	{
		sal_Unicode* dc = ustrtoend(d);					
		ustrcpy(s, dc);		
		return d;
	}	

	/******************************************************
	 *
	 ******************************************************/
 
	bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr)
	{
   		sal_Unicode* p = ustrtoend(pStr);
	   	if (p > pStr)
       		p--;
	   	return (*p == Chr);  
	}

	/******************************************************
	 * Ensure that the given string has the specified last 
	 * character if necessary append it
	 ******************************************************/
 
	sal_Unicode* _strensurelast(sal_Unicode* pStr, sal_Unicode Chr)
	{
    	if (!_islastchr(pStr, Chr))
        	ustrchrcat(Chr, pStr);
	    return pStr;
	}	

	/******************************************************
	 * Remove the last part of a path, a path that has 
	 * only a '/' or no '/' at all will be returned
	 * unmodified 
	 ******************************************************/
 
	sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath)
	{
		/* 	we always may skip -2 because we
	   		may at least stand on a '/' but
		   	either there is no other character
		   	before this '/' or it's another 
	   		character than the '/' 
		*/
		sal_Unicode* p = ustrtoend(aPath) - 2;

		// move back to the next path separator
		// or to the start of the string
		while ((p > aPath) && (*p != UNICHAR_SLASH))
			p--;

		if (p >= aPath)
		{
    		if (UNICHAR_SLASH == *p)
    		{
				p++;
			   *p = '\0';
    		}
    		else
    		{
		   		*p = '\0';
    		}
		}
    
	    return aPath;
	}

	/******************************************************
	 * 
	 ******************************************************/
 
	oslFileError _osl_resolvepath(
    	/*inout*/ sal_Unicode* path, 
	    /*inout*/ sal_Unicode* current_pos, 
	    /*in   */ sal_Unicode* sentinel, 
    	/*inout*/ bool* failed)
	{
    	oslFileError ferr = osl_File_E_None;
    
	    if (!*failed)
    	{
			char unresolved_path[PATH_MAX];			
			if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path)))
				return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
				
			char resolved_path[PATH_MAX];			
		    if (realpath(unresolved_path, resolved_path))
			{
				if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX))		
					return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
					
				current_pos = ustrtoend(path) - 1;	    					
			}
			else
			{
				if (EACCES == errno || ENOTDIR == errno || ENOENT == errno)
					*failed = true;
				else
					ferr = oslTranslateFileError(OSL_FET_ERROR, errno);
			}
    	}
		
	    return ferr;
	}	

	/******************************************************
	 * Works even with non existing paths. The resulting 
	 * path must not exceed PATH_MAX else 
	 * osl_File_E_NAMETOOLONG is the result
	 ******************************************************/
 
	oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path)
	{
		// the given unresolved path must not exceed PATH_MAX 
	    if (unresolved_path.getLength() >= (PATH_MAX - 2))
    	    return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
		
	    sal_Unicode        path_resolved_so_far[PATH_MAX];	    
	    const sal_Unicode* punresolved = unresolved_path.getStr(); 
		sal_Unicode*       presolvedsf = path_resolved_so_far;
    
	    // reserve space for leading '/' and trailing '\0'
	    // do not exceed this limit 
    	sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2; 
    
	    // if realpath fails with error ENOTDIR, EACCES or ENOENT
	    // we will not call it again, because _osl_realpath should also
    	// work with non existing directories etc. 
	    bool realpath_failed = false;
    	oslFileError ferr;
              
	    path_resolved_so_far[0] = '\0';
    
    	while (*punresolved != '\0')
    	{
        	// ignore '/.' , skip one part back when '/..' 
	
	        if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf))
    	    {            
        	    if ('\0' == *(punresolved + 1))
            	{
                	punresolved++;
	                continue;
    	        }
        	    else if (UNICHAR_SLASH == *(punresolved + 1))
            	{
                	punresolved += 2;
	                continue;
    	        }            
        	    else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2))))
            	{                
                	_rmlastpathtoken(path_resolved_so_far);
                
	                presolvedsf = ustrtoend(path_resolved_so_far) - 1;
                
    	            if (UNICHAR_SLASH == *(punresolved + 2))
        	            punresolved += 3;
            	    else
                	    punresolved += 2;
                    
	                continue;
    	        }                    
        	    else // a file or directory name may start with '.' 
            	{
                	if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
                    	return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
                    
	                ustrchrcat(*punresolved++, path_resolved_so_far); 
                
    	            if ('\0' == *punresolved && !realpath_failed)
        	        {
						ferr = _osl_resolvepath(
							path_resolved_so_far, 
							presolvedsf, 
							sentinel, 
							&realpath_failed);
					
						if (osl_File_E_None != ferr)
			    			return ferr;
            	    }
            	}
        	}
	        else if (UNICHAR_SLASH == *punresolved)
    	    {  
				if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
            	    return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
                        
	            ustrchrcat(*punresolved++, path_resolved_so_far); 
            
    	        if (!realpath_failed)
        	    {                
            	    ferr = _osl_resolvepath(
						path_resolved_so_far, 
						presolvedsf, 
						sentinel, 
						&realpath_failed);
		    
					if (osl_File_E_None != ferr)
						return ferr;
				
					if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH))
					{
	    				if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
							return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
					
						ustrchrcat(UNICHAR_SLASH, path_resolved_so_far); 
					}
            	}
        	}
	        else // any other character
    	    {
        	    if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
            	    return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
                
	            ustrchrcat(*punresolved++, path_resolved_so_far); 
            
    	        if ('\0' == *punresolved && !realpath_failed)
        	    {            
            	    ferr = _osl_resolvepath(
						path_resolved_so_far, 
						presolvedsf, 
						sentinel, 
						&realpath_failed);
		    
					if (osl_File_E_None != ferr)
						return ferr;
            	}
        	}
    	}

		sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far);
		
	    OSL_ASSERT(len < PATH_MAX);
        
    	resolved_path = rtl::OUString(path_resolved_so_far, len);
		
	    return osl_File_E_None;
	}

#endif // 0 // YD

} // end namespace private

#if OSL_DEBUG_LEVEL > 0

    //##################################################### 
    void _osl_warnFile( const char *message, rtl_uString *ustrFile )
    {
	    char szBuffer[2048];

	    if (ustrFile)
	    {
		    rtl_String	*strFile = NULL;

		    rtl_uString2String( &strFile, rtl_uString_getStr( ustrFile ), rtl_uString_getLength( ustrFile ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
		    snprintf( szBuffer, sizeof(szBuffer), message, strFile->buffer );
		    rtl_string_release( strFile );

		    message = szBuffer;
	    }
	    OSL_ENSURE( 0, message );
    }

#endif // OSL_DEBUG_LEVEL > 0

/******************************************************
 * osl_getAbsoluteFileURL
 ******************************************************/
 
//oslFileError osl_getAbsoluteFileURL(rtl_uString*  ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL)
oslFileError SAL_CALL osl_getAbsoluteFileURL( rtl_uString* ustrBaseURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL )
{
	oslFileError	eError;
	rtl_uString		*ustrRelSysPath = NULL;
	rtl_uString		*ustrBaseSysPath = NULL;

	if ( ustrBaseURL && ustrBaseURL->length )
	{
		eError = _osl_getSystemPathFromFileURL( ustrBaseURL, &ustrBaseSysPath, sal_False );
		OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with relative or invalid base URL" );

		eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_True );
	}
	else
	{
		eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_False );
		OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with empty base URL and/or invalid relative URL" );
	}

	if ( !eError )
	{
		CHAR	szBuffer[_MAX_PATH];
		CHAR	szRelSysPath[_MAX_PATH];
		CHAR	szCurrentDir[_MAX_PATH];
		int		result;
		char*	cwd;
		int		rc;

/*@@@ToDo
  Bad, bad hack, this only works if the base path
  really exists which is not necessary according
  to RFC2396
  The whole FileURL implementation should be merged 
  with the rtl/uri class.
*/
		if ( ustrBaseSysPath )
		{
			CHAR	szBaseSysPath[_MAX_PATH];
			
			if (!g_CurrentDirectoryMutex)
				g_CurrentDirectoryMutex = osl_createMutex();

			osl_acquireMutex( g_CurrentDirectoryMutex );

			cwd = getcwd( szCurrentDir, sizeof(szCurrentDir) );
			UnicodeToText( szBaseSysPath, sizeof(szBaseSysPath), ustrBaseSysPath->buffer, ustrBaseSysPath->length);
			rc = chdir( szBaseSysPath);
		}

		UnicodeToText( szRelSysPath, sizeof(szRelSysPath), ustrRelSysPath->buffer, ustrRelSysPath->length);
		result = !_abspath( szBuffer, szRelSysPath, sizeof(szBuffer));

		if ( ustrBaseSysPath )
		{
			rc = chdir( szCurrentDir );

			osl_releaseMutex( g_CurrentDirectoryMutex );
		}

		if ( result )
		{
				rtl_uString	*ustrAbsSysPath = NULL;

				oslMakeUStrFromPsz( szBuffer, &ustrAbsSysPath);

				eError = osl_getFileURLFromSystemPath( ustrAbsSysPath, pustrAbsoluteURL );

				if ( ustrAbsSysPath )
					rtl_uString_release( ustrAbsSysPath );
		}
		else
			eError = osl_File_E_INVAL;
	}

	if ( ustrBaseSysPath )
		rtl_uString_release( ustrBaseSysPath );

	if ( ustrRelSysPath )
		rtl_uString_release( ustrRelSysPath );

	return	eError;
#if 0	
	FileBase::RC  rc;
    rtl::OUString unresolved_path;    
    
    rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path);
    
	if(FileBase::E_None != rc)
        return oslFileError(rc);

    if (systemPathIsRelativePath(unresolved_path))
    {
		rtl::OUString base_path;		
        rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False);

        if (FileBase::E_None != rc)		
            return oslFileError(rc);
		
		rtl::OUString abs_path;				
		systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path);

        unresolved_path = abs_path;        
    }

	rtl::OUString resolved_path;	  
    rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
        
	if (FileBase::E_None == rc)
    {
    	rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL);            
        OSL_ASSERT(FileBase::E_None == rc);            
    }
    
    return oslFileError(rc);
#endif // 0
}  


namespace /* private */
{
						
	/*********************************************
	 No separate error code if unicode to text
	 conversion or getenv fails because for the
	 caller there is no difference why a file
	 could not be found in $PATH 
	 ********************************************/
 
	bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result)
	{	
		bool          bfound = false;		
		rtl::OUString path   = rtl::OUString::createFromAscii("PATH");
		rtl::OUString env_path;
		
		if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData))
			bfound = osl::searchPath(file_path, env_path, result);
		
		return bfound;
	}

	/*********************************************
	 No separate error code if unicode to text
	 conversion or getcwd fails because for the
	 caller there is no difference why a file
	 could not be found in CDW
	 ********************************************/
 
	bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result)
	{		
		bool bfound = false;		
		rtl::OUString cwd_url;
		
		if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
		{
			rtl::OUString cwd;
			FileBase::getSystemPathFromFileURL(cwd_url, cwd);			
			bfound = osl::searchPath(file_path, cwd, result);
		}
		return bfound;
	}
	
	/*********************************************

	 ********************************************/
 
	bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result)
	{
		return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result));
	}

} // end namespace private


/****************************************************************************
 *	osl_searchFileURL 
 ***************************************************************************/
 
oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL)
{
	OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter");
	
	FileBase::RC  rc;
	rtl::OUString file_path;
		
	// try to interpret search path as file url else assume it's a system path list
	rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path);
	if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc))
		file_path = ustrFilePath; 
	else if (FileBase::E_None != rc)
		return oslFileError(rc);

	bool          bfound = false;	
	rtl::OUString result;	
			
	if (find_in_searchPath(file_path, ustrSearchPath, result) || 
	    find_in_PATH(file_path, result) || 
		find_in_CWD(file_path, result))	
    { 
		rtl::OUString resolved;
		
		if (osl::realpath(result, resolved))
		{
#if OSL_DEBUG_LEVEL > 0            
			oslFileError osl_error = 
#endif             
                osl_getFileURLFromSystemPath(resolved.pData, pustrURL);		
			OSL_ASSERT(osl_File_E_None == osl_error);
			bfound = true;
		}
    }    
    return bfound ? osl_File_E_None : osl_File_E_NOENT;
}


/****************************************************************************
 * FileURLToPath 
 ***************************************************************************/

oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL)
{
    rtl_uString* ustrSystemPath = NULL;
    oslFileError osl_error		= osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath);
			
    if(osl_File_E_None != osl_error)
        return osl_error;

	osl_systemPathRemoveSeparator(ustrSystemPath);
	    
    /* convert unicode path to text */
    if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length))
        osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); 
        
    rtl_uString_release(ustrSystemPath);
	
    return osl_error;
}
