
/*
  File: include/basic/filesys.h
  Description: File system manipulation classes
  Part of the Mantis project
  (c) 2002 Lycos Inc.

  This file is distributed for the sole purpose of allowing you to write
  software to interface with Sonique 2 and other Mantis programs. It is
  not to be modified or used for any other purpose without written
  authorization.

  If you redistribute this file, it must be in the original package
  complete with all other files provided, including the usage agreement.

  Do not remove this notice.
*/

#ifndef _FILESYS_H_
#define _FILESYS_H_

#include "charstring.h"
#include <time.h>

//Get rid of "warning C4200: nonstandard extension used : zero-sized array in struct/union"
#pragma warning( disable: 4200 )


typedef enum IOObjectFlags
{
	// access modes
	access_read		= 0x0001,							// read access
	access_write	= 0x0002,							// write access
	access_all		= (access_read | access_write),		// file has both

	// share modes
 	share_none		= 0x0000,							// others can't touch file
	share_read		= 0x0004,							// others can read
	share_write		= 0x0008,							// others can write
	share_all		= (share_read | share_write),		// others can do both

	// create/open mode
	create_new		= 0x0000,							// only works if file doesn't already exist
	create_always	= 0x0010,							// creates a new file (deletes previous if it already exists)
	open_existing   = 0x0020,							// only works if file exists, (doesn't clear the file)
	open_always		= 0x0030,							// opens the file, creates a new one if necessary

	// hints
	hint_none		= 0x0000,							// no hints, (default)
	hint_random		= 0x0040,							// gives OS hint that the file is accessed randomly 
	hint_sequential	= 0x0080							// gives OS hint that the file is accessed sequentially
}IOObjectFlags;
typedef enum IOObjectType
{
	objecttype_unknown		=	0x0000,
	objecttype_memory		=	0x0001,
	objecttype_file			=	0x0002,
	objecttype_directory	=	0x0003
}IOObjectType;

typedef enum IOObjectSeekModes
{
	seek_set	= 0, // seek from start
	seek_start  = 0, // seek from start
	seek_begin  = 0, // seek from start
	seek_end	= 1, // seek from end
	seek_cur	= 2  // seek from current pos
}IOObjectSeekModes;
typedef bool MemoryResizeCallback( uint8** pMemory, uint32 cursize, uint32 newsize );
class IOObjectMemoryTracker
{
public:
	int32			nAllocatedMemoryRefCount;
	uint32			nAllocatedMemoryLength;
	uint8			pAllocatedMemoryMap[0];
};

class IOObjectHandleTracker
{
public:
	int32 nCount;
#if defined   (_WIN32)
	HANDLE					hFile;
#elif defined (_LINUX)
	int						hFile;
#endif
};

namespace filesys
{

	template<class CHARTYPE>
	bool DeleteFile( const CHARTYPE* ctFileName);


	typedef enum { 
		FileAccess_None		= 0,
		FileAccess_Exists	= 1,
		FileAccess_Read		= 2,
		FileAccess_Write	= 4,
		FileAccess_Full		= 7
	} FileAccess;



}

class IOObject
{
protected:
	IOObjectHandleTracker*  pHandle;
	WString					wsCurrentFilename;
	uint8*					pOpenMemory;
	IOObjectMemoryTracker*	pAllocatedMemory;
	uint32					lMemSize;
	uint32					lCurPos;
	bool					bReadOnly;
 	MemoryResizeCallback*	pResize;	

public:
	IOObject()
	{
		Init();
	};

	//NV - convient.. ?   not necessary.
 	IOObject( const char *szFilename, uint32 flags )
 	{
 		Init();
 		OpenFile( szFilename, flags );
 	}

	IOObject( const wchar_t *wcFilename, uint32 flags )
 	{
 		Init();
 		OpenFile( wcFilename, flags );
 	}
 
 	IOObject( uint8* pLocation, uint32 size, bool bWritable = true, const wchar_t* wcMemoryName = L"none",MemoryResizeCallback* pResizeFunc = (MemoryResizeCallback*)NULL )
 	{
 		Init();
 		OpenMemory( pLocation, size, bWritable, wcMemoryName, pResizeFunc );
 	}

	IOObject(const IOObject& Other)
	{
		Init();
		*this = Other;
	}
	IOObject& operator = (const IOObject& Other)
	{
		Close();
		if(!Other.IsOpen())
			return(*this);

		pOpenMemory = Other.pOpenMemory;

		lMemSize = Other.lMemSize;
		lCurPos = Other.lCurPos;

		pHandle = Other.pHandle;
		if (pHandle)
			++pHandle->nCount;

		wsCurrentFilename = Other.wsCurrentFilename;
		bReadOnly = Other.bReadOnly;

		pAllocatedMemory = Other.pAllocatedMemory;
		if (pAllocatedMemory)
			++pAllocatedMemory->nAllocatedMemoryRefCount;

		return *this;
	}

 	void Init(void)
 	{
   		pOpenMemory			= NULL;
		pHandle				= NULL;
		pAllocatedMemory	= NULL;
   	};

	~IOObject()
	{
		Close();
	}

	bool IsOpen() const { return pOpenMemory != NULL || pHandle != NULL; };
 	bool IsReadOnly() const { return IsOpen() && bReadOnly; };
	IOObjectType QueryType() const { return pOpenMemory != NULL ? objecttype_memory : objecttype_file; }

	bool OpenMemory( uint8* pLocation, uint32 size, bool bWritable = true, const wchar_t* wcName = L"none", MemoryResizeCallback* pResizeFunc = (MemoryResizeCallback*)NULL )
	{
		Close();

		if (pAllocatedMemory)
		{
			if (--pAllocatedMemory->nAllocatedMemoryRefCount == 0)
				delete pAllocatedMemory;
			pAllocatedMemory = NULL;
		}

		pOpenMemory	= pLocation;
		lMemSize	= size;
		lCurPos		= 0;
 		bReadOnly	= !bWritable;
 		pResize		= pResizeFunc;
	
		if( pOpenMemory )
			wsCurrentFilename = wcName;
	
		return pOpenMemory != NULL;

	};
	bool Read( void* pData, uint32 numBytes, uint32* numBytesRead )
	{
		if( !pOpenMemory )
		{
			return PortFileRead( pData, numBytes, numBytesRead );
		}
		else if( lCurPos < lMemSize && numBytes )
		{
			int length = min(numBytes, lMemSize-lCurPos);

			memcpy(pData, &pOpenMemory[lCurPos], length );
			lCurPos += length;
			*numBytesRead = length;

			return true;
		}
		return false;
	}
	bool Write( const void* pData, uint32 numBytes, uint32* numBytesWritten )
	{
		if( !pOpenMemory )
		{
			return PortFileWrite( pData, numBytes, numBytesWritten );
 		}
		else
		{	
    		if( lCurPos < lMemSize && numBytes )
    		{
 				int length = min(numBytes, lMemSize-lCurPos);

 				if ( pResize )
 				{
 					length = numBytes;
 					if ( lCurPos + length > lMemSize )
 					{
 						int newsize = lCurPos + length;

 						if ( !pResize( &pOpenMemory, lMemSize, newsize ) )
 							return false;

 						lMemSize = newsize;
 					}
 				} else {
 					length = min(numBytes, lMemSize-lCurPos);
 				}


    			memcpy(&pOpenMemory[lCurPos], pData, length );
    			lCurPos += length;
    			*numBytesWritten = length;

    			return true;
    		}
			return false;
		}

	}

	bool WriteString( const AString& asStr )
	{
		uint32 Written;
		return Write( (const char*)asStr, asStr.Len(), &Written) && Written == asStr.Len();
	}
	bool WriteString( const WString& wsStr )
	{
		uint32 Written;
		return Write( (const wchar_t*)wsStr, wsStr.Len()*2, &Written) && Written == wsStr.Len()*2;
	}

	bool ReadString( AString& asToHere )
	{
		char cRead;
		uint32 nRead = 0;
		bool bEnd;
		uint32 nLen0 = asToHere.Len();

		do {
			bEnd = !Read ( &cRead, 1, &nRead ) || nRead != 1 || !(cRead == ' ' || cRead == '\n' || cRead == '\r') ;// advance to nonwhitespace
			if ( bEnd && nRead == 1 )
				asToHere.AppendChars( cRead, 1 );
		} while ( bEnd && nRead == 1 );

		do {
			bEnd = !Read ( &cRead, 1, &nRead ) || nRead != 1 || (cRead == ' ' || cRead == '\n' || cRead == '\r') ; // read to next whitespace
			if ( !bEnd ) 
				asToHere.AppendChars( cRead, 1 );
		} while ( bEnd && nRead == 1 );

		return asToHere.Len() > nLen0;
	}

	bool ReadString( WString& wsToHere )
	{
		wchar_t wcRead;
		uint32 nRead = 0;
		bool bEnd;
		uint32 nLen0 = wsToHere.Len();

		do {
			bEnd = !Read ( &wcRead, 2, &nRead ) || nRead != 2 || !(wcRead == L' ' || wcRead == L'\n' || wcRead == '\r'); // advance to nonwhitespace
			if ( bEnd && nRead == 2 )
				wsToHere.AppendChars( wcRead, 2 );
		} while ( bEnd && nRead == 2 );

		do {
			bEnd = !Read ( &wcRead, 2, &nRead ) || nRead != 2 || (wcRead == L' ' || wcRead == L'\n' || wcRead == L'\r'); // read to next whitespace
			if ( !bEnd )
				wsToHere.AppendChars( wcRead, 2 );
		} while ( bEnd && nRead == 2 );

		return wsToHere.Len() > nLen0;
	}


	uint32 GetBytesRemaining() 
	{
		if(!pOpenMemory)
		{
			uint32 curPos	= GetCurPos();
			uint32 lRet;
			if( GetLength(lRet) )
			{
				return lRet - curPos;
			}
			else
			{
				ASSERT(0);
				return 0;
			}
		}
		else
			return lMemSize-lCurPos;
		
	}

	uint32 GetCurPos() 
	{
		if(!pOpenMemory)
			return PortFileGetCurPos();
		else 
			return lCurPos;
		
	}


	bool GetLength(uint32 & len)
	{
		if(!pOpenMemory)
			return PortFileGetLength(len);
		else
			len = lMemSize;
		
		return true;
	}

	uint32 Seek( long offset, IOObjectSeekModes sm )
	{
		if( !pOpenMemory )
			return PortFileSeek( offset, sm );
		else 
		{
			switch( sm )
			{
			case seek_set:
				lCurPos = offset;
				break;
			case seek_cur:
				lCurPos += offset;
				break;
			case seek_end:
				lCurPos = lMemSize-offset;
				break;
			default:
				ASSERT(0);
				lCurPos = 0;
				break;
			}
			return lCurPos;
		}
	};

	uint32 Truncate( )
	{
		if ( !pOpenMemory )
			return PortFileTruncate();
		else 
		{
			if ( pResize )
				pResize( &pOpenMemory, lMemSize, lCurPos );
		
			lMemSize = lCurPos;
		}
		return lMemSize;
	};

	bool Delete( )
	{
		bool result;

		if( pOpenMemory )
		{
			Close();

			if ( pResize )
			{
				if ( pResize( &pOpenMemory, lMemSize, 0 ) )
					pOpenMemory = (uint8*)NULL;
			}

			lMemSize = 0;
		}

		if ( !wsCurrentFilename )
			return false;		//it's not a file or not open or something

		WString wcName;

		wcName = wsCurrentFilename;
		wsCurrentFilename = (wchar_t*)NULL;

		if ( !Close() )
		{
			wsCurrentFilename = wcName;
			return false;
		}
		result = filesys::DeleteFile( (const wchar_t*)wcName );
		return result;
	}

	WString GetName() const
	{
		if( IsOpen() )
			return wsCurrentFilename;
		else
			return (const wchar_t*)NULL;
	}

// OS specific
	bool OpenFile( const char *szFilename, long flags );			
	bool OpenFile( const wchar_t *wcFilename, long flags);			
	bool Close();													
	bool MakeMemoryPtr( uint8** ppMemory, uint32 *size );			
	void FreeMemoryPtr( uint8* pMem );								
	inline bool GetLastModified( tm& tmModified );

	// protected port bits
protected:
	inline bool		PortFileRead( void* pData, uint32 numBytes, uint32* numBytesRead );
	inline bool		PortFileWrite( const void* pData, uint32 numBytes, uint32* numBytesWritten );
	inline uint32	PortFileGetCurPos();
	inline bool		PortFileGetLength(uint32 & len);
	inline uint32	PortFileSeek( long offset, IOObjectSeekModes sm );
	inline uint32	PortFileTruncate( );

public:

	//platform specific
	int32 OS_GetFileDescriptor()
	{
		if (pHandle)
			return (int32)pHandle->hFile;
		else	
			return 0;
	}

};



#include "filesys_port.h"

//filesys namespace

namespace filesys
{




//Forms a path given a directory, a filename and optionally an extension
template <class CHARTYPE>
inline TString<CHARTYPE> MakePath(const TString<CHARTYPE>& Directory, const TString<CHARTYPE>& Filename, const TString<CHARTYPE>& Extension)
{
	TString<CHARTYPE> Result;

	Result.Copy(Directory);
	Result.Cat(CONSTSTR(DIR_DIVIDER_STRING,CHARTYPE));
	Result.Cat(Filename);
	if( Extension.Len() )
	{
		Result.Cat(CONSTSTR(EXTENSION_DIVIDER_STRING,CHARTYPE));
		Result.Cat(Extension);
	}

	return Result;
}
template <class CHARTYPE>
inline TString<CHARTYPE> MakePath(const CHARTYPE* tcDirectory, const CHARTYPE* tcFilename, const CHARTYPE* tcExtension = NULL)
{
	TString<CHARTYPE> Result;

	Result.Copy(tcDirectory);
	Result.Cat(CONSTSTR(DIR_DIVIDER_STRING,CHARTYPE));
	Result.Cat(tcFilename);
	if( tcExtension && *tcExtension )
	{
		Result.Cat(CONSTSTR(EXTENSION_DIVIDER_STRING,CHARTYPE));
		Result.Cat(tcExtension);
	}

	return Result;
}

//Finds the file name given a path
template <class CHARTYPE>
inline TString<CHARTYPE> GetBaseName(const TString<CHARTYPE>& Path)
{
	return GetBaseName((const CHARTYPE*)Path);
}
template <class CHARTYPE>
inline TString<CHARTYPE> GetBaseName(const CHARTYPE* Path)
{
	const CHARTYPE* start, * cur;
	
	start = cur = Path;
	ASSERT(Path); // mighty odd
	if( Path )
	{
		while(*cur)
			cur++;
		while (cur > start && cur[-1] != CONSTCHAR('\\',CHARTYPE) && cur[-1] != CONSTCHAR('/',CHARTYPE))
			cur--;
	}
	return TString<CHARTYPE>(cur);
}
//Finds the directory name given a path
template <class CHARTYPE>
inline TString<CHARTYPE> GetDirName(const TString<CHARTYPE>& Path)
{
	return GetDirName((const CHARTYPE*)Path);
}
template <class CHARTYPE>
inline TString<CHARTYPE> GetDirName(const CHARTYPE* Path)
{
	const CHARTYPE* start, * cur;
	
	ASSERT(Path); // mighty odd
	if( Path )
	{
		start = cur = Path;
		while( *cur )
			cur++;
		while( cur > start+1 && cur[-1] != CONSTCHAR('\\',CHARTYPE) && cur[-1] != CONSTCHAR('/',CHARTYPE) )
			cur--;
		if( cur == start+1 && cur[-1] != CONSTCHAR('\\',CHARTYPE) && cur[-1] != CONSTCHAR('/',CHARTYPE) )
			return TString<CHARTYPE>(CONSTSTR(".",CHARTYPE));
		else
			return TString<CHARTYPE>(Path, cur-start-1);
	}
	return NULL;
}
//Finds the extension of file a given a path
template <class CHARTYPE>
inline TString<CHARTYPE> GetExtension(const TString<CHARTYPE>& Path)
{
	return GetExtension((const CHARTYPE*)Path);
}
template <class CHARTYPE>
inline TString<CHARTYPE> GetExtension(const CHARTYPE* Path)
{
	const CHARTYPE* start, * cur;
	
	ASSERT(Path); // odd
	if( Path )
	{
		start = cur = Path;
		while(*cur)
			cur++;

		// jmc100902 tweak this.
		// old algorithm - run to end, backtrack to / or \, then forward to .
		//		bad if file is D.O.A.mp3
		// new algorithm - run to end, backtrack to .

		/*while (cur > start && cur[-1] != CONSTCHAR('\\',CHARTYPE) && cur[-1] != CONSTCHAR('/',CHARTYPE))
			cur--;
		while( cur[0] != CONSTCHAR('.',CHARTYPE) )
			cur++;*/
		while (cur > start && cur[0] != CONSTCHAR('.',CHARTYPE) )
			cur--;
		return TString<CHARTYPE>(cur);
	}
	return NULL;
}
//Returns a path minus the file's extension
template <class CHARTYPE>
inline TString<CHARTYPE> StripExtension(const TString<CHARTYPE>& Path)
{
	return StripExtension((const CHARTYPE*)Path);
}
template <class CHARTYPE>
inline TString<CHARTYPE> StripExtension(const CHARTYPE* Path)
{
	const CHARTYPE* start, * cur;
	
	ASSERT(Path);
	if( Path )
	{
		start = cur = Path;
		while(*cur)
			cur++;
		while (cur > start && cur[-1] != CONSTCHAR('\\',CHARTYPE) && cur[-1] != CONSTCHAR('/',CHARTYPE))
			cur--;
		while( cur[0] != CONSTCHAR('.',CHARTYPE) )
			cur++;
		return TString<CHARTYPE>(Path, cur-start);
	}
	return NULL;
}
//Returns a path with the file's extension replaced with another one
template <class CHARTYPE>
inline TString<CHARTYPE> ReplaceExtension(const CHARTYPE* Path, const CHARTYPE* NewExtension)
{
	TString<CHARTYPE> Result;

	Result = StringExtension(Path);
	Result.Cat(CONSTSTR(EXTENSION_DIVIDER_STRING,CHARTYPE));
	Result.Cat(NewExtension);

	return Result;
}
//Given a directory and a path relative to it, returns the full path.
template <class CHARTYPE>
TString<CHARTYPE> GetAbsolutePath(const CHARTYPE* Directory, const CHARTYPE* RelativePath)
{
	TString<CHARTYPE> Result;
	int32 ResultLen;
	const CHARTYPE* Start, * Cur;

	if (RelativePath[0] == CONSTCHAR('\\',CHARTYPE) ||
		RelativePath[0] == CONSTCHAR('/', CHARTYPE) ||
		RelativePath[0] && RelativePath[1] == CONSTCHAR(':', CHARTYPE))
		return RelativePath;

	Result.Copy(Directory);
	ResultLen = Result.Len();
	Start = Cur = RelativePath;
	while(true)
	{
		if (*Cur == CONSTCHAR('\\',CHARTYPE) ||
			*Cur == CONSTCHAR('/',CHARTYPE)  ||
			*Cur == CONSTCHAR('\0',CHARTYPE) )
		{
			if (Cur-Start == 1 && Start[0] == CONSTCHAR('.',CHARTYPE))
			{
				// do nothing
			} else if (Cur-Start == 2 && Start[0] == CONSTCHAR('.',CHARTYPE) && Start[1] == CONSTCHAR('.',CHARTYPE)) {
				if (ResultLen > 0 && (Result[ResultLen-1] == CONSTCHAR('\\',CHARTYPE) || Result[ResultLen-1] == CONSTCHAR('/',CHARTYPE)))
					ResultLen--;
				while (ResultLen > 0 && Result[ResultLen-1] != CONSTCHAR('\\',CHARTYPE) && Result[ResultLen-1] != CONSTCHAR('/',CHARTYPE))
					ResultLen--;
			} else {
				int len = Cur+(*Cur != CONSTCHAR('\0',CHARTYPE)?1:0)-Start;
				Result.Allocate(ResultLen);
				if ((ResultLen == 0 || (Result[ResultLen-1] != CONSTCHAR('\\',CHARTYPE) && Result[ResultLen-1] != CONSTCHAR('/',CHARTYPE))))
				{
					Result.Cat(CONSTSTR(DIR_DIVIDER_STRING,CHARTYPE));
					ResultLen += strlenof(DIR_DIVIDER_STRING);
				}
				Result.Cat(Start, len);
				ResultLen += len;
			}
			Start = Cur+1;
			if (*Cur == CONSTCHAR('\0',CHARTYPE))
				break;
		}
		Cur++;
	}
	Result.Allocate(ResultLen);

	return Result;
}
//Given an absolute path and a directory, works out a relative path which points to the same thing relative to that directory
template <class CHARTYPE>
TString<CHARTYPE> GetRelativePath(const CHARTYPE* BaseDirectory, const CHARTYPE* Path)
{
	const CHARTYPE* Cur, * BaseDirectoryEnd;
	TString<CHARTYPE> Result;
	int Level;//, pos;

	if( sizeof(CHARTYPE) == sizeof(char) )
	{
		BaseDirectoryEnd = BaseDirectory+strlen((const char*)BaseDirectory);
	} else if( sizeof(CHARTYPE) == sizeof(wchar_t) ) {
		BaseDirectoryEnd = BaseDirectory+wcslen((const wchar_t*)BaseDirectory);
	} else {
		ASSERT(0);
	}

	Cur = BaseDirectoryEnd;
	Level = 0;
	do
	{
		if (!TString<CHARTYPE>::Compare(Path, BaseDirectory, FILENAMESARECASESENSITIVE, Cur-BaseDirectory))
			break;
		Level++;
		Cur--;
		while (Cur > BaseDirectory && Cur[-1] != CONSTCHAR('/',CHARTYPE) && Cur[-1] != CONSTCHAR('\\',CHARTYPE))
			Cur--;
	} while (Cur > BaseDirectory);
	if (Cur == BaseDirectory)
		return Path;

	if (Level == 0 && (Path[(Cur-BaseDirectory)] == CONSTCHAR('/',CHARTYPE) || Path[(Cur-BaseDirectory)] == CONSTCHAR('\\',CHARTYPE)))
		Cur++;
	while (Level--)
	{
		Result.Cat(CONSTSTR("..",CHARTYPE));
        Result.Cat(CONSTSTR(DIR_DIVIDER_STRING,CHARTYPE));
	}
	Result.Cat(Path+(Cur-BaseDirectory));
	return Result;
}

/* jmctodo FileInfoArray functions should be WStrings, not AStrings */
inline bool LoadFileIntoArray(IOObject* IO, Array<AString>& Strings)
{
	char Buf[512];
	const char* Ptr, * Last;
	AString* CurString;
	uint32 read;
	bool bFinishedLine;

	Strings.RemoveAll();
	CurString = (AString*)NULL;
	bFinishedLine = false;
	while( true )
	{
		if( !IO->Read(Buf, sizeof(Buf), &read) || read <= 0 )
			break;
		Ptr = Last = Buf;
		do
		{
			while( Ptr < Buf+read )
			{
				if( *Ptr == '\r' || *Ptr == '\n' )
					break;
				Ptr++;
			}
			if( *Last != '\r' && *Last != '\n' )
			{
				if( !CurString || bFinishedLine )
					CurString = &Strings.AddTail();
				CurString->Cat(Last, Ptr-Last);
				if( Ptr < Buf+read )
					bFinishedLine = true;
				else
					bFinishedLine = false;
            } else {
                bFinishedLine = true;
            }
			Last = ++Ptr;
		} while ( Last < Buf+read );
	}

	return true;
}

inline bool SaveArrayIntoFile(IOObject* IO, Array<AString>& Strings)
{
	int32 i, n;
	uint32 w;

	n = Strings.GetCount();
	for( i = 0; i < n; i++ )
	{
		if( Strings[i].Len() && (!IO->Write( Strings[i], Strings[i].Len(), &w ) || w != Strings[i].Len()) )
			return false;
		if( !IO->Write( END_OF_LINE, strlenof(END_OF_LINE), &w ) || w != strlenof(END_OF_LINE) )
			return false;
	}

	return true;
}


template<class CHARTYPE>
inline bool FileExists( TString<CHARTYPE>& tsFileName ) 
{
	return FileExists( (const CHARTYPE*) tsFileName );
}

//IOObjectType QueryFileType(const char*);
//IOObjectType QueryFileType(const wchar_t*);
template<class CHARTYPE>
inline bool DirectoryExists( const CHARTYPE* tcFileName ) 
{
	if( FileExists( tcFileName ) && QueryFileType(tcFileName) == objecttype_directory )
        return true;
    return false;
}


template<class CHARTYPE>
inline bool DeleteFile( TString<CHARTYPE>& tsFileName ) 
{
	return DeleteFile( (const CHARTYPE*) tsFileName );
}

template <class CHARTYPE>
bool RenameFile( TString<CHARTYPE>& tsNewName, TString<CHARTYPE>& tsOldName )
{
	return RenameFile( (const CHARTYPE*) tsNewName, (const CHARTYPE*) tsOldName );
}

template <class CHARTYPE>  
inline uint32 SizeOfFile(const CHARTYPE* sName)
{
        IOObject ioobj;
        if (ioobj.OpenFile(sName, open_existing| access_read ))
        {
                uint32 len;
                if (ioobj.GetLength(len))
                        return len;
        }
	return 0;
}



template <class CHARTYPE>
int CreatePath(const CHARTYPE* Path, CHARTYPE** CreatePos)
{
	const CHARTYPE* End;
	CHARTYPE c;
	bool Result;

    if(sizeof(CHARTYPE)==sizeof(char))
	    End = Path+strlen((const char*)Path);
    else if(sizeof(CHARTYPE)==sizeof(wchar_t))
        End = Path+wcslen((const wchar_t*)Path);
    else
        ASSERT(0);

	while(true)
	{
		while (End > Path && End[-1] != '\\') // go up one level
			End--;
		if (End == Path) 
			return 0; // didn't find any existing parent directory
		c = End[0];
		((CHARTYPE*)End)[0] = 0; 
		Result = DirectoryExists(Path); // does this parent directory exist..?
		((CHARTYPE*)End)[0] = c;
		if (Result) 
			break;
		End--;
	}

	if (!*End) return 2; // path ends in '\' and already exists

	if (CreatePos)
		*CreatePos = (CHARTYPE*)End;
	while(*End)
	{
		if (End[0] == '\\' && End[1] == 0)
			break;
		if (End[0] == '\\') 
			End++;
		while (*End && *End != '\\')
			End++;
		c = End[0];
		((CHARTYPE*)End)[0] = 0;
		Result = MakeDirectory(Path);
		((CHARTYPE*)End)[0] = c;
	}

	if (!Result) 
		return 2;  // couldn't make...directory probably already exists
	return 1; // directory created
}


} // namespace filesys





// globals





#endif//_FILESYS_H_
