【C/C++】ファイルパスに指定の拡張子(複数)が含まれるか安全にチェックする

ファイルパスの拡張子を単一の拡張子と比較する処理はネット上で散見されますが、ここではカンマ区切りの複数拡張子を安全に比較する処理を紹介します。 

#include <stdio.h>
#include <string.h>

bool CheckExtension(const char *pszPath, const char *pszCmpExts){

   // ファイルパスの拡張子を抽出
   const char *pszExt = strrchr(pszPath, '.');
   if(pszExt && *(pszExt + 1) != '\0'){
      pszExt += 1;
   }else{
      return false; // ファイルパスに拡張子が存在しない場合はfalse
   }

   // 拡張子をチェック(大文字小文字区別あり)
   char szCmpExts[1024];
   strncpy(szCmpExts, pszCmpExts, sizeof(szCmpExts)-1);
   for(const char *pszCmpExt = strtok(szCmpExts, ","); pszCmpExt; pszCmpExt = strtok(NULL, ",")){
      if(strcmp(pszExt, pszCmpExt) == 0) return true;
   }
   return false;
}

int main(){
   CheckExtension("ほげ.jpg", "jpg");     // true
   CheckExtension("ほげ.jpg", "png,jpg"); // true
   CheckExtension("ほげ.jpg", "JPG");     // false
   return 0;
}
 

ファイルパスから拡張子を抽出する処理では、strrchrでパスの後方から"."の位置を取得します。
"."は複数箇所に含まれる可能性があるため、strchrやstrstrでパスの前方から検索してはいけません。
また、拡張子無し("."なし)のファイルパスが渡される可能性もあるため、strrchrの戻り値は必ずNULLチェックする必要があります。

拡張子のチェック処理では、カンマ区切りで渡された拡張子をstrtokで分解し、strcmpで拡張子を比較しています。拡張子の大文字小文字を区別しない場合はstricmpやstrcasecmpで比較を行ってください。

 なお、比較可能な拡張子の文字列(szCmpExts)は1024文字(終端含む)で固定としています。通常の使用ではオーバーしませんが、必要に応じて動的にszCmpExtsを確保してください。