/*
	DirTools.cpp

	ディレクトリ関係の処理を行う

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


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

#include "stdafx.h"
#include "DirTools.h"

#include <direct.h>
#include <shlobj.h>


/*********************************************************************/
/*	CDirIndexer	*/
/*********************************************************************/
//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////
CDirIndexer::CDirIndexer()
{
	m_hFind = INVALID_HANDLE_VALUE;
}

CDirIndexer::~CDirIndexer()
{
	CloseFind();
}

///////////////////////////////////////////////////////////////////////
//	検索命令
///////////////////////////////////////////////////////////////////////
/*!
	ファイルの検索を行う

	\return TRUE:見つかった、FALSE:見つからない
*/
int CDirIndexer::StartFind(CUTF8String fileName)
{
	//	前の検索を終了しておく
	CloseFind();

	//	ファイル名加工(ロングファイル名対応)
	fileName = CPathTools::AddLongPathPrefix(fileName);

	//	パス保存
	m_findPath = CPathTools::PathToDir(fileName);

	//	検索開始
	m_hFind = ::FindFirstFile(_cnvU16(fileName), &m_currentEntry);
	if(m_hFind == INVALID_HANDLE_VALUE)
		return(FALSE);
	return(TRUE);
}

/*!
	次を検索
*/
int CDirIndexer::FindNext()
{
	//	検索していない
	if(m_hFind != INVALID_HANDLE_VALUE)
		return(FALSE);

	//	次を検索
	if(::FindNextFile(m_hFind, &m_currentEntry))
		return(TRUE);

	//	見つからなかった
	CloseFind();
	return(FALSE);
}

/*!
	検索終了
*/
void CDirIndexer::CloseFind()
{
	if(m_hFind != INVALID_HANDLE_VALUE)
		FindClose(m_hFind);
	m_hFind = INVALID_HANDLE_VALUE;
}



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

	CUTF8String	mpath;
	int			ret=0, index = 0;
	while(1)
	{
		index = path.Find(_U8("\\"), index);
		if(index == -1)
			break;

		//	作成
		ret = MakeDirectory(path.Mid(0, index));
		index++;
	}
	return(ret);
}


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

	//	検索してみる
	CDirIndexer	find;
	if(!find.StartFind(path + _U8("\\*.*")))
	{
		//	無いので作る
		if(_wmkdir(_cnvU16(path))==-1)
			return(-1);
		return(1);
	}

	//	あった
	return(0);
}


///////////////////////////////////////////////////////////////////////
//	ファイル
///////////////////////////////////////////////////////////////////////
/*!
	ファイルの存在を確認

	CFileDirTools::FILE_TYPE_FILE		ファイルが存在
	CFileDirTools::FILE_TYPE_DIRECTORY	フォルダが存在
	CFileDirTools::FILE_TYPE_NOTFOUND	なし
*/
int CFileDirTools::FileExist(CUTF8String path)
{
	//	ロングファイル名へ対応
	path = CPathTools::AddLongPathPrefix(path);

	//	"\"で終わってるので、ディレクトリと思われる
	CDirIndexer	find;
	if(CPathTools::CheckBackSlash(path))
	{
		//	ディレクトリインデックスを調べてみる
		if(find.StartFind(path + _U8("*.*")))
			return(FILE_TYPE_DIRECTORY);
		return(FILE_TYPE_NOTFOUND);
	}

	//	調べてみる
	if(find.StartFind(path))
	{
		//	ディレクトリ
		if(find.IsDirectory())
			return(FILE_TYPE_DIRECTORY);

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

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

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

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

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



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

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

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

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

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

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

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

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

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

	return(path);
}

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

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

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


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

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

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

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

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


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

	return(name);
}

/*!
	32Kパスを有効にする（頭に"\\?\"追加）
*/
CUTF8String CPathTools::AddLongPathPrefix(CUTF8String path)
{
	//	パス名加工(\\?\追加して長いパスへ対応)
	if(path.Left(4) != _U8("\\\\?\\"))
		return(_U8("\\\\?\\") + path);

	return(path);
}


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

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

	return(FALSE);
}

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

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

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

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

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

	return(path);
}

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

	return(path);
}

/*!
	最後の文字をチェック
*/
int CPathTools::CheckLastChar(CUTF8String path, unsigned char c)
{
	LPCU8STR	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(CUTF8String path)
{
	return(CheckLastChar(path,'/'));
}

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

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

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

	return(s);
}

/*!
	モジュールパス名取得
*/
CUTF8String 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
*/
CUTF8String CPathTools::GetPathSwapString(CUTF8String path)
{
	//	サイズ取得
	int len = ::ExpandEnvironmentStrings(_cnvU16(path), NULL, 0) + 1;

	//	変換
	CUTF8StringTempBuf	ret;
	LPWSTR	str = ret.AllocUTF16(len);
	::ExpandEnvironmentStrings(_cnvU16(path), str, len);

	return(str);
}

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

	SHGetSpecialFolderPath(NULL, szPath, CSIDL_WINDOWS, FALSE);

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

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

	SHGetSpecialFolderPath(NULL, szPath, CSIDL_SYSTEM, FALSE);

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

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

	SHGetSpecialFolderPath(NULL, szPath, CSIDL_PROGRAM_FILES, FALSE);

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


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

	SHGetSpecialFolderPath(NULL, szPath, CSIDL_COMMON_APPDATA, FALSE);

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