/*
	CPathTools
	ディレクトリ関係の処理を行う
	インプリメンテーション ファイル

	Version		: 0.0 (Release1)
	Version		: 0.0 (Release1)
	説明		: ファイルの検索やパスの処理など


	作成日		: 2000/12/07
	修正日		: ----/--/--
	改定履歴	: 
*/

#include "stdafx.h"
#include "Dir.h"

#include <direct.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/*********************************************************************/
/*	CDirIndexer	*/
/*********************************************************************/
//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////
CDirIndexer::CDirIndexer()
{
	m_allFileSize = 0;
}

CDirIndexer::~CDirIndexer()
{
}

//////////////////////////////////////////////////////////////////////
// 検索命令
//////////////////////////////////////////////////////////////////////
/*!
	処理内容	: ファイルの検索
	引数		: path : パス(C:\*.jpg・・・)、subDirectory : 1:サブディレクトリも有効
	帰り値		: -1：エラー、0：成功
*/
int CDirIndexer::FindFile(CString path, int subDirectory)
{
	int				done=1;
	CFileFind		find;
	CString			fileName =  CPathTools::PathToName(path);

	m_allFileSize = 0;

	if(find.FindFile(path))
	{
		while(done)
		{
			done=find.FindNextFile();

			if(find.IsDots())
				continue;

			//	再起検索
			if(find.IsDirectory())
			{
				if(subDirectory)
				{
					__int64 push = m_allFileSize;
					FindFile(find.GetFilePath() + _T("\\") + fileName,subDirectory);
					m_allFileSize += push;
				}
				continue;
			}
			
			//	警告が出るから・・・
			CString	add = find.GetFilePath();
			m_fileList.Add(add);
			m_allFileSize += find.GetLength();
		}
	}
	find.Close();
	
	return(0);
}


/*!
	処理内容	: ディレクトリの検索
	引数		: path : パス(C:\*.jpg・・・)
	帰り値		: -1：エラー、0：成功
*/
int CDirIndexer::FindDir(CString path,int subDirectory)
{
	int				done=1;
	CFileFind		find;
	CString			fileName =  CPathTools::PathToName(path);

	m_allFileSize = 0;

	if(find.FindFile(path))
	{
		while(done)
		{
			done=find.FindNextFile();

			if(find.IsDots())
				continue;

			//	再起検索
			if(find.IsDirectory())
			{
				if(subDirectory)
					FindDir(find.GetFilePath() + _T("\\") + fileName);

				//	警告が出るから・・・
				CString	add = find.GetFilePath();
				m_fileList.Add(add);
			}			
		}
	}
	find.Close();
	
	return(0);
}

//////////////////////////////////////////////////////////////////////
// 検索結果へのアクセス
//////////////////////////////////////////////////////////////////////
/*!
	ファイルリストを取得する
*/
void CDirIndexer::GetFileList(CStringArray &list)
{
	list.Copy(m_fileList);
}

/*!
	処理内容	: 見つかったファイル数を返す
	引数		: なし
	帰り値		: ファイル数
*/
int CDirIndexer::GetFileCount()
{
	return((int)m_fileList.GetSize());
}


/*
	処理内容	: 見つかったファイルのパスを返す
	引数		: インデックス
	帰り値		: ファイルパス
*/
CString CDirIndexer::GetFilePath(int index)
{
	return(m_fileList.GetAt(index));
}

/*!
	総ファイルサイズを返す
*/
__int64 CDirIndexer::GetAllFleSize()
{
	return m_allFileSize;
}

/*********************************************************************/
/*	CDirIndexer	*/
/*********************************************************************/
//////////////////////////////////////////////////////////////////////
// ディレクトリ生成
//////////////////////////////////////////////////////////////////////
/*!
	関数名		: CPathTools::MakeDirectory(CString path)
	処理内容	: ディレクトリの生成
	引数		: パス
	帰り値		: -1：エラー、0：すでに存在、1：生成に成功
*/
int CFileDirTools::MakeDirectory(CString path)
{
	CFileFind	find;

	while(1)
	{
		if(CPathTools::CheckBackSlash(path) || CPathTools::CheckLastChar(path,_T(' ')))
		{
			path=path.Left(path.GetLength()-1);
		}
		else
		{
			break;
		}
	}

	path=path+_T("\\");
	if(!find.FindFile(path + _T("*.*")))
	{
		find.Close();
		if(_tmkdir(path)==-1)
			return(-1);
		return(1);
	}
	find.Close();

	return(0);
}


/*!
	関数名		: CPathTools::MakeAllDirectory(CString path)
	処理内容	: パスに存在するディレクトリを全て生成
	引数		: パス
	帰り値		: -1：エラー、0：生成に成功
*/
int CFileDirTools::MakeAllDirectory(CString path)
{
	CString	mpath;
	int	i,ret=0;

	path = CPathTools::AddBackSlash(path);

	while(1)
	{
		i=path.Find(_T("\\"));
		if(i==-1)
			break;
		mpath = mpath + path.Left(i+1);
		path = path.Right(path.GetLength() - i - 1);

		//	ネットワークドライブ対策
		ret = MakeDirectory(mpath);
	}
	return(ret);
}


///////////////////////////////////////////////////////////////////////
//	ファイル
///////////////////////////////////////////////////////////////////////
/*!
	CDirectoryUtility::FILE_TYPE_FILE		ファイルが存在
	CDirectoryUtility::FILE_TYPE_DIRECTORY	フォルダが存在
	CDirectoryUtility::FILE_TYPE_NOTFOUND	なし
*/
int CFileDirTools::FileExist(CString path)
{
	//	ディレクトリインデックスから強制取得
	CFileFind	find;

	//	ディレクトリ
	if(CPathTools::CheckBackSlash(path))
	{
		if(find.FindFile(path + "*.*"))
			return(FILE_TYPE_DIRECTORY);
		TRACE("%d : %s\n", GetLastError(), path + "*.*");
		return(FILE_TYPE_NOTFOUND);
	}

	//	ファイル
	if(find.FindFile(path))
	{
		find.FindNextFile();
		if(find.IsDirectory())
			return(FILE_TYPE_DIRECTORY);

		//	システムデバイス？
		if(find.GetFilePath().Left(4) == "\\\\.\\")
			return(FILE_TYPE_NOTFOUND);

		CString	srcPath = CPathTools::PathToName(path);
		CString	destPath = find.GetFileName();
		if(srcPath.CompareNoCase(destPath) == 0)
			return(FILE_TYPE_FILE);
	}

	//	ディレクトリ2
	if(find.FindFile(path + _T("\\*.*")))
	{
		return(FILE_TYPE_DIRECTORY);
	}

	//	見つからない
	return(FILE_TYPE_NOTFOUND);
}

/*!
	ファイルもしくはディレクトリの属性取得
*/
DWORD CFileDirTools::GetFileAttribute(CString path)
{
	return(GetFileAttributes(CPathTools::RemoveBackSlash(path)));
}



/*********************************************************************/
/*	CPathTools	*/
/*********************************************************************/
///////////////////////////////////////////////////////////////////////
//	パス変換
///////////////////////////////////////////////////////////////////////
/*!
	関数名		: CPathTools::PathToName(CString path)
	処理内容	: パスからファイル名を取得
	引数		: パス
	帰り値		: ファイル名
*/
CString CPathTools::PathToDrive(CString path)
{
	if(path.Mid(1,1) != _T(":"))
		return(_T(""));

	return(path.Left(1) + _T(":")); //	(X:)
}

/*!
	関数名		: CPathTools::PathToName(CString path)
	処理内容	: パスからファイル名を取得
	引数		: パス
	帰り値		: ファイル名
*/
CString CPathTools::PathToName(CString path)
{
	int	index;

	index = path.ReverseFind(_T('\\'));
	if(index==-1)
		return(path);

	return(path.Right(path.GetLength() - index - 1));
}

/*!
	関数名		: CPathTools::PathToNameNoExt(CString path)
	処理内容	: パスからファイル名(拡張子なし)を取得
	引数		: パス
	帰り値		: ファイル名(拡張子なし)
*/
CString CPathTools::PathToNameNoExt(CString path)
{
	CString	name = PathToName(path);
	int index = name.Find(".");
	if(index == -1)
		return(name);
	else
		return(name.Left(index));
}

/*!
	関数名		: CPathTools::PathToDir(CString path)
	処理内容	: パスからファイル名を削除
	引数		: パス
	帰り値		: パス
*/
CString CPathTools::PathToDir(CString path)
{
	int	index;

	index = path.ReverseFind(_T('\\'));
	if(index==-1)
		return(_T(""));

	path = path.Left(index);
	path = AddBackSlash(path);

	return(path);
}

/*!
	関数名		: CPathTools::PathToDir(CString path)
	処理内容		: パスから拡張子を取得
	引数			: パス
	帰り値		: パス
*/
CString CPathTools::PathToExt(CString path)
{
	int	index;

	index = path.ReverseFind(_T('.'));
	if(index==-1)
		return(path);

	return(path.Right(path.GetLength() - index - 1));
}


/*!
	表示名（ファイル名 or フォルダ名 or ドライブ名）取得
*/
CString CPathTools::PathToViewName(CString path)
{
	//	ファイル名を取得
	CString name = PathToName(path);
	if(!name.IsEmpty())
		return(name);
	
	//	バックスラッシュを削除
	path = RemoveBackSlash(path);

	//	ドライブ？
	if(CheckLastChar(path, _T(':')))
		return(path + _T("\\"));

	//	ディレクトリ
	return(PathToName(path));
}

/*!
	ひとつ上のディレクトリパスを取得
*/
CString CPathTools::GetUpDir(CString path)
{
	path = RemoveBackSlash(path);
	int index = path.ReverseFind(_T('\\'));
	if(index == -1)
		return(path);

	return(AddBackSlash(path.Mid(0,index)));
}


/*!
	使えない文字を置き換え
*/
CString CPathTools::SafeName(CString name, CString replace)
{
	name.Replace(_T("/"),replace);
	name.Replace(_T("\\"),replace);
	name.Replace(_T(":"),replace);
	name.Replace(_T("?"),replace);
	name.Replace(_T("*"),replace);
	name.Replace(_T("\""),replace);
	name.Replace(_T(">"),replace);
	name.Replace(_T("<"),replace);

	return(name);
}

///////////////////////////////////////////////////////////////////////
//	パスの比較
///////////////////////////////////////////////////////////////////////
/*!
	パスに含まれているか調べる

	\param parentPath	このパスのサブディレクトリか調べる
	\param childPath	調べるパス
	\return				TRUE:サブディレクトリ
*/
int CPathTools::IsInPath(CString parentPath, CString childPath)
{
	if(parentPath.CompareNoCase(childPath.Left(parentPath.GetLength())) == 0)
		return(TRUE);

	return(FALSE);
}

///////////////////////////////////////////////////////////////////////
//	/\の加工
///////////////////////////////////////////////////////////////////////
/*!
	スラッシュを後ろに追加
*/
CString CPathTools::AddSlash(CString path)
{
	if(CheckSlash(path))
		return(path);

	return(path + _T("/"));
}

/*!
	バックスラッシュを後ろに追加
*/
CString CPathTools::AddBackSlash(CString path)
{
	if(CheckSlash(path) || CheckBackSlash(path))
		return(path);

	return(path + _T("\\"));
}

/*!
	スラッシュを後ろから削除
*/
CString CPathTools::RemoveSlash(CString path)
{
	if(CheckSlash(path))
		path = path.Left(path.GetLength()-1);

	return(path);
}

/*!
	バックスラッシュを後ろから削除
*/
CString CPathTools::RemoveBackSlash(CString path)
{
	if(CheckBackSlash(path))
		path = path.Left(path.GetLength()-1);

	return(path);
}

/*!
	最後の文字をチェック
*/
int CPathTools::CheckLastChar(CString path, unsigned char c)
{
	LPCSTR	ptr = path;

	//	空文字列
	if(*ptr == 0)
		return(0);

	while(1)
	{
		//	シングルバイト
		if(*ptr <= 0x80 || (*ptr >= 0xA0 && *ptr <= 0xDF))
		{
			//	終了?
			if(*(ptr+1) == 0)
			{
				if(*ptr == c)
					return(1);
				else
					return(0);
			}
			ptr++;
		}
		else
		{
			//	終了?
			if(*(ptr+1) == 0 || *(ptr+2) == 0)
				return(0);
			ptr+=2;
		}
	}
}

/*!
	最後にスラッシュがあるか
*/
int CPathTools::CheckSlash(CString path)
{
	return(CheckLastChar(path,_T('/')));
}

/*!
	最後にバックスラッシュがあるか
*/
int CPathTools::CheckBackSlash(CString path)
{
	return(CheckLastChar(path,_T('\\')));
}

///////////////////////////////////////////////////////////////////////
//	モジュールパス
///////////////////////////////////////////////////////////////////////
/*!
	モジュールパス取得
*/
CString CPathTools::GetAppPath()
{
	TCHAR	s[MAX_PATH+1];
	DWORD len = GetModuleFileName(NULL, s, MAX_PATH);

	while (s[len--]!=_T('\\') && len!=0 )
		;
	s[len+2] = _T('\0');        // ￥マークで終わらせる

	return(s);
}

/*!
	モジュールパス名取得
*/
CString CPathTools::GetAppPathName()
{
	TCHAR	s[MAX_PATH+1];
	GetModuleFileName(NULL, s, MAX_PATH);

	return(s);
}



/////////////////////////////////////////////////////////////////////////
//	各種パスを取得
/////////////////////////////////////////////////////////////////////////
/*!
	パス変数を置き換え後のパスを取得

	%WINDOWS%		c:\Windows
	%SYSTEM32%		c:\Windows\System32
	%PROGRAMFILES%	c:\Program Files
*/
CString CPathTools::GetPathSwapString(CString path)
{
	//	サイズ取得
	int len = ExpandEnvironmentStrings(path, NULL, 0) + 1;

	//	変換
	CString	ret;
	ExpandEnvironmentStrings(path, ret.GetBuffer(len + 1), len);
	ret.ReleaseBuffer();

	return(ret);
}

/*!
	Windows パス取得
*/
CString CPathTools::GetWindowsPath()
{
	TCHAR szPath[_MAX_PATH];

	SHGetSpecialFolderPath(NULL, szPath, CSIDL_WINDOWS, FALSE);

	return(CPathTools::AddBackSlash(szPath));
}

/*!
	System32 パス取得
*/
CString CPathTools::GetSystem32Path()
{
	TCHAR szPath[_MAX_PATH];

	SHGetSpecialFolderPath(NULL, szPath, CSIDL_SYSTEM, FALSE);

	return(CPathTools::AddBackSlash(szPath));
}

/*!
	Program Files パス取得
*/
CString CPathTools::GetProgramFilesPath()
{
	TCHAR szPath[_MAX_PATH];

	SHGetSpecialFolderPath(NULL, szPath, CSIDL_PROGRAM_FILES, FALSE);

	return(CPathTools::AddBackSlash(szPath));
}


/*!
	All Users/Application Data パス取得
*/
CString CPathTools::GetCommonAppDataPath()
{
	TCHAR szPath[_MAX_PATH];

	SHGetSpecialFolderPath(NULL, szPath, CSIDL_COMMON_APPDATA, FALSE);

	return(CPathTools::AddBackSlash(szPath));
}


/*********************************************************************/
/*	CFileTimeAccess	*/
/*********************************************************************/
//////////////////////////////////////////////////////////////////////
// CFileTimeAccess
//////////////////////////////////////////////////////////////////////
//	時刻取得
int CFileTimeAccess::GetFileTime(CString path)
{
	//	開く
	HANDLE hFile;
	SECURITY_ATTRIBUTES Sec;
	Sec.nLength = sizeof(SECURITY_ATTRIBUTES);
	Sec.lpSecurityDescriptor = NULL;
	Sec.bInheritHandle = FALSE;
	if((hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, &Sec, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL)) == INVALID_HANDLE_VALUE)
		return(-1);

	//	時刻取得
	if(::GetFileTime(hFile, &m_cTime, &m_aTime, &m_mTime)==0)
	{
		CloseHandle(hFile);
		return(-1);
	}

	CloseHandle(hFile);
	return(0);
}

//	時刻設定
int CFileTimeAccess::SetFileTime(CString path)
{
	DWORD Attr;

	// GENERIC_WRITEを指定するためにReadOnlyを解除
	if((Attr = GetFileAttributes(path)) != 0xFFFFFFFF)
		SetFileAttributes(path, Attr & ~FILE_ATTRIBUTE_READONLY);

	//	開く
	HANDLE hFile;
	SECURITY_ATTRIBUTES Sec;
	Sec.nLength = sizeof(SECURITY_ATTRIBUTES);
	Sec.lpSecurityDescriptor = NULL;
	Sec.bInheritHandle = FALSE;
	if((hFile = CreateFile(path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, &Sec, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL)) == INVALID_HANDLE_VALUE)
		return(-1);

	//	時刻が不完全？
	if(m_cTime == 0 || m_aTime == 0 || m_mTime == 0)
	{
		CFileTime	cTime,aTime,mTime;
		if(::GetFileTime(hFile, &cTime, &aTime, &mTime)==0)
		{
			CloseHandle(hFile);
			return(-1);
		}

		//	修正
		if(m_cTime == 0)
			m_cTime = cTime;
		if(m_aTime == 0)
			m_aTime = aTime;
		if(m_mTime == 0)
			m_mTime = mTime;
	}

	//	設定
	::SetFileTime(hFile, &m_cTime, &m_aTime, &m_mTime);
	CloseHandle(hFile);

	// アトリビュートを元に戻しておく
	if(Attr != 0xFFFFFFFF)
		SetFileAttributes(path, Attr);

	return(0);
}


int CFileTimeAccess::GetFileTime(HANDLE hFile)
{
	//	時刻取得
	if(::GetFileTime(hFile, &m_cTime, &m_aTime, &m_mTime)==0)
	{
		return(-1);
	}
	return(0);
}

int CFileTimeAccess::SetFileTime(HANDLE hFile)
{
	if(::SetFileTime(hFile, &m_cTime, &m_aTime, &m_mTime)==0)
	{
		return(-1);
	}
	return(0);
}

//	時間変換
CFileTime CFileTimeAccess::CTimeToCFileTime(CTime time)
{
	if(time == 0)
		return(0);

	SYSTEMTIME timeDest;
	time.GetAsSystemTime(timeDest);
	FILETIME fileTime,fileTimeLocal;
	::SystemTimeToFileTime(&timeDest, &fileTime);
	::LocalFileTimeToFileTime(&fileTime,&fileTimeLocal);

	return(fileTimeLocal);
}	

