///////////////////////////////////
// ファイルクラスCFILE定義ファイル
///////////////////////////////////

class CFILE
{
private:	//メンバー変数
	HGLOBAL	m_hMem;					//メモリーブロックハンドル
	char	m_FileName[MAX_PATH];	//ファイル名
	char*	m_FilePtr;				//グローバルメモリーへのポインター（文字列型）
public:	//メンバー変数
	DWORD	m_FileSize;				//ファイルサイズ
	char*	m_Ptr;					//バッファ内のポインター（文字列型）

public:		//メンバー関数
	CFILE();						//コンストラクター（純粋な初期化）
	CFILE(char*, DWORD);			//コンストラクター（ファイルを作る）
	~CFILE();						//デストラクター
	char*	OpenFile(char*, DWORD);	//ファイルを開く
	char*	LoadFile(char*);		//ファイルを読み込む
	char*	SetFileSize(DWORD);		//ファイルサイズを設定
	bool	SaveFile();				//ファイルを書き込むする
	bool	CloseFile();			//ファイルを閉める
	bool	KillFile();				//ファイルを消去する
	bool	RenFile(char*);			//ファイル名の変更
	char*	GoTop();				//ファイルの先頭へ行く
	char*	GoBottom();				//ファイルの終わりにゆく
	char*	Read();					//ファイルバッファ内の文字列を読む
	char*	Write(char*);			//ファイルバッファ内に文字列を書き込む
	char*	Find(char*);			//ファイルバッファ内の文字列を現在位置から探す
	bool	Replace(char*, char*);	//ファイルバッファ内の文字列を置換する
	DWORD	GetTextSize();			//ファイルバッファ内の文字列の長さを返す
	bool	GetEditText(HWND);		//エディットコントロールから文字列を取り込む
	bool	PutEditText(HWND);		//エディットコントロールに文字列を表示する
};

//コンストラクター（純粋な初期化）
CFILE::CFILE() {

	m_hMem = 0;					//ファイルハンドル
	*m_FileName = NULL;			//ファイル名
	m_FilePtr = m_Ptr = NULL;	//グローバルメモリーへのポインター（文字列型）
	m_FileSize = 0;				//ファイルサイズ
}

//コンストラクター（ファイルを作る）
CFILE::CFILE(char* FileName, DWORD FileSize) {

	OpenFile(FileName, FileSize);
}

//デストラクター
CFILE::~CFILE() {

	GlobalFree(m_hMem);	//グローバルメモリーの解放
}

//ファイルを作る
char* CFILE::OpenFile(char* FileName, DWORD FileSize) {

	if(m_hMem) {		//既にファイルが存在している時は
		CloseFile();	//閉じて、グローバルメモリーを解放する
	}
	if(lstrlen(FileName) > MAX_PATH)	FileName[MAX_PATH] = NULL;
	lstrcpy(m_FileName, FileName);	//パス・ファイル名はMAX_PATHまで
	m_FileSize = FileSize;			//ファイルサイズ記録
	m_hMem = GlobalAlloc(GHND, m_FileSize + 1);
	if(!m_hMem == NULL)
		return (m_Ptr = m_FilePtr = (char*)GlobalLock(m_hMem));
	else {
		MessageBox(NULL, "ファイルをオープンできませんでした", "エラー",
					MB_OK | MB_ICONSTOP);
		return (m_Ptr = m_FilePtr = NULL);
	}
}

//ファイルを読み込む
char* CFILE::LoadFile(char* FileName) {

	if(m_hMem) {		//既にファイルが存在している時は
		CloseFile();	//閉じて、グローバルメモリーを解放する
	}
	if(lstrlen(FileName) > MAX_PATH)	FileName[MAX_PATH] = NULL;
	lstrcpy(m_FileName, FileName);	//パス・ファイル名はMAX_PATHまで
	HANDLE hFile = CreateFile(m_FileName, GENERIC_READ,
						FILE_SHARE_READ, NULL,
						OPEN_ALWAYS, NULL, NULL);	//ファイルを読込でオープン
	if(hFile != INVALID_HANDLE_VALUE) {	//オープンできたか
		m_FileSize = GetFileSize(hFile, NULL);		//ファイルサイズを取る
		if(m_FileSize != 0xFFFFFFFF) {				//-1は(0xFFFFFFFF)エラー
			m_hMem = GlobalAlloc(GHND, m_FileSize + 1);
			if(m_hMem != NULL) {
				m_FilePtr = (char*)GlobalLock(m_hMem);
				if(m_FilePtr) {	//バッファーを設定できたか？
					DWORD dwRead;
					ReadFile(hFile, m_FilePtr, m_FileSize, &dwRead, NULL);
					m_FilePtr[m_FileSize] = 0; //ファイルの終端にNULLを置く
				}
			}
		}
		CloseHandle(hFile);				//ファイルのクローズ
		return (m_Ptr = m_FilePtr);
	}
	MessageBox(NULL, "ファイルを読み込めませんでした", "エラー",
				MB_OK | MB_ICONSTOP);
	m_hMem = 0;
	return NULL;
}

//ファイルサイズを設定
char* CFILE::SetFileSize(DWORD NewSize) {

	m_FileSize = NewSize;
	m_hMem = GlobalReAlloc(m_hMem, m_FileSize + 1,
							GMEM_MOVEABLE | GMEM_ZEROINIT);
	if(m_hMem != NULL) {
		m_FilePtr[m_FileSize] = 0; //ファイルの終端にNULLを置く
		return (m_Ptr = m_FilePtr = (char*)GlobalLock(m_hMem));
	}
	else {
		MessageBox(NULL, "ファイルサイズを変更できませんでした", "エラー",
					MB_OK | MB_ICONSTOP);
		return NULL;
	}
}

//ファイルをセーブする
bool CFILE::SaveFile() {

	bool bSuccess = FALSE;
	HANDLE hFile = CreateFile(m_FileName, GENERIC_WRITE,
						FILE_SHARE_READ, NULL,
						OPEN_ALWAYS, NULL, NULL);	//ファイルを読込でオープン
	if(hFile != INVALID_HANDLE_VALUE) {				//オープンできたか
		if(GetLastError() == ERROR_ALREADY_EXISTS) {	//ファイル存在フラグ記録
			if(MessageBox(NULL, "上書きしますか？", "上書確認",
							MB_YESNO) == IDNO) {
				CloseHandle(hFile);					//ファイルのクローズ
				return bSuccess;
			}
		}
		DWORD dwWritten;
		SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
		m_FileSize = GetTextSize();
		if(WriteFile(hFile, m_FilePtr, m_FileSize, &dwWritten, NULL))
			bSuccess = TRUE;
		CloseHandle(hFile);							//ファイルのクローズ
	}
	else {
		MessageBox(NULL, "ファイルを書き込めませんでした", "エラー",
					MB_OK | MB_ICONSTOP);
	}
	return bSuccess;
}

//ファイルを閉める
bool CFILE::CloseFile() {

	GlobalFree(m_hMem);		//グローバルメモリーの解放
	m_hMem = 0;				//ファイルハンドル
	*m_FileName = NULL;		//ファイル名
	m_FilePtr = m_Ptr = 0;	//グローバルメモリーへのポインター（文字列型）
	m_FileSize = 0;			//ファイルサイズ
	return TRUE;
}

//ファイルを消す
bool CFILE::KillFile() {

	if(MessageBox(NULL, "ファイルを消去しますか？", "消去確認",
					MB_YESNO)  == IDNO)
		return FALSE;
	CloseFile();				//ファイルを閉める
	DeleteFile(m_FileName);		//閉じたファイルを削除する
	return TRUE;
}

//ファイル名の変更
bool CFILE::RenFile(char* NewFile) {

	return lstrcpy(m_FileName, NewFile);
}

//ファイルの先頭へ行く
char*	CFILE::GoTop() {

	return (m_Ptr = m_FilePtr);
}

//ファイル（ファイル内のテキスト）の終わりにゆく
char*	CFILE::GoBottom() {

	char* cp = m_FilePtr;
	while(*cp) cp++;
	m_Ptr = cp > (m_FilePtr + m_FileSize) ? (m_FilePtr + m_FileSize) : cp;
	return m_Ptr;
}

//バッファ内の文字列を読む
char*	CFILE::Read() {

	return m_Ptr;
}

//バッファ内に文字列を書き込む
char*	CFILE::Write(char* str) {

	if(lstrlen(str) > (m_FilePtr + m_FileSize - m_Ptr)) {
		MessageBox(NULL, "文字列が長すぎます", "エラー",
					MB_OK | MB_ICONSTOP);
		return NULL;
	}
	for(int i = 0, j = lstrlen(str); i < j; i++) {
		*m_Ptr = str[i];
		m_Ptr++;
	}
	return m_Ptr;	//書き込んだ文字列分先に進んだポインターを返す
}

//バッファ内の文字列を現在位置から探す
char*	CFILE::Find(char* str) {

	return strstr(m_Ptr, str);
}

//ファイルバッファ内の文字列を置換する
bool CFILE::Replace(char* org, char* sub) {

	char* cp = m_Ptr;
	int orglen = lstrlen(org);
	int sublen = lstrlen(sub);
	int lendiff = sublen - orglen;
	bool bSuccess = FALSE;
	while((cp = strstr(cp, org))) {	//org文字列を探す
		//有ればバッファサイズを変更して、文字列長から後の文字列を移動する
		if(lendiff >= 0) {
			int offset = cp - m_Ptr;	//メモリーブロックを増やす場合は
			SetFileSize(m_FileSize + lendiff);
			cp = m_Ptr + offset;		//m_Ptrが変わり得るので再設定する
			MoveMemory (cp + sublen, cp + orglen, lstrlen(cp + orglen));
			for(int i = 0, j = lstrlen(sub); i < j; i++) cp[i] = sub[i];
		}
		else {
			MoveMemory (cp + sublen, cp + orglen, lstrlen(cp + orglen));
			for(int i = 0, j = lstrlen(sub); i < j; i++) cp[i] = sub[i];
			SetFileSize(m_FileSize + lendiff);	//減る場合は要らない
		}
		bSuccess =TRUE;
	}
	return bSuccess;
}

//ファイルバッファ内の文字列の長さを返す
DWORD CFILE::GetTextSize() {

	return (GoBottom() - m_FilePtr + 1); 
}

//エディットコントロールから文字列を取り込む
bool CFILE::GetEditText(HWND hWnd) {

	SetFileSize(SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0));
	return SendMessage(hWnd, WM_GETTEXT, m_FileSize + 1, (LPARAM)m_FilePtr);
}

//エディットコントロールに文字列を表示する
bool CFILE::PutEditText(HWND hWnd) {

	return SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)m_FilePtr);
}
