Просмотр исходного кода

Simplified importer search and fixed a few bugs

The search for a matching importer had a few issues, see #3791. There were two different mechanisms to determine whether an importer accepts a specific file extension:
1. `aiImporterDesc::mFileExtensions`, which was forwarded to the UI via `BaseImporter::GetExtensionList()`.
2. `BaseImporter::CanRead()` when called with `checkSig == false`, which determines whether to actually use that importer.
Both were redundant and got out of sync repeatedly. I removed 2. completely and replaced it with 1., thereby syncing UI/import and shortening all `BaseImporter::CanRead()` implementations.

Further bugfixes:
- fixed glTF2 importer throwing exceptions when checking whether it can load a file
- removed `BaseImporter::SimpleExtensionCheck()` because it is no longer used and had a bug with case sensitivity

Since the `checkSig` parameter in `BaseImporter::CanRead()` is now useless, it can be removed completely. I’m not sure if this would break ABI compatiblity, so I’ll submit it with a later pull request.
Krishty 4 лет назад
Родитель
Сommit
b00de10eb3
51 измененных файлов с 245 добавлено и 658 удалено
  1. 3 14
      code/AssetLib/3DS/3DSLoader.cpp
  2. 5 15
      code/AssetLib/3MF/D3MFImporter.cpp
  3. 3 12
      code/AssetLib/AC/ACLoader.cpp
  4. 3 13
      code/AssetLib/AMF/AMFImporter.cpp
  5. 3 13
      code/AssetLib/ASE/ASELoader.cpp
  6. 2 13
      code/AssetLib/B3D/B3DImporter.cpp
  7. 3 12
      code/AssetLib/BVH/BVHLoader.cpp
  8. 3 12
      code/AssetLib/Blender/BlenderLoader.cpp
  9. 2 8
      code/AssetLib/C4D/C4DImporter.cpp
  10. 3 11
      code/AssetLib/COB/COBLoader.cpp
  11. 3 12
      code/AssetLib/CSM/CSMLoader.cpp
  12. 7 28
      code/AssetLib/Collada/ColladaLoader.cpp
  13. 3 12
      code/AssetLib/DXF/DXFLoader.cpp
  14. 4 12
      code/AssetLib/FBX/FBXImporter.cpp
  15. 7 14
      code/AssetLib/HMP/HMPLoader.cpp
  16. 6 13
      code/AssetLib/IFC/IFCLoader.cpp
  17. 3 17
      code/AssetLib/Irr/IRRLoader.cpp
  18. 7 19
      code/AssetLib/Irr/IRRMeshLoader.cpp
  19. 7 15
      code/AssetLib/LWO/LWOLoader.cpp
  20. 6 14
      code/AssetLib/LWS/LWSLoader.cpp
  21. 13 30
      code/AssetLib/M3D/M3DImporter.cpp
  22. 3 12
      code/AssetLib/MD2/MD2Loader.cpp
  23. 3 12
      code/AssetLib/MD3/MD3Loader.cpp
  24. 3 14
      code/AssetLib/MD5/MD5Loader.cpp
  25. 3 13
      code/AssetLib/MDC/MDCLoader.cpp
  26. 12 17
      code/AssetLib/MDL/MDLLoader.cpp
  27. 3 8
      code/AssetLib/MMD/MMDImporter.cpp
  28. 3 17
      code/AssetLib/MS3D/MS3DLoader.cpp
  29. 3 12
      code/AssetLib/NDO/NDOLoader.cpp
  30. 1 1
      code/AssetLib/NFF/NFFLoader.cpp
  31. 3 12
      code/AssetLib/OFF/OFFLoader.cpp
  32. 4 10
      code/AssetLib/Obj/ObjFileImporter.cpp
  33. 4 8
      code/AssetLib/Ogre/OgreImporter.cpp
  34. 3 10
      code/AssetLib/OpenGEX/OpenGEXImporter.cpp
  35. 3 18
      code/AssetLib/Ply/PlyLoader.cpp
  36. 2 6
      code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp
  37. 3 12
      code/AssetLib/Q3D/Q3DLoader.cpp
  38. 2 2
      code/AssetLib/Raw/RawLoader.cpp
  39. 2 2
      code/AssetLib/SIB/SIBImporter.cpp
  40. 2 2
      code/AssetLib/SMD/SMDLoader.cpp
  41. 3 14
      code/AssetLib/STL/STLLoader.cpp
  42. 3 21
      code/AssetLib/Terragen/TerragenLoader.cpp
  43. 2 2
      code/AssetLib/Unreal/UnrealLoader.cpp
  44. 3 11
      code/AssetLib/X/XFileImporter.cpp
  45. 1 8
      code/AssetLib/X3D/X3DImporter.cpp
  46. 3 17
      code/AssetLib/XGL/XGLLoader.cpp
  47. 6 16
      code/AssetLib/glTF/glTFImporter.cpp
  48. 4 10
      code/AssetLib/glTF2/glTF2Importer.cpp
  49. 2 28
      code/Common/BaseImporter.cpp
  50. 52 7
      code/Common/Importer.cpp
  51. 8 27
      include/assimp/BaseImporter.h

+ 3 - 14
code/AssetLib/3DS/3DSLoader.cpp

@@ -111,20 +111,9 @@ Discreet3DSImporter::~Discreet3DSImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    std::string extension = GetExtension(pFile);
-    if (extension == "3ds" || extension == "prj") {
-        return true;
-    }
-
-    if (!extension.length() || checkSig) {
-        uint16_t token[3];
-        token[0] = 0x4d4d;
-        token[1] = 0x3dc2;
-        //token[2] = 0x3daa;
-        return CheckMagicToken(pIOHandler, pFile, token, 2, 0, 2);
-    }
-    return false;
+bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint16_t token[] = { 0x4d4d, 0x3dc2 /*, 0x3daa */ };
+    return CheckMagicToken(pIOHandler, pFile, token, std::size(token), 0, sizeof token[0]);
 }
 
 // ------------------------------------------------------------------------------------------------

+ 5 - 15
code/AssetLib/3MF/D3MFImporter.cpp

@@ -585,22 +585,12 @@ D3MFImporter::~D3MFImporter() {
     // empty
 }
 
-bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension(GetExtension(filename));
-    if (extension == desc.mFileExtensions) {
-        return true;
-    } else if (!extension.length() || checkSig) {
-        if (nullptr == pIOHandler) {
-            return false;
-        }
-        if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
-            return false;
-        }
-        D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
-        return opcPackage.validate();
+bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
+        return false;
     }
-
-    return false;
+    D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
+    return opcPackage.validate();
 }
 
 void D3MFImporter::SetupProperties(const Importer * /*pImp*/) {

+ 3 - 12
code/AssetLib/AC/ACLoader.cpp

@@ -152,18 +152,9 @@ AC3DImporter::~AC3DImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    std::string extension = GetExtension(pFile);
-
-    // fixme: are acc and ac3d *really* used? Some sources say they are
-    if (extension == "ac" || extension == "ac3d" || extension == "acc") {
-        return true;
-    }
-    if (!extension.length() || checkSig) {
-        uint32_t token = AI_MAKE_MAGIC("AC3D");
-        return CheckMagicToken(pIOHandler, pFile, &token, 1, 0);
-    }
-    return false;
+bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = { AI_MAKE_MAGIC("AC3D") };
+    return CheckMagicToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 13
code/AssetLib/AMF/AMFImporter.cpp

@@ -502,19 +502,9 @@ void AMFImporter::ParseNode_Metadata(XmlNode &node) {
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 
-bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "amf") {
-        return true;
-    }
-
-    if (extension.empty() || pCheckSig) {
-        const char *tokens[] = { "<amf" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-
-    return false;
+bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*pCheckSig*/) const {
+    static const char *tokens[] = { "<amf" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 const aiImporterDesc *AMFImporter::GetInfo() const {

+ 3 - 13
code/AssetLib/ASE/ASELoader.cpp

@@ -97,19 +97,9 @@ ASEImporter::~ASEImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool ASEImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
-    // check file extension
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "ase" || extension == "ask") {
-        return true;
-    }
-
-    if ((!extension.length() || cs) && pIOHandler) {
-        const char *tokens[] = { "*3dsmax_asciiexport" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool ASEImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "*3dsmax_asciiexport" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 2 - 13
code/AssetLib/B3D/B3DImporter.cpp

@@ -92,19 +92,8 @@ B3DImporter::~B3DImporter() {
 }
 
 // ------------------------------------------------------------------------------------------------
-bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
-
-    size_t pos = pFile.find_last_of('.');
-    if (pos == string::npos) {
-        return false;
-    }
-
-    string ext = pFile.substr(pos + 1);
-    if (ext.size() != 3) {
-        return false;
-    }
-
-    return (ext[0] == 'b' || ext[0] == 'B') && (ext[1] == '3') && (ext[2] == 'd' || ext[2] == 'D');
+bool B3DImporter::CanRead(const std::string & /*pFile*/, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/BVH/BVHLoader.cpp

@@ -92,18 +92,9 @@ BVHLoader::~BVHLoader() {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
-    // check file extension
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "bvh")
-        return true;
-
-    if ((!extension.length() || cs) && pIOHandler) {
-        const char *tokens[] = { "HIERARCHY" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "HIERARCHY" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/Blender/BlenderLoader.cpp

@@ -118,18 +118,9 @@ static const char *TokensForSearch[] = { "blender" };
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string &extension = GetExtension(pFile);
-    if (extension == "blend") {
-        return true;
-    }
-
-    if ((!extension.length() || checkSig) && pIOHandler) {
-        // note: this won't catch compressed files
-        return SearchFileHeaderForToken(pIOHandler, pFile, TokensForSearch, 1);
-    }
-
-    return false;
+bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    // note: this won't catch compressed files
+    return SearchFileHeaderForToken(pIOHandler, pFile, TokensForSearch, std::size(TokensForSearch));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 2 - 8
code/AssetLib/C4D/C4DImporter.cpp

@@ -109,14 +109,8 @@ C4DImporter::~C4DImporter() {
 }
 
 // ------------------------------------------------------------------------------------------------
-bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
-    const std::string& extension = GetExtension(pFile);
-    if (extension == "c4d") {
-        return true;
-    } else if ((!extension.length() || checkSig) && pIOHandler)   {
-        // TODO
-    }
-
+bool C4DImporter::CanRead( const std::string& /*pFile*/, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const {
+    // TODO
     return false;
 }
 

+ 3 - 11
code/AssetLib/COB/COBLoader.cpp

@@ -103,17 +103,9 @@ COBImporter::~COBImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string &extension = GetExtension(pFile);
-    if (extension == "cob" || extension == "scn" || extension == "COB" || extension == "SCN") {
-        return true;
-    }
-
-    else if ((!extension.length() || checkSig) && pIOHandler) {
-        const char *tokens[] = { "Caligary" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "Caligary" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/CSM/CSMLoader.cpp

@@ -90,19 +90,10 @@ CSMImporter::~CSMImporter()
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
 {
-    // check file extension
-    const std::string extension = GetExtension(pFile);
-
-    if( extension == "csm")
-        return true;
-
-    if ((checkSig || !extension.length()) && pIOHandler) {
-        const char* tokens[] = {"$Filename"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-    }
-    return false;
+    static const char* tokens[] = {"$Filename"};
+    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 7 - 28
code/AssetLib/Collada/ColladaLoader.cpp

@@ -117,36 +117,15 @@ ColladaLoader::~ColladaLoader() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    // check file extension
-    const std::string extension = GetExtension(pFile);
-    const bool readSig = checkSig && (pIOHandler != nullptr);
-    if (!readSig) {
-        if (extension == "dae" || extension == "zae") {
-            return true;
-        }
-    } else {
-        // Look for a DAE file inside, but don't extract it
-        ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
-        if (zip_archive.isOpen()) {
-            return !ColladaParser::ReadZaeManifest(zip_archive).empty();
-        }
-    }
-
-    // XML - too generic, we need to open the file and search for typical keywords
-    if (extension == "xml" || !extension.length() || checkSig) {
-        /*  If CanRead() is called in order to check whether we
-         *  support a specific file extension in general pIOHandler
-         *  might be nullptr and it's our duty to return true here.
-         */
-        if (!pIOHandler) {
-            return true;
-        }
-        static const char *tokens[] = { "<collada" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
+bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    // Look for a DAE file inside, but don't extract it
+    ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
+    if (zip_archive.isOpen()) {
+        return !ColladaParser::ReadZaeManifest(zip_archive).empty();
     }
 
-    return false;
+    static const char *tokens[] = { "<collada" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/DXF/DXFLoader.cpp

@@ -125,18 +125,9 @@ DXFImporter::~DXFImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool DXFImporter::CanRead( const std::string& filename, IOSystem* pIOHandler, bool checkSig ) const {
-    const std::string& extension = GetExtension( filename );
-    if ( extension == desc.mFileExtensions ) {
-        return true;
-    }
-
-    if ( extension.empty() || checkSig ) {
-        const char *pTokens[] = { "SECTION", "HEADER", "ENDSEC", "BLOCKS" };
-        return BaseImporter::SearchFileHeaderForToken(pIOHandler, filename, pTokens, 4, 32 );
-    }
-
-    return false;
+bool DXFImporter::CanRead( const std::string& filename, IOSystem* pIOHandler, bool /*checkSig*/ ) const {
+    static const char *tokens[] = { "SECTION", "HEADER", "ENDSEC", "BLOCKS" };
+    return SearchFileHeaderForToken(pIOHandler, filename, tokens, std::size(tokens), 32);
 }
 
 // ------------------------------------------------------------------------------------------------

+ 4 - 12
code/AssetLib/FBX/FBXImporter.cpp

@@ -100,18 +100,10 @@ FBXImporter::~FBXImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool FBXImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-	const std::string &extension = GetExtension(pFile);
-	if (extension == std::string(desc.mFileExtensions)) {
-		return true;
-	}
-
-	else if ((!extension.length() || checkSig) && pIOHandler) {
-		// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
-		const char *tokens[] = { "fbx" };
-		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-	}
-	return false;
+bool FBXImporter::CanRead(const std::string & pFile, IOSystem * pIOHandler, bool /*checkSig*/) const {
+	// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
+	static const char *tokens[] = { "fbx" };
+	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 7 - 14
code/AssetLib/HMP/HMPLoader.cpp

@@ -83,20 +83,13 @@ HMPImporter::~HMPImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool HMPImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "hmp")
-        return true;
-
-    // if check for extension is not enough, check for the magic tokens
-    if (!extension.length() || cs) {
-        uint32_t tokens[3];
-        tokens[0] = AI_HMP_MAGIC_NUMBER_LE_4;
-        tokens[1] = AI_HMP_MAGIC_NUMBER_LE_5;
-        tokens[2] = AI_HMP_MAGIC_NUMBER_LE_7;
-        return CheckMagicToken(pIOHandler, pFile, tokens, 3, 0);
-    }
-    return false;
+bool HMPImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = {
+        AI_HMP_MAGIC_NUMBER_LE_4,
+        AI_HMP_MAGIC_NUMBER_LE_5,
+        AI_HMP_MAGIC_NUMBER_LE_7
+    };
+    return CheckMagicToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 6 - 13
code/AssetLib/IFC/IFCLoader.cpp

@@ -129,19 +129,12 @@ IFCImporter::~IFCImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool IFCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string &extension = GetExtension(pFile);
-    if (extension == "ifc" || extension == "ifczip") {
-        return true;
-    } else if ((!extension.length() || checkSig) && pIOHandler) {
-        // note: this is the common identification for STEP-encoded files, so
-        // it is only unambiguous as long as we don't support any further
-        // file formats with STEP as their encoding.
-        const char *tokens[] = { "ISO-10303-21" };
-        const bool found(SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1));
-        return found;
-    }
-    return false;
+bool IFCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    // note: this is the common identification for STEP-encoded files, so
+    // it is only unambiguous as long as we don't support any further
+    // file formats with STEP as their encoding.
+    static const char *tokens[] = { "ISO-10303-21" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 17
code/AssetLib/Irr/IRRLoader.cpp

@@ -94,23 +94,9 @@ IRRImporter::~IRRImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool IRRImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-	const std::string extension = GetExtension(pFile);
-	if (extension == "irr") {
-		return true;
-	} else if (extension == "xml" || checkSig) {
-		/*  If CanRead() is called in order to check whether we
-         *  support a specific file extension in general pIOHandler
-         *  might be nullptr and it's our duty to return true here.
-         */
-		if (nullptr == pIOHandler) {
-			return true;
-		}
-		const char *tokens[] = { "irr_scene" };
-		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-	}
-
-	return false;
+bool IRRImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+	static const char *tokens[] = { "irr_scene" };
+	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 7 - 19
code/AssetLib/Irr/IRRMeshLoader.cpp

@@ -85,26 +85,14 @@ IRRMeshImporter::~IRRMeshImporter() {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
+bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
 	/* NOTE: A simple check for the file extension is not enough
-     * here. Irrmesh and irr are easy, but xml is too generic
-     * and could be collada, too. So we need to open the file and
-     * search for typical tokens.
-     */
-	const std::string extension = GetExtension(pFile);
-
-	if (extension == "irrmesh")
-		return true;
-	else if (extension == "xml" || checkSig) {
-		/*  If CanRead() is called to check whether the loader
-         *  supports a specific file extension in general we
-         *  must return true here.
-         */
-		if (!pIOHandler) return true;
-		const char *tokens[] = { "irrmesh" };
-		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-	}
-	return false;
+	 * here. Irrmesh and irr are easy, but xml is too generic
+	 * and could be collada, too. So we need to open the file and
+	 * search for typical tokens.
+	 */
+	static const char *tokens[] = { "irrmesh" };
+	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 7 - 15
code/AssetLib/LWO/LWOLoader.cpp

@@ -105,21 +105,13 @@ LWOImporter::~LWOImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool LWOImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(file);
-    if (extension == "lwo" || extension == "lxo") {
-        return true;
-    }
-
-    // if check for extension is not enough, check for the magic tokens
-    if (!extension.length() || checkSig) {
-        uint32_t tokens[3];
-        tokens[0] = AI_LWO_FOURCC_LWOB;
-        tokens[1] = AI_LWO_FOURCC_LWO2;
-        tokens[2] = AI_LWO_FOURCC_LXOB;
-        return CheckMagicToken(pIOHandler, file, tokens, 3, 8);
-    }
-    return false;
+bool LWOImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = {
+        AI_LWO_FOURCC_LWOB,
+        AI_LWO_FOURCC_LWO2,
+        AI_LWO_FOURCC_LXOB
+    };
+    return CheckMagicToken(pIOHandler, file, tokens, std::size(tokens), 8);
 }
 
 // ------------------------------------------------------------------------------------------------

+ 6 - 14
code/AssetLib/LWS/LWSLoader.cpp

@@ -147,20 +147,12 @@ LWSImporter::~LWSImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool LWSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "lws" || extension == "mot") {
-        return true;
-    }
-
-    // if check for extension is not enough, check for the magic tokens LWSC and LWMO
-    if (!extension.length() || checkSig) {
-        uint32_t tokens[2];
-        tokens[0] = AI_MAKE_MAGIC("LWSC");
-        tokens[1] = AI_MAKE_MAGIC("LWMO");
-        return CheckMagicToken(pIOHandler, pFile, tokens, 2);
-    }
-    return false;
+bool LWSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = {
+        AI_MAKE_MAGIC("LWSC"),
+        AI_MAKE_MAGIC("LWMO")
+    };
+    return CheckMagicToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 13 - 30
code/AssetLib/M3D/M3DImporter.cpp

@@ -114,38 +114,21 @@ M3DImporter::M3DImporter() :
 
 // ------------------------------------------------------------------------------------------------
 //  Returns true, if file is a binary or ASCII Model 3D file.
-bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "m3d"
-#ifdef M3D_ASCII
-            || extension == "a3d"
-#endif
-    )
-        return true;
-    else if (!extension.length() || checkSig) {
-        if (!pIOHandler) {
-            return true;
-        }
-        /*
-         * don't use CheckMagicToken because that checks with swapped bytes too, leading to false
-         * positives. This magic is not uint32_t, but char[4], so memcmp is the best way
-
-        const char* tokens[] = {"3DMO", "3dmo"};
-        return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
-        */
-        std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
-        unsigned char data[4];
-        if (4 != pStream->Read(data, 1, 4)) {
-            return false;
-        }
-        return !memcmp(data, "3DMO", 4) /* bin */
+bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    /*
+     * don't use CheckMagicToken because that checks with swapped bytes too, leading to false
+     * positives. This magic is not uint32_t, but char[4], so memcmp is the best way
+     */
+    std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
+    unsigned char data[4];
+    if (4 != pStream->Read(data, 1, 4)) {
+        return false;
+    }
+    return !memcmp(data, "3DMO", 4) /* bin */
 #ifdef M3D_ASCII
-               || !memcmp(data, "3dmo", 4) /* ASCII */
+        || !memcmp(data, "3dmo", 4) /* ASCII */
 #endif
-                ;
-    }
-    return false;
+            ;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/MD2/MD2Loader.cpp

@@ -106,19 +106,10 @@ MD2Importer::~MD2Importer()
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
 {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "md2")
-        return true;
-
-    // if check for extension is not enough, check for the magic tokens
-    if (!extension.length() || checkSig) {
-        uint32_t tokens[1];
-        tokens[0] = AI_MD2_MAGIC_NUMBER_LE;
-        return CheckMagicToken(pIOHandler,pFile,tokens,1);
-    }
-    return false;
+    static const uint32_t tokens[] = { AI_MD2_MAGIC_NUMBER_LE };
+    return CheckMagicToken(pIOHandler,pFile,tokens,std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/MD3/MD3Loader.cpp

@@ -349,18 +349,9 @@ MD3Importer::~MD3Importer() {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool MD3Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "md3")
-        return true;
-
-    // if check for extension is not enough, check for the magic tokens
-    if (!extension.length() || checkSig) {
-        uint32_t tokens[1];
-        tokens[0] = AI_MD3_MAGIC_NUMBER_LE;
-        return CheckMagicToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool MD3Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = { AI_MD3_MAGIC_NUMBER_LE };
+    return CheckMagicToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 14
code/AssetLib/MD5/MD5Loader.cpp

@@ -100,20 +100,9 @@ MD5Importer::~MD5Importer() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool MD5Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "md5anim" || extension == "md5mesh" || extension == "md5camera")
-        return true;
-    else if (!extension.length() || checkSig) {
-        if (!pIOHandler) {
-            return true;
-        }
-        const char *tokens[] = { "MD5Version" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-
-    return false;
+bool MD5Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "MD5Version" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 13
code/AssetLib/MDC/MDCLoader.cpp

@@ -110,19 +110,9 @@ MDCImporter::~MDCImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool MDCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "mdc") {
-        return true;
-    }
-
-    // if check for extension is not enough, check for the magic tokens
-    if (!extension.length() || checkSig) {
-        uint32_t tokens[1];
-        tokens[0] = AI_MDC_MAGIC_NUMBER_LE;
-        return CheckMagicToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool MDCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = { AI_MDC_MAGIC_NUMBER_LE };
+    return CheckMagicToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 12 - 17
code/AssetLib/MDL/MDLLoader.cpp

@@ -104,23 +104,18 @@ MDLImporter::~MDLImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool MDLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    // if check for extension is not enough, check for the magic tokens
-    if (extension == "mdl" || !extension.length() || checkSig) {
-        uint32_t tokens[8];
-        tokens[0] = AI_MDL_MAGIC_NUMBER_LE_HL2a;
-        tokens[1] = AI_MDL_MAGIC_NUMBER_LE_HL2b;
-        tokens[2] = AI_MDL_MAGIC_NUMBER_LE_GS7;
-        tokens[3] = AI_MDL_MAGIC_NUMBER_LE_GS5b;
-        tokens[4] = AI_MDL_MAGIC_NUMBER_LE_GS5a;
-        tokens[5] = AI_MDL_MAGIC_NUMBER_LE_GS4;
-        tokens[6] = AI_MDL_MAGIC_NUMBER_LE_GS3;
-        tokens[7] = AI_MDL_MAGIC_NUMBER_LE;
-        return CheckMagicToken(pIOHandler, pFile, tokens, 8, 0);
-    }
-    return false;
+bool MDLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = {
+        AI_MDL_MAGIC_NUMBER_LE_HL2a,
+        AI_MDL_MAGIC_NUMBER_LE_HL2b,
+        AI_MDL_MAGIC_NUMBER_LE_GS7,
+        AI_MDL_MAGIC_NUMBER_LE_GS5b,
+        AI_MDL_MAGIC_NUMBER_LE_GS5a,
+        AI_MDL_MAGIC_NUMBER_LE_GS4,
+        AI_MDL_MAGIC_NUMBER_LE_GS3,
+        AI_MDL_MAGIC_NUMBER_LE
+    };
+    return CheckMagicToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 8
code/AssetLib/MMD/MMDImporter.cpp

@@ -89,14 +89,9 @@ MMDImporter::~MMDImporter() {
 // ------------------------------------------------------------------------------------------------
 //  Returns true, if file is an pmx file.
 bool MMDImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler,
-        bool checkSig) const {
-    if (!checkSig) {
-        return SimpleExtensionCheck(pFile, "pmx");
-    } else {
-        // Check file Header
-        static const char *pTokens[] = { "PMX " };
-        return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 1);
-    }
+        bool /*checkSig*/) const {
+    static const char *tokens[] = { "PMX " };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 17
code/AssetLib/MS3D/MS3DLoader.cpp

@@ -88,26 +88,12 @@ MS3DImporter::MS3DImporter()
 // Destructor, private as well
 MS3DImporter::~MS3DImporter()
 {}
-
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool MS3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool MS3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
 {
-    // first call - simple extension check
-    const std::string extension = GetExtension(pFile);
-    if (extension == "ms3d") {
-        return true;
-    }
-
-    // second call - check for magic identifiers
-    else if (!extension.length() || checkSig)   {
-        if (!pIOHandler) {
-            return true;
-        }
-        const char* tokens[] = {"MS3D000000"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-    }
-    return false;
+    static const char* tokens[] = { "MS3D000000" };
+    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/NDO/NDOLoader.cpp

@@ -82,19 +82,10 @@ NDOImporter::~NDOImporter()
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool NDOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool NDOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
 {
-    // check file extension
-    const std::string extension = GetExtension(pFile);
-
-    if( extension == "ndo")
-        return true;
-
-    if ((checkSig || !extension.length()) && pIOHandler) {
-        const char* tokens[] = {"nendo"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1,5);
-    }
-    return false;
+    static const char* tokens[] = {"nendo"};
+    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,std::size(tokens),5);
 }
 
 // ------------------------------------------------------------------------------------------------

+ 1 - 1
code/AssetLib/NFF/NFFLoader.cpp

@@ -84,7 +84,7 @@ NFFImporter::~NFFImporter() {}
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 bool NFFImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
-    return SimpleExtensionCheck(pFile, "nff", "enff");
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/OFF/OFFLoader.cpp

@@ -85,19 +85,10 @@ OFFImporter::~OFFImporter()
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
 {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "off")
-        return true;
-    else if (!extension.length() || checkSig)
-    {
-        if (!pIOHandler)return true;
-        const char* tokens[] = {"off"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1,3);
-    }
-    return false;
+    static const char* tokens[] = { "off" };
+    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,std::size(tokens),3);
 }
 
 // ------------------------------------------------------------------------------------------------

+ 4 - 10
code/AssetLib/Obj/ObjFileImporter.cpp

@@ -87,16 +87,10 @@ ObjFileImporter::~ObjFileImporter() {
 }
 
 // ------------------------------------------------------------------------------------------------
-//  Returns true, if file is an obj file.
-bool ObjFileImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    if (!checkSig) {
-        //Check File Extension
-        return SimpleExtensionCheck(pFile, "obj");
-    } else {
-        // Check file Header
-        static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
-        return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9, 200, false, true);
-    }
+//  Returns true if file is an obj file.
+bool ObjFileImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
+    return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens), 200, false, true);
 }
 
 // ------------------------------------------------------------------------------------------------

+ 4 - 8
code/AssetLib/Ogre/OgreImporter.cpp

@@ -73,17 +73,13 @@ void OgreImporter::SetupProperties(const Importer *pImp) {
     m_detectTextureTypeFromFilename = pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false);
 }
 
-bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const {
-    if (!checkSig) {
-        return EndsWith(pFile, ".mesh.xml", false) || EndsWith(pFile, ".mesh", false);
-    }
-
+bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool /*checkSig*/) const {
     if (EndsWith(pFile, ".mesh.xml", false)) {
-        const char *tokens[] = { "<mesh>" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
+        static const char *tokens[] = { "<mesh>" };
+        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
     } else {
         /// @todo Read and validate first header chunk?
-        return EndsWith(pFile, ".mesh", false);
+        return false;
     }
 }
 

+ 3 - 10
code/AssetLib/OpenGEX/OpenGEXImporter.cpp

@@ -281,16 +281,9 @@ OpenGEXImporter::~OpenGEXImporter() {
 }
 
 //------------------------------------------------------------------------------------------------
-bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool checkSig) const {
-    bool canRead(false);
-    if (!checkSig) {
-        canRead = SimpleExtensionCheck(file, "ogex");
-    } else {
-        static const char *token[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
-        canRead = BaseImporter::SearchFileHeaderForToken(pIOHandler, file, token, 4);
-    }
-
-    return canRead;
+bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
+    return SearchFileHeaderForToken(pIOHandler, file, tokens, std::size(tokens));
 }
 
 //------------------------------------------------------------------------------------------------

+ 3 - 18
code/AssetLib/Ply/PlyLoader.cpp

@@ -100,24 +100,9 @@ PLYImporter::~PLYImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool PLYImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "ply") {
-        return true;
-    }
-
-    if (!extension.length() || checkSig) {
-        if (!pIOHandler) {
-            return true;
-        }
-        static const char *tokens[] = {
-            "ply"
-        };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-
-    return false;
+bool PLYImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "ply" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 2 - 6
code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp

@@ -160,12 +160,8 @@ Q3BSPFileImporter::~Q3BSPFileImporter() {
 }
 
 // ------------------------------------------------------------------------------------------------
-//  Returns true, if the loader can read this.
-bool Q3BSPFileImporter::CanRead(const std::string &rFile, IOSystem * /*pIOHandler*/, bool checkSig) const {
-    if (!checkSig) {
-        return SimpleExtensionCheck(rFile, "pk3", "bsp");
-    }
-
+//  Returns true if the loader can read this.
+bool Q3BSPFileImporter::CanRead(const std::string &/*rFile*/, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
     return false;
 }
 

+ 3 - 12
code/AssetLib/Q3D/Q3DLoader.cpp

@@ -83,18 +83,9 @@ Q3DImporter::~Q3DImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool Q3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "q3s" || extension == "q3o")
-        return true;
-    else if (!extension.length() || checkSig) {
-        if (!pIOHandler)
-            return true;
-        const char *tokens[] = { "quick3Do", "quick3Ds" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 2);
-    }
-    return false;
+bool Q3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "quick3Do", "quick3Ds" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 2 - 2
code/AssetLib/Raw/RawLoader.cpp

@@ -84,8 +84,8 @@ RAWImporter::~RAWImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool RAWImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
-    return SimpleExtensionCheck(pFile, "raw");
+bool RAWImporter::CanRead(const std::string & /*pFile*/, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 2 - 2
code/AssetLib/SIB/SIBImporter.cpp

@@ -217,8 +217,8 @@ SIBImporter::~SIBImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool SIBImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
-    return SimpleExtensionCheck(pFile, "sib");
+bool SIBImporter::CanRead(const std::string & /*pFile*/, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 2 - 2
code/AssetLib/SMD/SMDLoader.cpp

@@ -101,9 +101,9 @@ SMDImporter::~SMDImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool SMDImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool) const {
+bool SMDImporter::CanRead( const std::string& /*pFile*/, IOSystem* /*pIOHandler*/, bool) const {
     // fixme: auto format detection
-    return SimpleExtensionCheck(pFile,"smd","vta");
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 14
code/AssetLib/STL/STLLoader.cpp

@@ -141,20 +141,9 @@ STLImporter::~STLImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool STLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "stl") {
-        return true;
-    } else if (!extension.length() || checkSig) {
-        if (!pIOHandler) {
-            return true;
-        }
-        const char *tokens[] = { "STL", "solid" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 2);
-    }
-
-    return false;
+bool STLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "STL", "solid" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 21
code/AssetLib/Terragen/TerragenLoader.cpp

@@ -77,27 +77,9 @@ TerragenImporter::~TerragenImporter() {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool TerragenImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    // check file extension
-    std::string extension = GetExtension(pFile);
-
-    if (extension == "ter")
-        return true;
-
-    if (!extension.length() || checkSig) {
-        /*  If CanRead() is called in order to check whether we
-         *  support a specific file extension in general pIOHandler
-         *  might be nullptr and it's our duty to return true here.
-         */
-        if (!pIOHandler) {
-            return true;
-        }
-
-        const char *tokens[] = { "terragen" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-
-    return false;
+bool TerragenImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "terragen" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 2 - 2
code/AssetLib/Unreal/UnrealLoader.cpp

@@ -176,8 +176,8 @@ UnrealImporter::~UnrealImporter() {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool UnrealImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
-    return SimpleExtensionCheck(pFile, "3d", "uc");
+bool UnrealImporter::CanRead(const std::string & /*pFile*/, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 3 - 11
code/AssetLib/X/XFileImporter.cpp

@@ -89,17 +89,9 @@ XFileImporter::~XFileImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
-    std::string extension = GetExtension(pFile);
-    if(extension == "x") {
-        return true;
-    }
-    if (!extension.length() || checkSig) {
-        uint32_t token[1];
-        token[0] = AI_MAKE_MAGIC("xof ");
-        return CheckMagicToken(pIOHandler,pFile,token,1,0);
-    }
-    return false;
+bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t token[] = { AI_MAKE_MAGIC("xof ") };
+    return CheckMagicToken(pIOHandler,pFile,token,std::size(token));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 1 - 8
code/AssetLib/X3D/X3DImporter.cpp

@@ -156,14 +156,7 @@ void X3DImporter::ParseFile(const std::string &file, IOSystem *pIOHandler) {
 	}
 }
 
-bool X3DImporter::CanRead( const std::string &pFile, IOSystem * /*pIOHandler*/, bool checkSig ) const {
-    if (checkSig) {
-        std::string::size_type pos = pFile.find_last_of(".x3d");
-        if (pos != std::string::npos) {
-            return true;
-        }
-    }
-
+bool X3DImporter::CanRead( const std::string & /*pFile*/, IOSystem * /*pIOHandler*/, bool /*checkSig*/ ) const {
     return false;
 }
 

+ 3 - 17
code/AssetLib/XGL/XGLLoader.cpp

@@ -105,23 +105,9 @@ XGLImporter::~XGLImporter() {
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool XGLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-	/* NOTE: A simple check for the file extension is not enough
-     * here. XGL and ZGL are ok, but xml is too generic
-     * and might be collada as well. So open the file and
-     * look for typical signal tokens.
-     */
-	const std::string extension = GetExtension(pFile);
-
-	if (extension == "xgl" || extension == "zgl") {
-		return true;
-	} else if (extension == "xml" || checkSig) {
-		ai_assert(pIOHandler != NULL);
-
-		const char *tokens[] = { "<world>", "<World>", "<WORLD>" };
-		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 3);
-	}
-	return false;
+bool XGLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+	static const char *tokens[] = { "<world>", "<World>", "<WORLD>" };
+	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, std::size(tokens));
 }
 
 // ------------------------------------------------------------------------------------------------

+ 6 - 16
code/AssetLib/glTF/glTFImporter.cpp

@@ -93,24 +93,14 @@ const aiImporterDesc *glTFImporter::GetInfo() const {
 }
 
 bool glTFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
-    const std::string &extension = GetExtension(pFile);
-
-    if (extension != "gltf" && extension != "glb") {
+    glTF::Asset asset(pIOHandler);
+    try {
+        asset.Load(pFile, GetExtension(pFile) == "glb");
+        std::string version = asset.asset.version;
+        return !version.empty() && version[0] == '1';
+    } catch (...) {
         return false;
     }
-
-    if (pIOHandler) {
-        glTF::Asset asset(pIOHandler);
-        try {
-            asset.Load(pFile, extension == "glb");
-            std::string version = asset.asset.version;
-            return !version.empty() && version[0] == '1';
-        } catch (...) {
-            return false;
-        }
-    }
-
-    return false;
 }
 
 inline void SetMaterialColorProperty(std::vector<int> &embeddedTexIdxs, Asset & /*r*/, glTF::TexProperty prop, aiMaterial *mat,

+ 4 - 10
code/AssetLib/glTF2/glTF2Importer.cpp

@@ -110,20 +110,14 @@ const aiImporterDesc *glTF2Importer::GetInfo() const {
 }
 
 bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
-    const std::string &extension = GetExtension(pFile);
-
-    if (extension != "gltf" && extension != "glb") {
-        return false;
-    }
-
-    if (pIOHandler) {
+    try {
         glTF2::Asset asset(pIOHandler);
-        asset.Load(pFile, extension == "glb");
+        asset.Load(pFile, GetExtension(pFile) == "glb");
         std::string version = asset.asset.version;
         return !version.empty() && version[0] == '2';
+    } catch(...) {
+        return false;
     }
-
-    return false;
 }
 
 static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) {

+ 2 - 28
code/Common/BaseImporter.cpp

@@ -170,7 +170,7 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
 /*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem *pIOHandler,
         const std::string &pFile,
         const char **tokens,
-        unsigned int numTokens,
+        std::size_t numTokens,
         unsigned int searchBytes /* = 200 */,
         bool tokensSol /* false */,
         bool noAlphaBeforeTokens /* false */) {
@@ -238,32 +238,6 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
     return false;
 }
 
-// ------------------------------------------------------------------------------------------------
-// Simple check for file extension
-/*static*/ bool BaseImporter::SimpleExtensionCheck(const std::string &pFile,
-        const char *ext0,
-        const char *ext1,
-        const char *ext2) {
-    std::string::size_type pos = pFile.find_last_of('.');
-
-    // no file extension - can't read
-    if (pos == std::string::npos)
-        return false;
-
-    const char *ext_real = &pFile[pos + 1];
-    if (!ASSIMP_stricmp(ext_real, ext0))
-        return true;
-
-    // check for other, optional, file extensions
-    if (ext1 && !ASSIMP_stricmp(ext_real, ext1))
-        return true;
-
-    if (ext2 && !ASSIMP_stricmp(ext_real, ext2))
-        return true;
-
-    return false;
-}
-
 // ------------------------------------------------------------------------------------------------
 // Get file extension from path
 std::string BaseImporter::GetExtension(const std::string &file) {
@@ -284,7 +258,7 @@ std::string BaseImporter::GetExtension(const std::string &file) {
 // ------------------------------------------------------------------------------------------------
 // Check for magic bytes at the beginning of the file.
 /* static */ bool BaseImporter::CheckMagicToken(IOSystem *pIOHandler, const std::string &pFile,
-        const void *_magic, unsigned int num, unsigned int offset, unsigned int size) {
+        const void *_magic, std::size_t num, unsigned int offset, unsigned int size) {
     ai_assert(size <= 16);
     ai_assert(_magic);
 

+ 52 - 7
code/Common/Importer.cpp

@@ -617,16 +617,61 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
             profiler->BeginRegion("total");
         }
 
-        // Find an worker class which can handle the file
-        BaseImporter* imp = nullptr;
+        // Find an worker class which can handle the file extension.
+        // Multiple importers may be able to handle the same extension (.xml!); gather them all.
         SetPropertyInteger("importerIndex", -1);
-        for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
+        struct ImporterAndIndex {
+            BaseImporter * importer;
+            unsigned int   index;
+        };
+        std::vector<ImporterAndIndex> possibleImporters;
+        for (unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
+
+            // Every importer has a list of supported extensions.
+            std::set<std::string> extensions;
+            pimpl->mImporter[a]->GetExtensionList(extensions);
+
+            // CAUTION: Do not just search for the extension!
+            // GetExtension() returns the part after the *last* dot, but some extensions have dots
+            // inside them, e.g. ogre.mesh.xml. Compare the entire end of the string.
+            for (std::set<std::string>::const_iterator it = extensions.cbegin(); it != extensions.cend(); ++it) {
+
+                // Yay for C++<20 not having std::string::ends_with()
+                std::string extension = "." + *it;
+                if (extension.length() <= pFile.length()) {
+                    // Possible optimization: Fetch the lowercase filename!
+                    if (0 == ASSIMP_stricmp(pFile.c_str() + pFile.length() - extension.length(), extension.c_str())) {
+                        ImporterAndIndex candidate = { pimpl->mImporter[a], a };
+                        possibleImporters.push_back(candidate);
+                        break;
+                    }
+                }
 
-            if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) {
-                imp = pimpl->mImporter[a];
-                SetPropertyInteger("importerIndex", a);
-                break;
             }
+
+        }
+
+        // If just one importer supports this extension, pick it and close the case.
+        BaseImporter* imp = nullptr;
+        if (1 == possibleImporters.size()) {
+            imp = possibleImporters[0].importer;
+            SetPropertyInteger("importerIndex", possibleImporters[0].index);
+        }
+        // If multiple importers claim this file extension, ask them to look at the actual file data to decide.
+        // This can happen e.g. with XML (COLLADA vs. Irrlicht).
+        else {
+            for (std::vector<ImporterAndIndex>::const_iterator it = possibleImporters.begin(); it < possibleImporters.end(); ++it) {
+                BaseImporter & importer = *it->importer;
+
+                ASSIMP_LOG_INFO("Found a possible importer: " + std::string(importer.GetInfo()->mName) + "; trying signature-based detection");
+                if (importer.CanRead( pFile, pimpl->mIOHandler, true)) {
+                    imp = &importer;
+                    SetPropertyInteger("importerIndex", it->index);
+                    break;
+                }
+
+            }
+
         }
 
         if (!imp)   {

+ 8 - 27
include/assimp/BaseImporter.h

@@ -97,20 +97,15 @@ public:
     // -------------------------------------------------------------------
     /** Returns whether the class can handle the format of the given file.
      *
-     * The implementation should be as quick as possible. A check for
-     * the file extension is enough. If no suitable loader is found with
-     * this strategy, CanRead() is called again, the 'checkSig' parameter
-     * set to true this time. Now the implementation is expected to
-     * perform a full check of the file structure, possibly searching the
-     * first bytes of the file for magic identifiers or keywords.
+     * The implementation is expected to perform a full check of the file
+     * structure, possibly searching the first bytes of the file for magic
+     * identifiers or keywords.
      *
      * @param pFile Path and file name of the file to be examined.
      * @param pIOHandler The IO handler to use for accessing any file.
-     * @param checkSig Set to true if this method is called a second time.
-     *   This time, the implementation may take more time to examine the
-     *   contents of the file to be loaded for magic bytes, keywords, etc
-     *   to be able to load files with unknown/not existent file extensions.
-     * @return true if the class can read this file, false if not.
+     * @param checkSig Legacy; do not use.
+     * @return true if the class can read this file, false if not or if
+     * unsure.
      */
     virtual bool CanRead(
             const std::string &pFile,
@@ -295,25 +290,11 @@ public: // static utilities
             IOSystem *pIOSystem,
             const std::string &file,
             const char **tokens,
-            unsigned int numTokens,
+            std::size_t numTokens,
             unsigned int searchBytes = 200,
             bool tokensSol = false,
             bool noAlphaBeforeTokens = false);
 
-    // -------------------------------------------------------------------
-    /** @brief Check whether a file has a specific file extension
-     *  @param pFile Input file
-     *  @param ext0 Extension to check for. Lowercase characters only, no dot!
-     *  @param ext1 Optional second extension
-     *  @param ext2 Optional third extension
-     *  @note Case-insensitive
-     */
-    static bool SimpleExtensionCheck(
-            const std::string &pFile,
-            const char *ext0,
-            const char *ext1 = nullptr,
-            const char *ext2 = nullptr);
-
     // -------------------------------------------------------------------
     /** @brief Extract file extension from a string
      *  @param pFile Input file
@@ -340,7 +321,7 @@ public: // static utilities
             IOSystem *pIOHandler,
             const std::string &pFile,
             const void *magic,
-            unsigned int num,
+            std::size_t num,
             unsigned int offset = 0,
             unsigned int size = 4);