//-----------------------
//        CSTR.h
// Copyright January 2002
// 		By K. Yoshida
// 		Version 1.0A
// CSTR Class ヘッダー
//-----------------------
#ifndef	_CSTR_
#define _CSTR_

class CSTR {

	char*	m_str;

public:
	CSTR();									//コンストラクター（無）
	CSTR(const char*);						//コンストラクター（文字列）
	CSTR(const CSTR&);						//コンストラクター（CSTR）
	CSTR(const long);						//コンストラクター（整数）
	~CSTR();								//デストラクター
	CSTR& operator = (const char*);			//operator = (B) ---> = B;
	CSTR& operator = (const CSTR&);			//operator = (B) ---> = B;
	CSTR& operator = (const long);			//operator = (B) ---> = B;
	char* ToChar() {return m_str;}			//文字列ポインターとして返す
	void Print();							//m_strを印字する
	friend CSTR operator + (const CSTR&, const CSTR&);	//A operator + (B) --->= A + B;
	friend bool operator == (const CSTR&, const CSTR&);	//A operator == (B) --->= A == B;
	friend bool operator == (const CSTR&, const char*);	//A operator == (B) --->= A == B;
	friend bool operator != (const CSTR&, const CSTR&);	//A operator == (B) --->= A != B;
	friend bool operator != (const CSTR&, const char*);	//A operator == (B) --->= A != B;
	bool FromFile(char*, char*, HWND);		//ファイルからの読込
	bool FromFile(char*);					//ファイルからの読込
	bool ToFile(char* , char* , HWND);		//ファイルへの書き込み
	bool ToFile(char*);						//ファイルへの書き込み
	bool Next(CSTR&);						//m_strの単語を切り取り出す
	bool GetLine(CSTR&);					//この行末まで進む
	bool NextLine();						//次の行頭まで進む
	char* Find(char*, char*);				//文字列の検索
	char* Replace(char*, char*, char*);		//文字列の置換
	void ReplaceAll(char*, char*, char*);	//文字列の全置換
};

//コンストラクター（無）
CSTR::CSTR() {

	m_str = new char[1];
	*m_str = NULL;
}

//コンストラクター（文字列）
CSTR::CSTR(const char* string) {

	m_str = new char[lstrlen(string) + 1];
	lstrcpy(m_str, string);
}

//コンストラクター（CSTR）
CSTR::CSTR(const CSTR& cst) {

	m_str = new char[lstrlen(cst.m_str) + 1];
	lstrcpy(m_str, cst.m_str);
}

//コンストラクター（整数）
CSTR::CSTR(const long i) {

	char sbuff[MAX_PATH / 8];
	wsprintf(sbuff, "%d", i);
	m_str = new char[lstrlen(sbuff) + 1];
	lstrcpy(m_str, sbuff);
}

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

	delete [] m_str;
}

//char文字列の代入
CSTR& CSTR::operator = (const char* str) {

	delete [] m_str;
	m_str = new char[lstrlen(str) + 1];
	lstrcpy(m_str, str);
	return *this;
}

//CSTRの代入
CSTR& CSTR::operator = (const CSTR& cst) {

	if(&cst != this) {	//You can't copy yourself
		delete [] m_str;
		m_str = new char[lstrlen(cst.m_str) + 1];
		lstrcpy(m_str, cst.m_str);
	}
	return *this;
}

//整数の代入
CSTR& CSTR::operator = (const long i) {

	char sbuff[MAX_PATH / 8];
	wsprintf(sbuff, "%d", i);
	delete [] m_str;
	m_str = new char[lstrlen(sbuff) + 1];
	lstrcpy(m_str, sbuff);
	return *this;
}

//m_strを印字する
void CSTR::Print() {

	MessageBox(NULL, m_str, "CSTR Message", MB_OK);
}

//追加演算子の定義
CSTR operator + (const CSTR& cst1, const CSTR& cst2) {

	CSTR CSTR;
	delete [] CSTR.m_str;
	CSTR.m_str = new char[lstrlen(cst1.m_str) + lstrlen(cst2.m_str) + 1];
	lstrcpy(CSTR.m_str, cst1.m_str);
	lstrcat(CSTR.m_str, cst2.m_str);
	return CSTR;
}

//比較演算子の定義（１）
bool operator == (const CSTR& cst1, const CSTR& cst2) {

	return !lstrcmp(cst1.m_str, cst2.m_str);
}

//比較演算子の定義（２）
bool operator == (const CSTR& cst, const char* str) {

	return !lstrcmp(cst.m_str, str);
}

//比較演算子の定義（３）
bool operator != (const CSTR& cst1, const CSTR& cst2) {

	return lstrcmp(cst1.m_str, cst2.m_str);
}

//比較演算子の定義（４）
bool operator != (const CSTR& cst, const char* str) {

	return lstrcmp(cst.m_str, str);
}

//ファイルからの読込
bool CSTR::FromFile(char* Filter, char* FilePath, HWND hWnd = NULL) {

	char FileName[MAX_PATH];
	char file_path[MAX_PATH];
	lstrcpy(file_path, FilePath);	//Default Path
	OPENFILENAME ofn;				//オープンファイルダイアログ構造体

	ZeroMemory(&ofn, sizeof(ofn));	//ゼロ初期化
	FileName[0] = NULL;

	ofn.lStructSize		= sizeof(ofn);
	ofn.hwndOwner		= hWnd;
	ofn.lpstrFilter		= Filter;
	ofn.nFilterIndex	= 1;
	ofn.lpstrFile		= FileName;
	ofn.nMaxFile		= MAX_PATH;
	if(!*file_path)					//規定値のNULLであれば現在のディレクトリー
		GetCurrentDirectory(MAX_PATH, file_path);
	ofn.lpstrInitialDir = file_path;
	ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
	if(!GetOpenFileName(&ofn))	return FALSE;		//読み込み結果

	BOOL bSuccess = FALSE;
	HANDLE hFile;
	hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL,
						OPEN_EXISTING, NULL, NULL);	//ファイルを読込みでオープン
	if(hFile != INVALID_HANDLE_VALUE) {				//オープンできたか
		DWORD dwFileSize = GetFileSize(hFile, NULL);
		if(dwFileSize != 0xFFFFFFFF) {				//-1は(0xFFFFFFFF)エラー
			delete [] m_str;						//元の文字列を廃棄して
			m_str = new char[dwFileSize + 1];		//読み込んだデータとNULL終端を入れられるようにする
			DWORD dwRead;
			if(ReadFile(hFile, m_str, dwFileSize, &dwRead, NULL)) {
				m_str[dwFileSize] = 0; 				//念のため、バッファの終端にNULLを置く
				bSuccess = TRUE;					//読み込み成功
			}
		}
		CloseHandle(hFile);							//ファイルのクローズ
	}
	return bSuccess;
}

//ファイルからの読込
bool CSTR::FromFile(char* FileName) {

	BOOL bSuccess = FALSE;
	HANDLE hFile;
	hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL,
						OPEN_EXISTING, NULL, NULL);	//ファイルを読込みでオープン
	if(hFile != INVALID_HANDLE_VALUE) {				//オープンできたか
		DWORD dwFileSize = GetFileSize(hFile, NULL);
		if(dwFileSize != 0xFFFFFFFF) {				//-1は(0xFFFFFFFF)エラー
			delete [] m_str;						//元の文字列を廃棄して
			m_str = new char[dwFileSize + 1];		//読み込んだデータとNULL終端を入れられるようにする
			DWORD dwRead;
			if(ReadFile(hFile, m_str, dwFileSize, &dwRead, NULL)) {
				m_str[dwFileSize] = 0; 				//念のため、バッファの終端にNULLを置く
				bSuccess = TRUE;					//読み込み成功
			}
		}
		CloseHandle(hFile);							//ファイルのクローズ
	}
	return bSuccess;
}

//ファイルへの書き込み
bool CSTR::ToFile(char* Filter, char* Default, HWND hWnd = NULL) {

	char FileName[MAX_PATH];
	char file_path[MAX_PATH];
	OPENFILENAME ofn;				//オープンファイルダイアログ構造体

	ZeroMemory(&ofn, sizeof(ofn));	//ゼロ初期化
	FileName[0] = NULL;

	ofn.lStructSize		= sizeof(ofn);
	ofn.hwndOwner		= hWnd;
	ofn.lpstrFilter		= Filter;
	ofn.nFilterIndex	= 1;
	ofn.lpstrFile		= FileName;
	ofn.nMaxFile		= MAX_PATH;
	GetCurrentDirectory(MAX_PATH, file_path);
	ofn.lpstrInitialDir = file_path;
	ofn.lpstrDefExt		= Default;		//デフォルトの拡張子
	ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY |
				OFN_OVERWRITEPROMPT;

	if(!GetSaveFileName(&ofn))	return FALSE;;

	BOOL bSuccess = FALSE;
	HANDLE hFile;
	hFile = CreateFile(FileName, GENERIC_WRITE, NULL, NULL,	//ファイルを書込みでオープン
						CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if(hFile != INVALID_HANDLE_VALUE) {				//オープンできたか
		DWORD dwTextLength = lstrlen(m_str) + 1;	//バッファから文字列長取得し、NULL終端も加算
		if(dwTextLength > 0) {						//テキストがあれば以下を実行
			DWORD dwWritten;
			if(WriteFile(hFile, m_str, dwTextLength, &dwWritten, NULL))
				bSuccess = TRUE;					//書込み成功
		}
		CloseHandle(hFile);							//ファイルのクローズ
	}
	return bSuccess;
}

//ファイルへの書き込み
bool CSTR::ToFile(char* FileName) {

	BOOL bSuccess = FALSE;
	HANDLE hFile;
	hFile = CreateFile(FileName, GENERIC_WRITE, NULL, NULL,	//ファイルを書込みでオープン
						CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if(hFile != INVALID_HANDLE_VALUE) {				//オープンできたか
		DWORD dwTextLength = lstrlen(m_str) + 1;	//バッファから文字列長取得し、NULL終端も加算
		if(dwTextLength > 0) {						//テキストがあれば以下を実行
			DWORD dwWritten;
			if(WriteFile(hFile, m_str, dwTextLength, &dwWritten, NULL))
				bSuccess = TRUE;					//書込み成功
		}
		CloseHandle(hFile);							//ファイルのクローズ
	}
	return bSuccess;
}

//m_strの単語を切り取り出す
bool CSTR::Next(CSTR& destination) {

	CSTR str;
	delete [] str.m_str;
	str.m_str = new char[lstrlen(m_str) + 1];
	char* ptr = m_str;
	char* des = str.m_str;
	bool Terminate = TRUE;
	//スペース文字はスキップする
	while(isspace(*ptr) || (*ptr == -0x7F && *(ptr + 1) == 0x40) || *ptr == ',') {
		if(isspace(*ptr) || *ptr == ',')
			ptr++;						//スキップスペース文字
		else {
			ptr++;	ptr++;				//全角"　"もスキップ
		}
	}
	//非スペース文字を調べる
	while(!isspace(*ptr)) {				//スペース文字でない
		if(!*ptr) {						//NULL終端ならFALSEを返す
			Terminate = FALSE;
			break;
		}
		else if(*ptr == -0x7F && *(ptr + 1) == 0x40) {
			break;						//全角"　"なら終了
		}
		else if(*ptr == ',') {
			ptr++;						//','をスキップして次の文字まで進む
			break;						//空白文字扱い
		}
		else if(*ptr == '"') {
			ptr++;						//'"'をスキップして中身だけ取り出す
			while(*ptr != '"') {		//'"'なら'"'まで進む
				if(!*ptr) {				//NULL終端ならFALSEを返す
					Terminate = FALSE;
					break;
				}
				*des = *ptr;
				ptr++;	des++;
			}
			ptr++;						//ソースポインターは次の文字へ進める
			break;						//ループを抜けてデスティネーションはNULLが入る
		}
		else if(*ptr == '/' && *(ptr + 1) == '*') {
			ptr++;	ptr++;				//"/*〜*/"コメント
			while(!(*ptr == '*' && *(ptr + 1) == '/')) {
				if(!*ptr) {				//NULL終端ならFALSEを返す
					Terminate = FALSE;
					break;
				}
				ptr++;
			}
			ptr++;	ptr++;
			//再度スペース文字をスキップする
			while(isspace(*ptr) || (*ptr == -0x7F && *(ptr + 1) == 0x40) || *ptr == ',') {
				if(!*ptr) {				//NULL終端ならFALSEを返す
					Terminate = FALSE;
					break;
				}
				if(isspace(*ptr) || *ptr == ',')
					ptr++;				//スキップスペース文字
				else {
					ptr++;	ptr++;		//全角"　"もスキップ
				}
			}
			continue;
		}
		else if(*ptr == '/' && *(ptr + 1) == '/') {
			while(*ptr != '\n') {		//"//"コメント
				if(!*ptr) {				//NULL終端ならFALSEを返す
					Terminate = FALSE;
					break;
				}
				ptr++;
			}
			while(isspace(*ptr) || (*ptr == -0x7F && *(ptr + 1) == 0x40) || *ptr == ',') {
				if(!*ptr) {				//NULL終端ならFALSEを返す
					Terminate = FALSE;
					break;
				}
				if(isspace(*ptr) || *ptr == ',')
					ptr++;				//スキップスペース文字
				else {
					ptr++;	ptr++;		//全角"　"もスキップ
				}
			}
			continue;
		}
		else {
			*des = *ptr;
		}
		ptr++;	des++;
	}
	*des = NULL;

	destination = str;			//destinationに切り取った文字列を代入
	str = ptr;					//strにm_strより進んだptr以降の文字列を代入
	delete [] m_str;
	m_str = new char[lstrlen(str.m_str) + 1];
	strcpy(m_str, str.m_str);	//m_strには切り取った後の文字列が入る
	if(*str.m_str || *destination.m_str)
		Terminate = TRUE;		//残がNULLだけでも切り取った文字列があれば続ける
	else
		Terminate = FALSE;		//NULLだけなら終わり
	return Terminate;			//成功･失敗フラグを返す
}

//この行末まで進む
bool CSTR::GetLine(CSTR& destination) {

	bool Terminate = TRUE;
	char* ptr = m_str;
	char* des = ptr;
	while(*des && *des != '\n')
		des++;
	if(!*des) {
		destination = "";
		Terminate = FALSE;	//文字列の終了サイン
	}
	else {
		*des = NULL; des++;				//NULL終端させ、一つ進める
		delete destination.m_str;
		destination.m_str = new char[des - ptr + 1];
		strcpy(destination.m_str, ptr);
		destination.m_str[des - ptr - 1] = '\n';//NULLにした'\n'を付加
		destination.m_str[des - ptr] = NULL;	//NULL終端
	}
	if(Terminate) {					//まだ文字列があれば残りを入れる
		CSTR str = des;
		delete [] m_str;
		m_str = new char[lstrlen(str.m_str) + 1];
		strcpy(m_str, str.m_str);	//m_strには切り取った後の文字列が入る
	}
	if(*destination.m_str)			//NULLに出会ったが、
		Terminate = TRUE;			//切り取った文字列があれば続ける
	else
		Terminate = FALSE;			//NULLだけなら終わり
	return Terminate;				//成功･失敗フラグを返す
}

//次の行頭まで進む
bool CSTR::NextLine() {

	char* ptr = m_str;
	while(*ptr != '\n') {		//改行コードまで進む
		if(!*ptr) {				//途中でNULL終端したならFALSEを返す
			return FALSE;
		}
		ptr++;
	}
	ptr++;
	CSTR str = ptr;
	delete [] m_str;
	m_str = new char[lstrlen(str.m_str) + 1];
	strcpy(m_str, str.m_str);	//m_strには切り取った後の文字列が入る
	return TRUE;				//成功･失敗フラグを返す
}

//文字列の検索
char* CSTR::Find(char* ToFind, char* sp = 0) {

	if(!sp)
		sp = m_str;
	return strstr(sp, ToFind);
}

//文字列の置換
char* CSTR::Replace(char* ToFind, char* ToReplace, char* sp = 0) {

	//CSTRのデータ長、検索文字長、置換文字長を計算する
	int OrgLen = lstrlen(m_str);
	int ToFindLen = lstrlen(ToFind);
	int ToReplaceLen = lstrlen(ToReplace);
	//spの指定が無ければCSTRデータの先頭から検索する
	if(!sp)
		sp = m_str;
	//検索文字列ポインターの取得
	char* Found_at = strstr(sp, ToFind);		//検索文字列が無ければNULLを返す
	//検索文字があれば
	if(Found_at) {
		DWORD dspl = Found_at - m_str;			//Found_atのm_str内の相対位置
		//置換後の文字列データバッファー（NULL終端付）の確保
		char* buff = new char[OrgLen - ToFindLen + ToReplaceLen + 1];
		*Found_at = NULL;						//NULL終端
		lstrcpy(buff, m_str);					//検索文字列（ToFind）までをbuffにコピー
		lstrcat(buff, ToReplace);				//検索文字列（ToFind）の代わりに置換文字列をコピー
		lstrcat(buff, Found_at + ToFindLen);	//検索文字列（ToFind）以降の文字列をコピー
		buff[OrgLen - ToFindLen + ToReplaceLen] = NULL;	//NULL終端を付ける
		delete [] m_str;						//CSTRデータ（m_str）を削除
		m_str = new char[OrgLen - ToFindLen + ToReplaceLen + 1];	//新しいデータ領域を確保
		lstrcpy(m_str, buff);					//置換後のデータをコピー
		Found_at = m_str + dspl;				//Found_atのm_str内の相対位置
		delete [] buff;							//文字列データバッファーを破棄
	}
	return Found_at;	//置換できなかった場合NULL、できた場合置換文字列の先頭ポインター
}

//文字列の全置換
void CSTR::ReplaceAll(char* ToFind, char* ToReplace, char* sp = 0) {

	char* Next = sp;
	while((Next = Replace(ToFind, ToReplace, Next)))
		Next += lstrlen(ToReplace);
}

#endif
