// $Id: Files.h 8019 2007-07-14 22:30:11Z trick $

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Deadly Rooms of Death.
 *
 * The Initial Developer of the Original Code is
 * Caravel Software.
 * Portions created by the Initial Developer are Copyright (C) 1995, 1996,
 * 1997, 2000, 2001, 2002 Caravel Software. All Rights Reserved.
 *
 * Contributor(s):
 * Mike Rimer (mrimer)
 *
 * ***** END LICENSE BLOCK ***** */

//Files.h
//Declarations for CFiles.
//Class for handling file-related tasks.

#ifndef FILES_H
#define FILES_H

#if defined WIN32
#  define HAS_UNICODE
#elif defined __sgi
#  undef HAS_UNICODE
#elif defined __APPLE__
#  undef HAS_UNICODE
#elif defined __linux__ || defined __FreeBSD__
#  undef HAS_UNICODE
#else
#error Platform unknown!  Does this platform support Unicode?
#endif


#ifdef WIN32
#  define SLASH '\\'
#  pragma warning(disable:4786)
#else
#  define SLASH '/'
#endif

#include "Assert.h"
#include "StretchyBuffer.h"
#include "IniFile.h"
#include <string>
#include <vector>

using std::string;
using std::vector;

#define MAX_PROFILE_STRING 1024
#ifndef MAX_PATH
#  ifdef PATH_MAX
#     define MAX_PATH PATH_MAX
#  else
#     define MAX_PATH 260
#  endif
#endif

extern const WCHAR wszDefExportDir[];

class CFiles
{
public:
	 CFiles(const WCHAR *wszSetAppPath = NULL,
				const WCHAR *wszSetGameName = NULL,
				const WCHAR *wszSetGameBranch = NULL,
				const WCHAR *wszSetGameVer = NULL,
				const bool bIsDemo = false);
	 ~CFiles();

	 static FILE *           Open(const WCHAR *pszFilepath, const char *pszOptions);
	 static bool             DoesFileExist(const WCHAR *pszFilepath);
	 static bool             DoesFileExist(const char *pszFilepath);
	 static bool             FileCopy(const WCHAR *pszSourceFilepath, const WCHAR *pszDestFilepath);
	 static bool             HasReadWriteAccess(const WCHAR *pwzFilepath);
	 static bool             IsValidPath(const WCHAR *pwzPath);
	 static bool             ReadFileIntoBuffer(const WCHAR *pwzFilepath, CStretchyBuffer &Buffer, bool bBinary = false);
	 static bool             WriteBufferToFile(const WCHAR *pwzFilepath, const CStretchyBuffer &Buffer);
	 static bool             WriteBufferToFile(const char *pszFilepath, const CStretchyBuffer &Buffer);

	 //These methods require class construction.
	 void                    AppendErrorLog(const char *pszText);
	 const WCHAR *           GetAppPath() {ASSERT(wszAppPath); return wszAppPath;}
	 const WCHAR *           GetDatPath() {ASSERT(wszDatPath); return wszDatPath;}
	 const WCHAR *           GetResPath() {ASSERT(wszResPath); return wszResPath;}
	 bool                 GetGameProfileString(const char *pszSection, const char *pszKey, string& strValue);
	 bool                 GetGameProfileString(const char *pszSection, const char *pszKey, list<string>& strValue);
	 bool                 GetGameProfileString(const char *pszSection, const char *pszKey, list<WSTRING>& strValue);
	 void                 TryToFixDataPath();
	 bool                 WriteGameProfileString(const char *pszSection, const char *pszKey, const char *pszValue);

#ifdef USE_LOGCONTEXT
	 //Used to set context that is described in error log.  Use LOGCONTEXT() macro from
	 //instead of calling directly.
	 static void             PushLogContext(const char *pszDesc);
	 static void             PopLogContext(const char *pszDesc);
#endif

	 //File encryption/unencryption.
	 static bool             FileIsEncrypted(const WCHAR *wszFilepath) {
		 return wszFilepath[WCSlen(wszFilepath) - 1] == '_';}
	 static bool             ProtectFile(const WCHAR *pszFilepath);
	 //symmetric operations
	 static bool             UnprotectFile(const WCHAR *pszFilepath) {return ProtectFile(pszFilepath);}
	 static bool             GetTrueDatafileName(WCHAR *pszFilepath);
	 static void             MutateFileName(WCHAR *pszFilepath);
	 static bool             WindowsCanBrowseUnicode();

	 static bool             GetDirectoryList(const WCHAR *wszFilepath, vector<WSTRING>& dirs,
										 bool bShowHidden = false);
	 static bool             GetFileList(const WCHAR *wszFilepath, const WSTRING& mask,
										 vector<WSTRING>& files, bool bFullPath = false, bool bShowHidden = false);
	 static bool             GetDriveList(vector<WSTRING>& drives);
#if defined __linux__ || defined __FreeBSD__ || defined __APPLE__
	 static bool             CreatePathIfInvalid (const WCHAR *wszPath);
	 static const WCHAR *    GetHomePath() {return wstrHomePath.c_str();}
#endif

private:
	 void                    DeinitClass();
#if defined __linux__ || defined __FreeBSD__ || defined __APPLE__
	 static bool             CheckDataAndMakeWritable(WCHAR *wszPath);
	 static bool             CheckForDataFile(WCHAR *wszPath, const WCHAR *wszFmt,
											 const WCHAR *wszFile, const bool bTryClean, const bool bData);
	 static bool             FindPossibleDatFile(const WCHAR *wszFilename, WCHAR *wszPathBuf);
	 static bool             FindPossibleResFile(const WCHAR *wszFilename, WCHAR *wszPathBuf);
#else
	 static bool             FindPossibleDatPath(const WCHAR *wszStartPath, WCHAR *wszPossibleDatPath);
	 static bool             FindPossibleResPath(const WCHAR *wszStartPath, WCHAR *wszPossibleResPath);
#endif
	 void                InitClass(const WCHAR *pszSetAppPath,
          const WCHAR *wszSetGameName, const WCHAR *setGameBranch, const WCHAR *wszSetGameVer, const bool bIsDemo);
	 static bool             WriteDataPathTxt(const WCHAR *pszFilepath,
			 const WCHAR *wszDatPath, const WCHAR *wszResPath, const bool overwrite);

#if defined __linux__ || defined __FreeBSD__ || defined __APPLE__
	 static WSTRING wstrHomePath;
#endif
	 static WCHAR *wszAppPath;
	 static WCHAR *wszDatPath;
	 static WCHAR *wszResPath;
	 static WCHAR *wszGameName, *wszGameBranch, *wszGameVer;
	 static DWORD dwRefCount;
	 static CIniFile gameIni;
	 static bool bInitIni;
	 static bool bIsDemo;

#ifdef WIN32
#define NUMDRIVES 26
	static bool bDrives[NUMDRIVES];
	static bool bDrivesChecked;
#endif

	 PREVENT_DEFAULT_COPY(CFiles);
};

#if defined __linux__ || defined __FreeBSD__ || defined __APPLE__
//A small class for getting trees of search paths.  The expr parameter to
//the constructor is a string in a special format containing the paths we want
//with a few control chars thrown in (all control chars except ; are replaced
//by SLASH in the output).  Most control chars adds a bit to the setup.
//Next() returns every bit combination in turn, starting with all bits set
//and decreasing.  The control chars are:
//
//  '/'  (no bit)  Always write
//  ';'  (no bit)  (Invisible) Always write, switch off all control chars,
//                 return position
//  '?'  (+1 bit)  Write if bit is on ("toggle")
//  '<'  (+1 bit)  Write if bit is on and preceding bit is on ("tail")
//  '>'  (+1 bit)  Write if bit is on and preceding bit is off ("swap")
//
//So, passing the string "/one?two>three<four" returns this in the buffer
//(four calls to Next()):
//
//      "/one/two", "/one/three/four", "/one/three", "/one"
//
//(one is static, two is toggled and swapped with three, and four is
// three's tail)

class CPathGen {
	WCHAR       *wszBuffer;
	const WCHAR *wszExpr;
	UINT         wBits, wN;

public:
	CPathGen(WCHAR *buffer, const WCHAR *expr);
	int Next();
};
#endif


#endif //...#ifndef FILES_H
