/////////////////////////////
// ECCSkelton
// CEXTCHKクラス定義ファイル
// Copyright (c) August, 2022
//        By Ysama
/////////////////////////////
//////////////////////////////////////////////////////////
// OPENFILENAME構造体のlpstrFilterを用いた拡張子チェック
// Extension Check Class using OPENFILENAME's lpstrFilter
// OPENFILENAME's lpstrFilterの構造
// （表示文字列\0）
// （拡張子データ文字列\0）
// ......
// （表示文字列\0）
// （拡張子データ文字列\0）\0←最終NULL
// なお、拡張子データ文字列は"*.ext1;*.ext2;*ext3...\0"と
// いう書式により複数の拡張子を対象とすることができる
//////////////////////////////////////////////////////////
class CEXTCHK
{
public:
	//メンバー変数
	int m_Count = 0;				//拡張子数
	WCHAR** m_Ext = 0;				//拡張子配列
	//メンバー関数
	~CEXTCHK();						//デストラクター
	void Init();					//全てのメンバー変数を初期化する
	int GetExt(WCHAR*, WCHAR**&);	//'.'付小文字拡張子配列を返す
	void ConvertUC();				//'.'付大文字拡張子配列を返す（必ずGetExt関数の後に使う）
	int CheckExt(WCHAR*, WCHAR*);	//フルパスファイル名の拡張子チェック（1〜ベースの拡張子番号を返す）
};

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

	Init();
}

//全てのメンバー変数を初期化する
void CEXTCHK::Init() {
	if(m_Count) {							//拡張子配列があれば
		for(int i = 0; i < m_Count; i++)	//すべての
			delete [] m_Ext[i];				//拡張子文字列配列を解放する
	}
	delete [] m_Ext;						//最後にポインター配列を解放する
	m_Count = 0;							//拡張子数
	m_Ext = 0;								//拡張子配列
}

//'.'付小文字拡張子配列を返す
int CEXTCHK::GetExt(WCHAR* src, WCHAR**& pext) {

	if(m_Count)								//既に使われた場合
		Init();								//再初期化する
	WCHAR *cp1, *cp2, *cp3;					//処理用文字列ポインター
	cp1 = src;								//ソース文字列をセット
	while(*cp1) {							//cp1が二重のNULL（\0\0）を指すまで
		//最初の表示用文字列をスキップする
		cp1 += lstrlenW(cp1) + 1;			//cp1を次のNULL（L'\0'）の次まで進める
		//cp1〜3はデータ文字列（*.ext1;*.ext2;*.ext3;\0）を指している
		cp3 = cp2 = cp1;
		//ここからはcp2を先頭に置き、cp3を前に進める
		while(*cp3) {						//cp3を次のNULLまで進める
			//大文字は小文字に変換する
			if(*cp3 >= L'A' && *cp3 <= L'Z')
				*cp3 += L'a' - L'A';
			//';'で区切られた複数の拡張子設定の場合
			if(*cp3 == L';') {				//L';'の場合もNULLと同様の処理を行う
				//文字列配列ポインターextを作り、m_Extのデータを退避させる
				WCHAR** ext = m_Ext;
				//要素数が一つ多い配列を作る
				m_Ext = new WCHAR*[m_Count + 1];
				//退避した配列の文字列ポインターデータを新しい配列に移す
				for(int i = 0; i < m_Count; i++)
					m_Ext[i] = ext[i];
				//旧m_Extの配列用メモリーを解放
				delete [] ext;
				//追加した配列にアスタリスク以降(cp2 + 1)NULLまでをコピーする
				m_Ext[m_Count] = new WCHAR[cp3 - cp2];				//正しくは「(cp3 - cp2 - 1) + 1」
				wcsncpy(m_Ext[m_Count], cp2 + 1, cp3 - cp2 - 1);	//"(cp2)->*.ext(cp3)->;"
				m_Ext[m_Count][cp3 - cp2 - 1] = L'\0';				//m_Ext[m_Count]の指す文字列の最後にNULLを置く
				//配列の追加が終わったのでカウンターを増加させる
				m_Count++;
				//cp3、cp2を';'の次に進める
				cp3++;
				cp2 = cp3;
			}
			else
				cp3++;
		}
		//文字列ポインター配列を作り、m_Extのデータを退避させる
		WCHAR** ext = m_Ext;
		//要素数が一つ多い配列を作る
		m_Ext = new WCHAR*[m_Count + 1];
		//退避した配列の文字列ポインターデータを新しい配列に移す
		for(int i = 0; i < m_Count; i++)
			m_Ext[i] = ext[i];
		//旧m_Extの配列用メモリーを解放
		delete [] ext;
		//追加した配列にアスタリスク以降(cp2 + 1)NULLまでをコピーする
		m_Ext[m_Count] = new WCHAR[lstrlenW(cp2)];
		lstrcpyW(m_Ext[m_Count], cp2 + 1);
		//配列の追加が終わったのでカウンターを増加させる
		m_Count++;
		//cp1を次の'\0'の次まで進める(表示文字列を指す)
		cp1 = cp3 + 1;
	}
	//第2引数に文字列配列のポインタ―を渡す
	pext = m_Ext;
	//戻り値で文字列配列の要素数を返す
	return m_Count;
}

//'.'付大文字拡張子配列を返す（必ずGetExt関数の後に使う）
void CEXTCHK::ConvertUC() {

	for(int i = 0; i < m_Count; i++) {
		for(WCHAR* cp = m_Ext[i]; *cp; cp++)
			if(*cp >= L'a' && *cp <= L'z')
				*cp -= L'a' - L'A';
	}
}

//フルパスファイル名の拡張子チェック（1〜ベースの拡張子番号を返す）
int CEXTCHK::CheckExt(WCHAR* filename, WCHAR* flt) {

	WCHAR** ext;
	int n = GetExt(flt, ext);
	//小文字チェック
	for(int i = 0; i < n; i++) {
		if(StrStrW(filename, ext[i])) {
			return i + 1;
		}
	}
	ConvertUC();
	//大文字チェック
	for(int i = 0; i < n; i++) {
		if(StrStrW(filename, ext[i])) {
			return i + 1;
		}
	}
	return NULL;
}
