それでは前回のクイズの私なりの回答を紹介します。ポインターとメモリー割り当てを使ってC++っぽい感じがするのではないでしょうか?(勿論、関数、クラスを問わず、これ以外にも多くの回答があり得ます。皆さんも考えてみてください。一つの例として、フィルター文字列のデータ文字列をそのまま記録用にメモリーを割り当ててコピーして、各拡張子部分("*.ext;")を"\0.ext\0"に加工して、配列のポインターを割り当てる、という方法もあると思います。)
私の回答例は、緑字のテストプログラム付きで、そのままコンパイルできるようにしています。何をやっているのかはかなり詳しくコメントに書きましたのでわかると思います。
また、最後のサンプルを外したもの(青字部分)をCEXTCHK.hとしてBCCSkeltonに追加します。BCC55はC++11に合致していないのでメンバー変数の初期化はコンストラクターで行わなければなりませんが、BCC102はC++11を満たしているので不要です。その差異を紫字部分で示しますので参照してください。コードはC++11に適合していなくてもコンパイルできるようにしてあります。
//////////////////////////////////////////////////////////
// OPENFILENAME構造体のlpstrFilterを用いた拡張子チェック
// Extension Check Class using OPENFILENAME's lpstrFilter
// OPENFILENAME's lpstrFilterの構造
// (表示文字列\0)
// (拡張子データ文字列\0)
// ......
// (表示文字列\0)
// (拡張子データ文字列\0)\0←最終NULL
// なお、拡張子データ文字列は"*.ext1;*.ext2;*ext3...\0"と
// いう書式により複数の拡張子を対象とすることができる
//////////////////////////////////////////////////////////
#include <windows.h> //これは単体コンパイルの為に入れているので、CEXTCHK.hでは外しています。
class CEXTCHK
{
public:
//メンバー変数
int m_Count; //拡張子数
char** m_Ext; //拡張子配列
//C++11以降ではメンバー変数宣言時に初期化可能
// int m_Count = 0; //拡張子数
// char** m_Ext = 0; //拡張子配列
//メンバー関数
//C++11以降では初期化コンストラクターは不要
CEXTCHK(); //コンストラクター
~CEXTCHK(); //デストラクター
void Init(); //全てのメンバー変数を初期化する
int GetExt(char*, char**&); //'.'付小文字拡張子配列を返す
void ConvertUC(); //'.'付大文字拡張子配列を返す(必ずGetExt関数の後に使う)
bool CheckExt(char*, char*); //フルパスファイル名の拡張子チェック
};
//C++11以降では初期化コンストラクターは不要
//コンストラクター
CEXTCHK::CEXTCHK() {
m_Count = 0;
m_Ext = 0;
}
//デストラクター
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(char* src, char**& pext) {
if(m_Count) //既に使われた場合
Init(); //再初期化する
char *cp1, *cp2, *cp3; //処理用文字列ポインター
cp1 = src; //ソース文字列をセット
while(*cp1) { //cp1が二重のNULL(\0\0)を指すまで
//最初の表示用文字列をスキップする
cp1 += strlen(cp1) + 1; //cp1を次のNULL(\0)の次まで進める
//cp1~3はデータ文字列(*.ext1;*.ext2;*.ext3;\0)を指している
cp3 = cp2 = cp1;
//ここからはcp2を先頭に置き、cp3を前に進める
while(*cp3) { //cp3を次のNULLまで進める
//大文字は小文字に変換する
if(*cp3 >= 'A' && *cp3 <= 'Z')
*cp3 += 'a' - 'A';
//';'で区切られた複数の拡張子設定の場合
if(*cp3 == ';') { //';'の場合もNULLと同様の処理を行う
//文字列配列ポインターextを作り、m_Extのデータを退避させる
char** ext = m_Ext;
//要素数が一つ多い配列を作る
m_Ext = new char*[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 char[cp3 - cp2]; //正しくは「(cp3 - cp2 - 1) + 1」
strncpy(m_Ext[m_Count], cp2 + 1, cp3 - cp2 - 1); //"(cp2)->*.ext(cp3)->;"
m_Ext[m_Count][cp3 - cp2 - 1] = NULL; //m_Ext[m_Count]の指す文字列の最後にNULLを置く
//配列の追加が終わったのでカウンターを増加させる
m_Count++;
//cp3、cp2を';'の次に進める
cp3++;
cp2 = cp3;
}
else
cp3++;
}
//文字列ポインター配列を作り、m_Extのデータを退避させる
char** ext = m_Ext;
//要素数が一つ多い配列を作る
m_Ext = new char*[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 char[strlen(cp2)];
strcpy(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(char* cp = m_Ext[i]; *cp; cp++)
if(*cp >= 'a' && *cp <= 'z')
*cp -= 'a' - 'A';
}
}
//フルパスファイル名の拡張子チェック
bool CEXTCHK::CheckExt(char* filename, char* flt) {
char** ext;
int n = GetExt(flt, ext);
//小文字チェック
for(int i = 0; i < n; i++) {
if(strstr(filename, ext[i])) {
return TRUE;
}
}
ConvertUC();
//大文字チェック
for(int i = 0; i < n; i++) {
if(strstr(filename, ext[i])) {
return TRUE;
}
}
return FALSE;
}
////////// Sample Program/////////
#include <stdio.h>
#include <conio.h>
#include <stdlib>
#include <iostream>
/////////////////
//サンプルデータ
/////////////////
char* g_Flt = "ビデオファイル(*.avi;*.mp4;*.mov)\0*.avi;*.mp4;*.mov\0オーディオファイル(*.mp3;*.wav;*.mid)\0*.mp3;*.wav;*.mid\0\0";
char* filename = "C:\\Users\\ysama\\Programing\\Windows Program\\DirectShow\\Debug\VideoData\\Butterfly.mp4";
/////////////////
///////////////////////////
//Testコンソールプログラム
///////////////////////////
int main(int argc, char** argv) {
CEXTCHK ec;
char** ext;
int n = ec.GetExt(g_Flt, ext);
for(int i = 0; i < n; i++)
std::cout << ext[i] << std::endl;
fa.ConvertUC();
for(int i = 0; i < n; i++)
std::cout << ext[i] << std::endl;
getch();
std::cout << "<<<Source file ---> " << filename << ">>>" << std::endl;
if(ec.CheckExt(filename, g_Flt))
std::cout << "Found!" << std::endl;
else
std::cout << "Not found!" << std::endl;
getch();
return 0;
}