diff --git a/code/AssetLib/3DS/3DSLoader.cpp b/code/AssetLib/3DS/3DSLoader.cpp index e1a6d0f89..4c24394fb 100644 --- a/code/AssetLib/3DS/3DSLoader.cpp +++ b/code/AssetLib/3DS/3DSLoader.cpp @@ -147,7 +147,7 @@ void Discreet3DSImporter::InternReadFile(const std::string &pFile, // We should have at least one chunk if (theStream.GetRemainingSize() < 16) { - throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile); + throw DeadlyImportError("3DS file is either empty or corrupt: ", pFile); } this->stream = &theStream; @@ -178,7 +178,7 @@ void Discreet3DSImporter::InternReadFile(const std::string &pFile, // file. for (auto &mesh : mScene->mMeshes) { if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) { - throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile); + throw DeadlyImportError("3DS file contains faces but no vertices: ", pFile); } CheckIndices(mesh); MakeUnique(mesh); diff --git a/code/AssetLib/3MF/D3MFOpcPackage.cpp b/code/AssetLib/3MF/D3MFOpcPackage.cpp index e8e1e2f5e..7094ea3ae 100644 --- a/code/AssetLib/3MF/D3MFOpcPackage.cpp +++ b/code/AssetLib/3MF/D3MFOpcPackage.cpp @@ -118,7 +118,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) : mRootStream(nullptr), mZipArchive() { mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile)); if (!mZipArchive->isOpen()) { - throw DeadlyImportError("Failed to open file " + rFile + "."); + throw DeadlyImportError("Failed to open file ", rFile, "."); } std::vector fileList; @@ -192,7 +192,7 @@ std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) { }); if (itr == reader.m_relationShips.end()) { - throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE); + throw DeadlyImportError("Cannot find ", XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE); } return (*itr)->target; diff --git a/code/AssetLib/AC/ACLoader.cpp b/code/AssetLib/AC/ACLoader.cpp index 4291ce8d1..bf2828655 100644 --- a/code/AssetLib/AC/ACLoader.cpp +++ b/code/AssetLib/AC/ACLoader.cpp @@ -762,7 +762,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile, // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open AC3D file " + pFile + "."); + throw DeadlyImportError("Failed to open AC3D file ", pFile, "."); } // allocate storage and copy the contents of the file to a memory buffer diff --git a/code/AssetLib/AMF/AMFImporter.cpp b/code/AssetLib/AMF/AMFImporter.cpp index 0b76b2652..556dbb30b 100644 --- a/code/AssetLib/AMF/AMFImporter.cpp +++ b/code/AssetLib/AMF/AMFImporter.cpp @@ -143,23 +143,23 @@ bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Mater /*********************************************************************************************************************************************/ void AMFImporter::Throw_CloseNotFound(const std::string &pNode) { - throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt."); + throw DeadlyImportError("Close tag for node <", pNode, "> not found. Seems file is corrupt."); } void AMFImporter::Throw_IncorrectAttr(const std::string &pAttrName) { - throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\"."); + throw DeadlyImportError("Node <", mReader->getNodeName(), "> has incorrect attribute \"", pAttrName, "\"."); } void AMFImporter::Throw_IncorrectAttrValue(const std::string &pAttrName) { - throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value."); + throw DeadlyImportError("Attribute \"", pAttrName, "\" in node <", mReader->getNodeName(), "> has incorrect value."); } void AMFImporter::Throw_MoreThanOnceDefined(const std::string &pNodeType, const std::string &pDescription) { - throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription); + throw DeadlyImportError("\"", pNodeType, "\" node can be used only once in ", mReader->getNodeName(), ". Description: ", pDescription); } void AMFImporter::Throw_ID_NotFound(const std::string &pID) const { - throw DeadlyImportError("Not found node with name \"" + pID + "\"."); + throw DeadlyImportError("Not found node with name \"", pID, "\"."); } /*********************************************************************************************************************************************/ @@ -167,7 +167,7 @@ void AMFImporter::Throw_ID_NotFound(const std::string &pID) const { /*********************************************************************************************************************************************/ void AMFImporter::XML_CheckNode_MustHaveChildren() { - if (mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must have children."); + if (mReader->isEmptyElement()) throw DeadlyImportError("Node <", mReader->getNodeName(), "> must have children."); } void AMFImporter::XML_CheckNode_SkipUnsupported(const std::string &pParentNodeName) { @@ -202,7 +202,7 @@ void AMFImporter::XML_CheckNode_SkipUnsupported(const std::string &pParentNodeNa casu_cres: - if (!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + "."); + if (!found) throw DeadlyImportError("Unknown node \"", nn, "\" in ", pParentNodeName, "."); if (!close_found) Throw_CloseNotFound(nn); if (!skipped_before[sk_idx]) { @@ -227,7 +227,7 @@ bool AMFImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) { else if ((val == "true") || (val == "1")) return true; else - throw DeadlyImportError("Bool attribute value can contain \"false\"/\"0\" or \"true\"/\"1\" not the \"" + val + "\""); + throw DeadlyImportError("Bool attribute value can contain \"false\"/\"0\" or \"true\"/\"1\" not the \"", val, "\""); } float AMFImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx) { @@ -367,13 +367,13 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) { // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open AMF file " + pFile + "."); + throw DeadlyImportError("Failed to open AMF file ", pFile, "."); } // generate a XML reader for it std::unique_ptr mIOWrapper(new CIrrXML_IOStreamReader(file.get())); mReader = irr::io::createIrrXMLReader(mIOWrapper.get()); - if (!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + "."); + if (!mReader) throw DeadlyImportError("Failed to create XML reader for file", pFile, "."); // // start reading // search for root tag diff --git a/code/AssetLib/ASE/ASELoader.cpp b/code/AssetLib/ASE/ASELoader.cpp index a27767229..057272c91 100644 --- a/code/AssetLib/ASE/ASELoader.cpp +++ b/code/AssetLib/ASE/ASELoader.cpp @@ -137,7 +137,7 @@ void ASEImporter::InternReadFile(const std::string &pFile, // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open ASE file " + pFile + "."); + throw DeadlyImportError("Failed to open ASE file ", pFile, "."); } // Allocate storage and copy the contents of the file to a memory buffer diff --git a/code/AssetLib/B3D/B3DImporter.cpp b/code/AssetLib/B3D/B3DImporter.cpp index ff595aaf1..25e484e02 100644 --- a/code/AssetLib/B3D/B3DImporter.cpp +++ b/code/AssetLib/B3D/B3DImporter.cpp @@ -119,7 +119,7 @@ void B3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open B3D file " + pFile + "."); + throw DeadlyImportError("Failed to open B3D file ", pFile, "."); } // check whether the .b3d file is large enough to contain @@ -147,7 +147,7 @@ AI_WONT_RETURN void B3DImporter::Fail(string str) { #ifdef DEBUG_B3D ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str); #endif - throw DeadlyImportError("B3D Importer - error in B3D file data: " + str); + throw DeadlyImportError("B3D Importer - error in B3D file data: ", str); } // ------------------------------------------------------------------------------------------------ diff --git a/code/AssetLib/BVH/BVHLoader.cpp b/code/AssetLib/BVH/BVHLoader.cpp index 46afc5e64..3bea70c95 100644 --- a/code/AssetLib/BVH/BVHLoader.cpp +++ b/code/AssetLib/BVH/BVHLoader.cpp @@ -71,6 +71,13 @@ static const aiImporterDesc desc = { "bvh" }; +// ------------------------------------------------------------------------------------------------ +// Aborts the file reading with an exception +template +AI_WONT_RETURN void BVHLoader::ThrowException(T&&... args) { + throw DeadlyImportError(mFileName, ":", mLine, " - ", args...); +} + // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer BVHLoader::BVHLoader() : @@ -118,7 +125,7 @@ void BVHLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSyst // read file into memory std::unique_ptr file(pIOHandler->Open(pFile)); if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open file " + pFile + "."); + throw DeadlyImportError("Failed to open file ", pFile, "."); } size_t fileSize = file->FileSize(); @@ -176,12 +183,12 @@ aiNode *BVHLoader::ReadNode() { // first token is name std::string nodeName = GetNextToken(); if (nodeName.empty() || nodeName == "{") - ThrowException(format() << "Expected node name, but found \"" << nodeName << "\"."); + ThrowException("Expected node name, but found \"", nodeName, "\"."); // then an opening brace should follow std::string openBrace = GetNextToken(); if (openBrace != "{") - ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); + ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\"."); // Create a node aiNode *node = new aiNode(nodeName); @@ -211,7 +218,7 @@ aiNode *BVHLoader::ReadNode() { siteToken.clear(); siteToken = GetNextToken(); if (siteToken != "Site") - ThrowException(format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"."); + ThrowException("Expected \"End Site\" keyword, but found \"", token, " ", siteToken, "\"."); aiNode *child = ReadEndSite(nodeName); child->mParent = node; @@ -221,7 +228,7 @@ aiNode *BVHLoader::ReadNode() { break; } else { // everything else is a parse error - ThrowException(format() << "Unknown keyword \"" << token << "\"."); + ThrowException("Unknown keyword \"", token, "\"."); } } @@ -242,7 +249,7 @@ aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) { // check opening brace std::string openBrace = GetNextToken(); if (openBrace != "{") - ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); + ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\"."); // Create a node aiNode *node = new aiNode("EndSite_" + pParentName); @@ -261,7 +268,7 @@ aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) { break; } else { // everything else is a parse error - ThrowException(format() << "Unknown keyword \"" << token << "\"."); + ThrowException("Unknown keyword \"", token, "\"."); } } @@ -307,7 +314,7 @@ void BVHLoader::ReadNodeChannels(BVHLoader::Node &pNode) { else if (channelToken == "Zrotation") pNode.mChannels.push_back(Channel_RotationZ); else - ThrowException(format() << "Invalid channel specifier \"" << channelToken << "\"."); + ThrowException("Invalid channel specifier \"", channelToken, "\"."); } } @@ -317,7 +324,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) { // Read number of frames std::string tokenFrames = GetNextToken(); if (tokenFrames != "Frames:") - ThrowException(format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\"."); + ThrowException("Expected frame count \"Frames:\", but found \"", tokenFrames, "\"."); float numFramesFloat = GetNextTokenAsFloat(); mAnimNumFrames = (unsigned int)numFramesFloat; @@ -326,7 +333,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) { std::string tokenDuration1 = GetNextToken(); std::string tokenDuration2 = GetNextToken(); if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:") - ThrowException(format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\"."); + ThrowException("Expected frame duration \"Frame Time:\", but found \"", tokenDuration1, " ", tokenDuration2, "\"."); mAnimTickDuration = GetNextTokenAsFloat(); @@ -393,17 +400,11 @@ float BVHLoader::GetNextTokenAsFloat() { ctoken = fast_atoreal_move(ctoken, result); if (ctoken != token.c_str() + token.length()) - ThrowException(format() << "Expected a floating point number, but found \"" << token << "\"."); + ThrowException("Expected a floating point number, but found \"", token, "\"."); return result; } -// ------------------------------------------------------------------------------------------------ -// Aborts the file reading with an exception -AI_WONT_RETURN void BVHLoader::ThrowException(const std::string &pError) { - throw DeadlyImportError(format() << mFileName << ":" << mLine << " - " << pError); -} - // ------------------------------------------------------------------------------------------------ // Constructs an animation for the motion data and stores it in the given scene void BVHLoader::CreateAnimation(aiScene *pScene) { @@ -453,7 +454,7 @@ void BVHLoader::CreateAnimation(aiScene *pScene) { std::map::iterator mapIter = channelMap.find(channel); if (mapIter == channelMap.end()) - throw DeadlyImportError("Missing position channel in node " + nodeName); + throw DeadlyImportError("Missing position channel in node ", nodeName); else { int channelIdx = mapIter->second; switch (channel) { diff --git a/code/AssetLib/BVH/BVHLoader.h b/code/AssetLib/BVH/BVHLoader.h index c2ecbd102..3af3cbb31 100644 --- a/code/AssetLib/BVH/BVHLoader.h +++ b/code/AssetLib/BVH/BVHLoader.h @@ -134,7 +134,8 @@ protected: float GetNextTokenAsFloat(); /** Aborts the file reading with an exception */ - AI_WONT_RETURN void ThrowException(const std::string &pError) AI_WONT_RETURN_SUFFIX; + template + AI_WONT_RETURN void ThrowException(T&&... args) AI_WONT_RETURN_SUFFIX; /** Constructs an animation for the motion data and stores it in the given scene */ void CreateAnimation(aiScene *pScene); diff --git a/code/AssetLib/Blender/BlenderCustomData.cpp b/code/AssetLib/Blender/BlenderCustomData.cpp index c752da4e0..c74a6bb75 100644 --- a/code/AssetLib/Blender/BlenderCustomData.cpp +++ b/code/AssetLib/Blender/BlenderCustomData.cpp @@ -149,7 +149,7 @@ bool isValidCustomDataType(const int cdtype) { bool readCustomData(std::shared_ptr &out, const int cdtype, const size_t cnt, const FileDatabase &db) { if (!isValidCustomDataType(cdtype)) { - throw Error((Formatter::format(), "CustomData.type ", cdtype, " out of index")); + throw Error("CustomData.type ", cdtype, " out of index"); } const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype]; diff --git a/code/AssetLib/Blender/BlenderDNA.cpp b/code/AssetLib/Blender/BlenderDNA.cpp index 920362f24..ad0760914 100644 --- a/code/AssetLib/Blender/BlenderDNA.cpp +++ b/code/AssetLib/Blender/BlenderDNA.cpp @@ -130,9 +130,7 @@ void DNAParser::Parse() { uint16_t n = stream.GetI2(); if (n >= types.size()) { - throw DeadlyImportError((format(), - "BlenderDNA: Invalid type index in structure name", n, - " (there are only ", types.size(), " entries)")); + throw DeadlyImportError("BlenderDNA: Invalid type index in structure name", n, " (there are only ", types.size(), " entries)"); } // maintain separate indexes @@ -151,9 +149,7 @@ void DNAParser::Parse() { uint16_t j = stream.GetI2(); if (j >= types.size()) { - throw DeadlyImportError((format(), - "BlenderDNA: Invalid type index in structure field ", j, - " (there are only ", types.size(), " entries)")); + throw DeadlyImportError("BlenderDNA: Invalid type index in structure field ", j, " (there are only ", types.size(), " entries)"); } s.fields.push_back(Field()); Field &f = s.fields.back(); @@ -164,9 +160,7 @@ void DNAParser::Parse() { j = stream.GetI2(); if (j >= names.size()) { - throw DeadlyImportError((format(), - "BlenderDNA: Invalid name index in structure field ", j, - " (there are only ", names.size(), " entries)")); + throw DeadlyImportError("BlenderDNA: Invalid name index in structure field ", j, " (there are only ", names.size(), " entries)"); } f.name = names[j]; @@ -188,9 +182,7 @@ void DNAParser::Parse() { if (*f.name.rbegin() == ']') { const std::string::size_type rb = f.name.find('['); if (rb == std::string::npos) { - throw DeadlyImportError((format(), - "BlenderDNA: Encountered invalid array declaration ", - f.name)); + throw DeadlyImportError("BlenderDNA: Encountered invalid array declaration ", f.name); } f.flags |= FieldFlag_Array; diff --git a/code/AssetLib/Blender/BlenderDNA.h b/code/AssetLib/Blender/BlenderDNA.h index c89b21434..a084dbdbd 100644 --- a/code/AssetLib/Blender/BlenderDNA.h +++ b/code/AssetLib/Blender/BlenderDNA.h @@ -83,9 +83,10 @@ class ObjectCache; * ancestry. */ // ------------------------------------------------------------------------------- struct Error : DeadlyImportError { - Error(const std::string &s) : - DeadlyImportError(s) { - // empty + template + explicit Error(T&&... args) + : DeadlyImportError(args...) + { } }; diff --git a/code/AssetLib/Blender/BlenderDNA.inl b/code/AssetLib/Blender/BlenderDNA.inl index 7bb9d586a..c4e84b5e0 100644 --- a/code/AssetLib/Blender/BlenderDNA.inl +++ b/code/AssetLib/Blender/BlenderDNA.inl @@ -57,9 +57,7 @@ const Field& Structure :: operator [] (const std::string& ss) const { std::map::const_iterator it = indices.find(ss); if (it == indices.end()) { - throw Error((Formatter::format(), - "BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`" - )); + throw Error("BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`"); } return fields[(*it).second]; @@ -76,9 +74,7 @@ const Field* Structure :: Get (const std::string& ss) const const Field& Structure :: operator [] (const size_t i) const { if (i >= fields.size()) { - throw Error((Formatter::format(), - "BlendDNA: There is no field with index `",i,"` in structure `",name,"`" - )); + throw Error("BlendDNA: There is no field with index `",i,"` in structure `",name,"`"); } return fields[i]; @@ -109,9 +105,7 @@ void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatab // is the input actually an array? if (!(f.flags & FieldFlag_Array)) { - throw Error((Formatter::format(),"Field `",name,"` of structure `", - this->name,"` ought to be an array of size ",M - )); + throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M); } db.reader->IncPtr(f.offset); @@ -148,9 +142,9 @@ void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileD // is the input actually an array? if (!(f.flags & FieldFlag_Array)) { - throw Error((Formatter::format(),"Field `",name,"` of structure `", + throw Error("Field `",name,"` of structure `", this->name,"` ought to be an array of size ",M,"*",N - )); + ); } db.reader->IncPtr(f.offset); @@ -195,8 +189,8 @@ bool Structure :: ReadFieldPtr(TOUT& out, const char* name, const FileDatabas // sanity check, should never happen if the genblenddna script is right if (!(f->flags & FieldFlag_Pointer)) { - throw Error((Formatter::format(),"Field `",name,"` of structure `", - this->name,"` ought to be a pointer")); + throw Error("Field `",name,"` of structure `", + this->name,"` ought to be a pointer"); } db.reader->IncPtr(f->offset); @@ -241,8 +235,8 @@ bool Structure :: ReadFieldPtr(TOUT (&out)[N], const char* name, #ifdef _DEBUG // sanity check, should never happen if the genblenddna script is right if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) { - throw Error((Formatter::format(),"Field `",name,"` of structure `", - this->name,"` ought to be a pointer AND an array")); + throw Error("Field `",name,"` of structure `", + this->name,"` ought to be a pointer AND an array"); } #endif // _DEBUG @@ -322,8 +316,8 @@ bool Structure::ReadCustomDataPtr(std::shared_ptr&out, int cdtype, con // sanity check, should never happen if the genblenddna script is right if (!(f->flags & FieldFlag_Pointer)) { - throw Error((Formatter::format(), "Field `", name, "` of structure `", - this->name, "` ought to be a pointer")); + throw Error("Field `", name, "` of structure `", + this->name, "` ought to be a pointer"); } db.reader->IncPtr(f->offset); @@ -369,8 +363,8 @@ bool Structure::ReadFieldPtrVector(vector>&out, const char* name, const // sanity check, should never happen if the genblenddna script is right if (!(f->flags & FieldFlag_Pointer)) { - throw Error((Formatter::format(), "Field `", name, "` of structure `", - this->name, "` ought to be a pointer")); + throw Error("Field `", name, "` of structure `", + this->name, "` ought to be a pointer"); } db.reader->IncPtr(f->offset); @@ -428,9 +422,9 @@ bool Structure :: ResolvePointer(TOUT& out, const Pointer & ptrval, const Fil // and check if it matches the type which we expect. const Structure& ss = db.dna[block->dna_index]; if (ss != s) { - throw Error((Formatter::format(),"Expected target to be of type `",s.name, + throw Error("Expected target to be of type `",s.name, "` but seemingly it is a `",ss.name,"` instead" - )); + ); } // try to retrieve the object from the cache @@ -614,16 +608,14 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv if (it == db.entries.end()) { // this is crucial, pointers may not be invalid. // this is either a corrupted file or an attempted attack. - throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x", - std::hex,ptrval.val,", no file block falls into this address range" - )); + throw DeadlyImportError("Failure resolving pointer 0x", + std::hex,ptrval.val,", no file block falls into this address range"); } if (ptrval.val >= (*it).address.val + (*it).size) { - throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x", + throw DeadlyImportError("Failure resolving pointer 0x", std::hex,ptrval.val,", nearest file block starting at 0x", (*it).address.val," ends at 0x", - (*it).address.val + (*it).size - )); + (*it).address.val + (*it).size); } return &*it; } @@ -676,7 +668,7 @@ template inline void ConvertDispatcher(T& out, const Structure& in, out = static_cast(db.reader->GetF8()); } else { - throw DeadlyImportError("Unknown source for conversion to primitive data type: "+in.name); + throw DeadlyImportError("Unknown source for conversion to primitive data type: ", in.name); } } @@ -784,9 +776,7 @@ const Structure& DNA :: operator [] (const std::string& ss) const { std::map::const_iterator it = indices.find(ss); if (it == indices.end()) { - throw Error((Formatter::format(), - "BlendDNA: Did not find a structure named `",ss,"`" - )); + throw Error("BlendDNA: Did not find a structure named `",ss,"`"); } return structures[(*it).second]; @@ -803,9 +793,7 @@ const Structure* DNA :: Get (const std::string& ss) const const Structure& DNA :: operator [] (const size_t i) const { if (i >= structures.size()) { - throw Error((Formatter::format(), - "BlendDNA: There is no structure with index `",i,"`" - )); + throw Error("BlendDNA: There is no structure with index `",i,"`"); } return structures[i]; diff --git a/code/AssetLib/Blender/BlenderLoader.cpp b/code/AssetLib/Blender/BlenderLoader.cpp index 508db8422..8d14d0b9b 100644 --- a/code/AssetLib/Blender/BlenderLoader.cpp +++ b/code/AssetLib/Blender/BlenderLoader.cpp @@ -748,9 +748,8 @@ void BlenderImporter::BuildMaterials(ConversionData &conv_data) { void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) { ai_assert(dt); if (strcmp(dt->dna_type, check)) { - ThrowException((format(), - "Expected object at ", std::hex, dt, " to be of type `", check, - "`, but it claims to be a `", dt->dna_type, "`instead")); + ThrowException("Expected object at ", std::hex, dt, " to be of type `", check, + "`, but it claims to be a `", dt->dna_type, "`instead"); } } diff --git a/code/AssetLib/COB/COBLoader.cpp b/code/AssetLib/COB/COBLoader.cpp index 86550e776..80b41143e 100644 --- a/code/AssetLib/COB/COBLoader.cpp +++ b/code/AssetLib/COB/COBLoader.cpp @@ -125,7 +125,7 @@ void COBImporter::SetupProperties(const Importer * /*pImp*/) { // ------------------------------------------------------------------------------------------------ /*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string &msg) { - throw DeadlyImportError("COB: " + msg); + throw DeadlyImportError("COB: ", msg); } // ------------------------------------------------------------------------------------------------ diff --git a/code/AssetLib/CSM/CSMLoader.cpp b/code/AssetLib/CSM/CSMLoader.cpp index c455bb3a4..a90bc4b89 100644 --- a/code/AssetLib/CSM/CSMLoader.cpp +++ b/code/AssetLib/CSM/CSMLoader.cpp @@ -128,7 +128,7 @@ void CSMImporter::InternReadFile( const std::string& pFile, // Check whether we can read from the file if( file.get() == nullptr) { - throw DeadlyImportError( "Failed to open CSM file " + pFile + "."); + throw DeadlyImportError( "Failed to open CSM file ", pFile, "."); } // allocate storage and copy the contents of the file to a memory buffer diff --git a/code/AssetLib/Collada/ColladaLoader.cpp b/code/AssetLib/Collada/ColladaLoader.cpp index 7b0fdd8e0..58d413649 100644 --- a/code/AssetLib/Collada/ColladaLoader.cpp +++ b/code/AssetLib/Collada/ColladaLoader.cpp @@ -1251,7 +1251,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse // time count and value count must match if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount) - throw DeadlyImportError(format() << "Time count / value count mismatch in animation channel \"" << e.mChannel->mTarget << "\"."); + throw DeadlyImportError("Time count / value count mismatch in animation channel \"", e.mChannel->mTarget, "\"."); if (e.mTimeAccessor->mCount > 0) { // find bounding times diff --git a/code/AssetLib/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp index 964851d60..90157f63c 100644 --- a/code/AssetLib/Collada/ColladaParser.cpp +++ b/code/AssetLib/Collada/ColladaParser.cpp @@ -66,6 +66,13 @@ using namespace Assimp; using namespace Assimp::Collada; using namespace Assimp::Formatter; +// ------------------------------------------------------------------------------------------------ +// Aborts the file reading with an exception +template +AI_WONT_RETURN void ColladaParser::ThrowException(T&&... args) const { + throw DeadlyImportError("Collada: ", mFileName, " - ", args...); +} + // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) : @@ -116,7 +123,7 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) : // attempt to open the file directly daefile.reset(pIOHandler->Open(pFile)); if (daefile.get() == nullptr) { - throw DeadlyImportError("Failed to open file '" + pFile + "'."); + throw DeadlyImportError("Failed to open file '", pFile, "'."); } } @@ -853,7 +860,7 @@ void ColladaParser::ReadControllerJoints(Collada::Controller &pController) { // local URLS always start with a '#'. We don't support global URLs if (attrSource[0] != '#') - ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of data element"); + ThrowException("Unsupported URL format in \"", attrSource, "\" in source attribute of data element"); attrSource++; // parse source URL to corresponding source @@ -862,7 +869,7 @@ void ColladaParser::ReadControllerJoints(Collada::Controller &pController) { else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) pController.mJointOffsetMatrixSource = attrSource; else - ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in data element"); + ThrowException("Unknown semantic \"", attrSemantic, "\" in data element"); // skip inner data, if present if (!mReader->isEmptyElement()) @@ -904,7 +911,7 @@ void ColladaParser::ReadControllerWeights(Collada::Controller &pController) { // local URLS always start with a '#'. We don't support global URLs if (attrSource[0] != '#') - ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of data element"); + ThrowException("Unsupported URL format in \"", attrSource, "\" in source attribute of data element"); channel.mAccessor = attrSource + 1; // parse source URL to corresponding source @@ -913,7 +920,7 @@ void ColladaParser::ReadControllerWeights(Collada::Controller &pController) { else if (strcmp(attrSemantic, "WEIGHT") == 0) pController.mWeightInputWeights = channel; else - ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in data element"); + ThrowException("Unknown semantic \"", attrSemantic, "\" in data element"); // skip inner data, if present if (!mReader->isEmptyElement()) @@ -1901,7 +1908,7 @@ void ColladaParser::ReadAccessor(const std::string &pID) { int attrSource = GetAttribute("source"); const char *source = mReader->getAttributeValue(attrSource); if (source[0] != '#') - ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of element."); + ThrowException("Unknown reference format in url \"", source, "\" in source attribute of element."); int attrCount = GetAttribute("count"); unsigned int count = (unsigned int)mReader->getAttributeValueAsInt(attrCount); int attrOffset = TestAttribute("offset"); @@ -1968,7 +1975,7 @@ void ColladaParser::ReadAccessor(const std::string &pID) { else if (name == "V") acc.mSubOffset[1] = acc.mParams.size(); //else - // DefaultLogger::get()->warn( format() << "Unknown accessor parameter \"" << name << "\". Ignoring data channel." ); + // DefaultLogger::get()->warn( "Unknown accessor parameter \"", name, "\". Ignoring data channel." ); } // read data type @@ -1989,7 +1996,7 @@ void ColladaParser::ReadAccessor(const std::string &pID) { // skip remaining stuff of this element, if any SkipElement(); } else { - ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag "); + ThrowException("Unexpected sub element <", mReader->getNodeName(), "> in tag "); } } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "accessor") != 0) @@ -2012,7 +2019,7 @@ void ColladaParser::ReadVertexData(Mesh &pMesh) { if (IsElement("input")) { ReadInputChannel(pMesh.mPerVertexData); } else { - ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag "); + ThrowException("Unexpected sub element <", mReader->getNodeName(), "> in tag "); } } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (strcmp(mReader->getNodeName(), "vertices") != 0) @@ -2096,11 +2103,11 @@ void ColladaParser::ReadIndexData(Mesh &pMesh) { } else if (IsElement("ph")) { SkipElement("ph"); } else { - ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">"); + ThrowException("Unexpected sub element <", mReader->getNodeName(), "> in tag <", elementName, ">"); } } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (mReader->getNodeName() != elementName) - ThrowException(format() << "Expected end of <" << elementName << "> element."); + ThrowException("Expected end of <", elementName, "> element."); break; } @@ -2132,7 +2139,7 @@ void ColladaParser::ReadInputChannel(std::vector &poChannels) { int attrSource = GetAttribute("source"); const char *source = mReader->getAttributeValue(attrSource); if (source[0] != '#') - ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of element."); + ThrowException("Unknown reference format in url \"", source, "\" in source attribute of element."); channel.mAccessor = source + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only // read index offset, if per-index @@ -2146,7 +2153,7 @@ void ColladaParser::ReadInputChannel(std::vector &poChannels) { if (attrSet > -1) { attrSet = mReader->getAttributeValueAsInt(attrSet); if (attrSet < 0) - ThrowException(format() << "Invalid index \"" << (attrSet) << "\" in set attribute of element"); + ThrowException("Invalid index \"", (attrSet), "\" in set attribute of element"); channel.mIndex = attrSet; } @@ -2369,7 +2376,7 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, siz const Accessor &acc = *pInput.mResolved; if (pLocalIndex >= acc.mCount) - ThrowException(format() << "Invalid data index (" << pLocalIndex << "/" << acc.mCount << ") in primitive specification"); + ThrowException("Invalid data index (", pLocalIndex, "/", acc.mCount, ") in primitive specification"); // get a pointer to the start of the data object referred to by the accessor and the local index const ai_real *dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex * acc.mStride; @@ -2781,12 +2788,6 @@ void ColladaParser::ReadScene() { } } -// ------------------------------------------------------------------------------------------------ -// Aborts the file reading with an exception -AI_WONT_RETURN void ColladaParser::ThrowException(const std::string &pError) const { - throw DeadlyImportError(format() << "Collada: " << mFileName << " - " << pError); -} - void ColladaParser::ReportWarning(const char *msg, ...) { ai_assert(nullptr != msg); @@ -2833,17 +2834,17 @@ void ColladaParser::SkipElement(const char *pElement) { void ColladaParser::TestOpening(const char *pName) { // read element start if (!mReader->read()) { - ThrowException(format() << "Unexpected end of file while beginning of <" << pName << "> element."); + ThrowException("Unexpected end of file while beginning of <", pName, "> element."); } // whitespace in front is ok, just read again if found if (mReader->getNodeType() == irr::io::EXN_TEXT) { if (!mReader->read()) { - ThrowException(format() << "Unexpected end of file while reading beginning of <" << pName << "> element."); + ThrowException("Unexpected end of file while reading beginning of <", pName, "> element."); } } if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0) { - ThrowException(format() << "Expected start of <" << pName << "> element."); + ThrowException("Expected start of <", pName, "> element."); } } @@ -2862,18 +2863,18 @@ void ColladaParser::TestClosing(const char *pName) { // if not, read some more if (!mReader->read()) { - ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); + ThrowException("Unexpected end of file while reading end of <", pName, "> element."); } // whitespace in front is ok, just read again if found if (mReader->getNodeType() == irr::io::EXN_TEXT) { if (!mReader->read()) { - ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); + ThrowException("Unexpected end of file while reading end of <", pName, "> element."); } } // but this has the be the closing tag, or we're lost if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0) { - ThrowException(format() << "Expected end of <" << pName << "> element."); + ThrowException("Expected end of <", pName, "> element."); } } @@ -2882,7 +2883,7 @@ void ColladaParser::TestClosing(const char *pName) { int ColladaParser::GetAttribute(const char *pAttr) const { int index = TestAttribute(pAttr); if (index == -1) { - ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); + ThrowException("Expected attribute \"", pAttr, "\" for element <", mReader->getNodeName(), ">."); } // attribute not found -> throw an exception diff --git a/code/AssetLib/Collada/ColladaParser.h b/code/AssetLib/Collada/ColladaParser.h index f6056abcc..bb2f2e247 100644 --- a/code/AssetLib/Collada/ColladaParser.h +++ b/code/AssetLib/Collada/ColladaParser.h @@ -242,7 +242,9 @@ protected: protected: /** Aborts the file reading with an exception */ - AI_WONT_RETURN void ThrowException(const std::string &pError) const AI_WONT_RETURN_SUFFIX; + template + AI_WONT_RETURN void ThrowException(T&&... args) const AI_WONT_RETURN_SUFFIX; + void ReportWarning(const char *msg, ...); /** Skips all data until the end node of the current element */ @@ -383,7 +385,7 @@ template const Type &ColladaParser::ResolveLibraryReference(const std::map &pLibrary, const std::string &pURL) const { typename std::map::const_iterator it = pLibrary.find(pURL); if (it == pLibrary.end()) - ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\"."); + ThrowException("Unable to resolve library reference \"", pURL, "\"."); return it->second; } diff --git a/code/AssetLib/DXF/DXFLoader.cpp b/code/AssetLib/DXF/DXFLoader.cpp index 97b0d19dd..cda391fb8 100644 --- a/code/AssetLib/DXF/DXFLoader.cpp +++ b/code/AssetLib/DXF/DXFLoader.cpp @@ -152,7 +152,7 @@ void DXFImporter::InternReadFile( const std::string& filename, aiScene* pScene, // Check whether we can read the file if( file.get() == nullptr ) { - throw DeadlyImportError( "Failed to open DXF file " + filename + ""); + throw DeadlyImportError( "Failed to open DXF file ", filename, ""); } // Check whether this is a binary DXF file - we can't read binary DXF files :-( diff --git a/code/AssetLib/FBX/FBXBinaryTokenizer.cpp b/code/AssetLib/FBX/FBXBinaryTokenizer.cpp index 78f02ff96..419750e2c 100644 --- a/code/AssetLib/FBX/FBXBinaryTokenizer.cpp +++ b/code/AssetLib/FBX/FBXBinaryTokenizer.cpp @@ -127,7 +127,7 @@ namespace { AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) { - throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset)); + throw DeadlyImportError("FBX-Tokenize", Util::GetOffsetText(offset), message); } @@ -468,7 +468,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length) catch (const DeadlyImportError& e) { if (!is64bits && (length > std::numeric_limits::max())) { - throw DeadlyImportError("The FBX file is invalid. This may be because the content is too big for this older version (" + to_string(version) + ") of the FBX format. (" + e.what() + ")"); + throw DeadlyImportError("The FBX file is invalid. This may be because the content is too big for this older version (", to_string(version), ") of the FBX format. (", e.what(), ")"); } throw; } diff --git a/code/AssetLib/FBX/FBXDocumentUtil.cpp b/code/AssetLib/FBX/FBXDocumentUtil.cpp index 16235645c..42c056628 100644 --- a/code/AssetLib/FBX/FBXDocumentUtil.cpp +++ b/code/AssetLib/FBX/FBXDocumentUtil.cpp @@ -61,7 +61,7 @@ namespace Util { // signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError. void DOMError(const std::string& message, const Token& token) { - throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token)); + throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message); } // ------------------------------------------------------------------------------------------------ @@ -70,7 +70,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/) if(element) { DOMError(message,element->KeyToken()); } - throw DeadlyImportError("FBX-DOM " + message); + throw DeadlyImportError("FBX-DOM ", message); } @@ -79,7 +79,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/) void DOMWarning(const std::string& message, const Token& token) { if(DefaultLogger::get()) { - ASSIMP_LOG_WARN(Util::AddTokenText("FBX-DOM",message,&token)); + ASSIMP_LOG_WARN_F("FBX-DOM", Util::GetTokenText(&token), message); } } diff --git a/code/AssetLib/FBX/FBXParser.cpp b/code/AssetLib/FBX/FBXParser.cpp index 3c9137ccc..f93f69d4d 100644 --- a/code/AssetLib/FBX/FBXParser.cpp +++ b/code/AssetLib/FBX/FBXParser.cpp @@ -73,7 +73,7 @@ namespace { AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) { - throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token)); + throw DeadlyImportError("FBX-Parser", Util::GetTokenText(&token), message); } // ------------------------------------------------------------------------------------------------ @@ -83,7 +83,7 @@ namespace { if(element) { ParseError(message,element->KeyToken()); } - throw DeadlyImportError("FBX-Parser " + message); + throw DeadlyImportError("FBX-Parser ", message); } diff --git a/code/AssetLib/FBX/FBXTokenizer.cpp b/code/AssetLib/FBX/FBXTokenizer.cpp index bd3ee7ad1..2bb054d8e 100644 --- a/code/AssetLib/FBX/FBXTokenizer.cpp +++ b/code/AssetLib/FBX/FBXTokenizer.cpp @@ -90,7 +90,7 @@ namespace { AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) { - throw DeadlyImportError(Util::AddLineAndColumn("FBX-Tokenize",message,line,column)); + throw DeadlyImportError("FBX-Tokenize", Util::GetLineAndColumnText(line,column), message); } diff --git a/code/AssetLib/FBX/FBXUtil.cpp b/code/AssetLib/FBX/FBXUtil.cpp index 50dd78a4c..983730011 100644 --- a/code/AssetLib/FBX/FBXUtil.cpp +++ b/code/AssetLib/FBX/FBXUtil.cpp @@ -86,32 +86,30 @@ const char* TokenTypeString(TokenType t) // ------------------------------------------------------------------------------------------------ -std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset) +std::string GetOffsetText(size_t offset) { - return static_cast( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) ); + return static_cast( Formatter::format() << " (offset 0x" << std::hex << offset << ") " ); } // ------------------------------------------------------------------------------------------------ -std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column) +std::string GetLineAndColumnText(unsigned int line, unsigned int column) { - return static_cast( (Formatter::format() << prefix << " (line " << line << " << col " << column << ") " << text) ); + return static_cast( Formatter::format() << " (line " << line << " << col " << column << ") " ); } // ------------------------------------------------------------------------------------------------ -std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok) +std::string GetTokenText(const Token* tok) { if(tok->IsBinary()) { - return static_cast( (Formatter::format() << prefix << + return static_cast( Formatter::format() << " (" << TokenTypeString(tok->Type()) << - ", offset 0x" << std::hex << tok->Offset() << ") " << - text) ); + ", offset 0x" << std::hex << tok->Offset() << ") " ); } - return static_cast( (Formatter::format() << prefix << + return static_cast( Formatter::format() << " (" << TokenTypeString(tok->Type()) << ", line " << tok->Line() << - ", col " << tok->Column() << ") " << - text) ); + ", col " << tok->Column() << ") " ); } // Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; diff --git a/code/AssetLib/FBX/FBXUtil.h b/code/AssetLib/FBX/FBXUtil.h index 77bb0ad30..82d53eea1 100644 --- a/code/AssetLib/FBX/FBXUtil.h +++ b/code/AssetLib/FBX/FBXUtil.h @@ -73,31 +73,24 @@ const char* TokenTypeString(TokenType t); /** Format log/error messages using a given offset in the source binary file * - * @param prefix Message prefix to be preprended to the location info. - * @param text Message text - * @param line Line index, 1-based - * @param column Column index, 1-based - * @return A string of the following format: {prefix} (offset 0x{offset}) {text}*/ -std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset); + * @param offset offset within the file + * @return A string of the following format: " (offset 0x{offset}) "*/ +std::string GetOffsetText(size_t offset); /** Format log/error messages using a given line location in the source file. * - * @param prefix Message prefix to be preprended to the location info. - * @param text Message text * @param line Line index, 1-based * @param column Column index, 1-based - * @return A string of the following format: {prefix} (line {line}, col {column}) {text}*/ -std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column); + * @return A string of the following format: " (line {line}, col {column}) "*/ +std::string GetLineAndColumnText(unsigned int line, unsigned int column); /** Format log/error messages using a given cursor token. * - * @param prefix Message prefix to be preprended to the location info. - * @param text Message text * @param tok Token where parsing/processing stopped - * @return A string of the following format: {prefix} ({token-type}, line {line}, col {column}) {text}*/ -std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok); + * @return A string of the following format: " ({token-type}, line {line}, col {column}) "*/ +std::string GetTokenText(const Token* tok); /** Decode a single Base64-encoded character. * diff --git a/code/AssetLib/HMP/HMPLoader.cpp b/code/AssetLib/HMP/HMPLoader.cpp index 33460cc73..8ccba2ea4 100644 --- a/code/AssetLib/HMP/HMPLoader.cpp +++ b/code/AssetLib/HMP/HMPLoader.cpp @@ -115,7 +115,7 @@ void HMPImporter::InternReadFile(const std::string &pFile, // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open HMP file " + pFile + "."); + throw DeadlyImportError("Failed to open HMP file ", pFile, "."); } // Check whether the HMP file is large enough to contain @@ -159,8 +159,8 @@ void HMPImporter::InternReadFile(const std::string &pFile, szBuffer[4] = '\0'; // We're definitely unable to load this file - throw DeadlyImportError("Unknown HMP subformat " + pFile + - ". Magic word (" + szBuffer + ") is not known"); + throw DeadlyImportError("Unknown HMP subformat ", pFile, + ". Magic word (", szBuffer, ") is not known"); } // Set the AI_SCENE_FLAGS_TERRAIN bit diff --git a/code/AssetLib/Irr/IRRLoader.cpp b/code/AssetLib/Irr/IRRLoader.cpp index 5d5253516..c26ee40ba 100644 --- a/code/AssetLib/Irr/IRRLoader.cpp +++ b/code/AssetLib/Irr/IRRLoader.cpp @@ -867,7 +867,7 @@ void IRRImporter::InternReadFile(const std::string &pFile, // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open IRR file " + pFile + ""); + throw DeadlyImportError("Failed to open IRR file ", pFile, ""); } // Construct the irrXML parser diff --git a/code/AssetLib/Irr/IRRMeshLoader.cpp b/code/AssetLib/Irr/IRRMeshLoader.cpp index d07ff87ea..48bd06b3e 100644 --- a/code/AssetLib/Irr/IRRMeshLoader.cpp +++ b/code/AssetLib/Irr/IRRMeshLoader.cpp @@ -140,7 +140,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open IRRMESH file " + pFile + "."); + throw DeadlyImportError("Failed to open IRRMESH file ", pFile, "."); } // Construct the irrXML parser diff --git a/code/AssetLib/LWO/LWOLoader.cpp b/code/AssetLib/LWO/LWOLoader.cpp index ef11f2d15..149360559 100644 --- a/code/AssetLib/LWO/LWOLoader.cpp +++ b/code/AssetLib/LWO/LWOLoader.cpp @@ -145,7 +145,7 @@ void LWOImporter::InternReadFile(const std::string &pFile, // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open LWO file " + pFile + "."); + throw DeadlyImportError("Failed to open LWO file ", pFile, "."); } if ((this->fileSize = (unsigned int)file->FileSize()) < 12) { @@ -212,7 +212,7 @@ void LWOImporter::InternReadFile(const std::string &pFile, szBuff[2] = (char)(fileType >> 8u); szBuff[3] = (char)(fileType); szBuff[4] = '\0'; - throw DeadlyImportError(std::string("Unknown LWO sub format: ") + szBuff); + throw DeadlyImportError("Unknown LWO sub format: ", szBuff); } if (AI_LWO_FOURCC_LWOB != fileType) { @@ -232,7 +232,7 @@ void LWOImporter::InternReadFile(const std::string &pFile, } if (configLayerName.length() && !hasNamedLayer) { - throw DeadlyImportError("LWO2: Unable to find the requested layer: " + configLayerName); + throw DeadlyImportError("LWO2: Unable to find the requested layer: ", configLayerName); } } diff --git a/code/AssetLib/LWS/LWSLoader.cpp b/code/AssetLib/LWS/LWSLoader.cpp index 38b44f842..7d67c86d6 100644 --- a/code/AssetLib/LWS/LWSLoader.cpp +++ b/code/AssetLib/LWS/LWSLoader.cpp @@ -502,7 +502,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open LWS file " + pFile + "."); + throw DeadlyImportError("Failed to open LWS file ", pFile, "."); } // Allocate storage and copy the contents of the file to a memory buffer diff --git a/code/AssetLib/M3D/M3DImporter.cpp b/code/AssetLib/M3D/M3DImporter.cpp index d6fe678ec..05b75148b 100644 --- a/code/AssetLib/M3D/M3DImporter.cpp +++ b/code/AssetLib/M3D/M3DImporter.cpp @@ -160,21 +160,21 @@ void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSys // Read file into memory std::unique_ptr pStream(pIOHandler->Open(file, "rb")); if (!pStream.get()) { - throw DeadlyImportError("Failed to open file " + file + "."); + throw DeadlyImportError("Failed to open file ", file, "."); } // Get the file-size and validate it, throwing an exception when fails size_t fileSize = pStream->FileSize(); if (fileSize < 8) { - throw DeadlyImportError("M3D-file " + file + " is too small."); + throw DeadlyImportError("M3D-file ", file, " is too small."); } std::vector buffer(fileSize); if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) { - throw DeadlyImportError("Failed to read the file " + file + "."); + throw DeadlyImportError("Failed to read the file ", file, "."); } // extra check for binary format's first 8 bytes. Not done for the ASCII variant if (!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) { - throw DeadlyImportError("Bad binary header in file " + file + "."); + throw DeadlyImportError("Bad binary header in file ", file, "."); } #ifdef M3D_ASCII // make sure there's a terminator zero character, as input must be ASCIIZ @@ -200,7 +200,7 @@ void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSys M3DWrapper m3d(pIOHandler, buffer); if (!m3d) { - throw DeadlyImportError("Unable to parse " + file + " as M3D."); + throw DeadlyImportError("Unable to parse ", file, " as M3D."); } // create the root node diff --git a/code/AssetLib/MD2/MD2Loader.cpp b/code/AssetLib/MD2/MD2Loader.cpp index abc5f06ff..87b7a5609 100644 --- a/code/AssetLib/MD2/MD2Loader.cpp +++ b/code/AssetLib/MD2/MD2Loader.cpp @@ -222,7 +222,7 @@ void MD2Importer::InternReadFile( const std::string& pFile, // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open MD2 file " + pFile + ""); + throw DeadlyImportError("Failed to open MD2 file ", pFile, ""); } // check whether the md3 file is large enough to contain diff --git a/code/AssetLib/MD3/MD3Loader.cpp b/code/AssetLib/MD3/MD3Loader.cpp index 92d567801..9c31a7b20 100644 --- a/code/AssetLib/MD3/MD3Loader.cpp +++ b/code/AssetLib/MD3/MD3Loader.cpp @@ -715,7 +715,7 @@ void MD3Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open MD3 file " + pFile + "."); + throw DeadlyImportError("Failed to open MD3 file ", pFile, "."); } // Check whether the md3 file is large enough to contain the header diff --git a/code/AssetLib/MD5/MD5Loader.cpp b/code/AssetLib/MD5/MD5Loader.cpp index 5428a9c74..1741f4472 100644 --- a/code/AssetLib/MD5/MD5Loader.cpp +++ b/code/AssetLib/MD5/MD5Loader.cpp @@ -675,7 +675,7 @@ void MD5Importer::LoadMD5CameraFile() { // Check whether we can read from the file if (!file.get() || !file->FileSize()) { - throw DeadlyImportError("Failed to read MD5CAMERA file: " + pFile); + throw DeadlyImportError("Failed to read MD5CAMERA file: ", pFile); } mHadMD5Camera = true; LoadFileIntoMemory(file.get()); diff --git a/code/AssetLib/MDC/MDCLoader.cpp b/code/AssetLib/MDC/MDCLoader.cpp index 5748fba0b..0e917171c 100644 --- a/code/AssetLib/MDC/MDCLoader.cpp +++ b/code/AssetLib/MDC/MDCLoader.cpp @@ -219,7 +219,7 @@ void MDCImporter::InternReadFile( // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open MDC file " + pFile + "."); + throw DeadlyImportError("Failed to open MDC file ", pFile, "."); } // check whether the mdc file is large enough to contain the file header diff --git a/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h b/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h index 2891ddb1e..2fa1fd0e4 100644 --- a/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h +++ b/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h @@ -218,12 +218,12 @@ private: template void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned char *&buffer) { if (!io_->Exists(file_path)) - throw DeadlyImportError("Missing file " + DefaultIOSystem::fileName(file_path) + "."); + throw DeadlyImportError("Missing file ", DefaultIOSystem::fileName(file_path), "."); std::unique_ptr file(io_->Open(file_path)); if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open MDL file " + DefaultIOSystem::fileName(file_path) + "."); + throw DeadlyImportError("Failed to open MDL file ", DefaultIOSystem::fileName(file_path), "."); } const size_t file_size = file->FileSize(); diff --git a/code/AssetLib/MDL/MDLLoader.cpp b/code/AssetLib/MDL/MDLLoader.cpp index e917e3b5e..4e28f1a2f 100644 --- a/code/AssetLib/MDL/MDLLoader.cpp +++ b/code/AssetLib/MDL/MDLLoader.cpp @@ -167,7 +167,7 @@ void MDLImporter::InternReadFile(const std::string &pFile, // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open MDL file " + pFile + "."); + throw DeadlyImportError("Failed to open MDL file ", pFile, "."); } // This should work for all other types of MDL files, too ... @@ -251,8 +251,8 @@ void MDLImporter::InternReadFile(const std::string &pFile, } } else { // print the magic word to the log file - throw DeadlyImportError("Unknown MDL subformat " + pFile + - ". Magic word (" + std::string((char *)&iMagicWord, 4) + ") is not known"); + throw DeadlyImportError("Unknown MDL subformat ", pFile, + ". Magic word (", std::string((char *)&iMagicWord, 4), ") is not known"); } // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system diff --git a/code/AssetLib/MMD/MMDImporter.cpp b/code/AssetLib/MMD/MMDImporter.cpp index 0814f4813..d1912d2fe 100644 --- a/code/AssetLib/MMD/MMDImporter.cpp +++ b/code/AssetLib/MMD/MMDImporter.cpp @@ -111,7 +111,7 @@ void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene, // Read file by istream std::filebuf fb; if (!fb.open(file, std::ios::in | std::ios::binary)) { - throw DeadlyImportError("Failed to open file " + file + "."); + throw DeadlyImportError("Failed to open file ", file, "."); } std::istream fileStream(&fb); @@ -122,7 +122,7 @@ void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene, fileStream.seekg(0, fileStream.beg); if (fileSize < sizeof(pmx::PmxModel)) { - throw DeadlyImportError(file + " is too small."); + throw DeadlyImportError(file, " is too small."); } pmx::PmxModel model; diff --git a/code/AssetLib/MMD/MMDPmxParser.cpp b/code/AssetLib/MMD/MMDPmxParser.cpp index 7ac5ac399..bbeeef4b8 100644 --- a/code/AssetLib/MMD/MMDPmxParser.cpp +++ b/code/AssetLib/MMD/MMDPmxParser.cpp @@ -524,7 +524,7 @@ namespace pmx if (version != 2.0f && version != 2.1f) { std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl; - throw DeadlyImportError("MMD: this is not ver2.0 or ver2.1 but " + to_string(version)); + throw DeadlyImportError("MMD: this is not ver2.0 or ver2.1 but ", to_string(version)); } this->setting.Read(stream); diff --git a/code/AssetLib/MS3D/MS3DLoader.cpp b/code/AssetLib/MS3D/MS3DLoader.cpp index b5b6673f3..7edbd91f2 100644 --- a/code/AssetLib/MS3D/MS3DLoader.cpp +++ b/code/AssetLib/MS3D/MS3DLoader.cpp @@ -229,7 +229,7 @@ void MS3DImporter::InternReadFile( const std::string& pFile, stream.CopyAndAdvance(head,10); stream >> version; if (strncmp(head,"MS3D000000",10)) { - throw DeadlyImportError("Not a MS3D file, magic string MS3D000000 not found: "+pFile); + throw DeadlyImportError("Not a MS3D file, magic string MS3D000000 not found: ", pFile); } if (version != 4) { diff --git a/code/AssetLib/NFF/NFFLoader.cpp b/code/AssetLib/NFF/NFFLoader.cpp index a5e6c8c7a..1a4a65982 100644 --- a/code/AssetLib/NFF/NFFLoader.cpp +++ b/code/AssetLib/NFF/NFFLoader.cpp @@ -214,7 +214,7 @@ void NFFImporter::InternReadFile(const std::string &pFile, // Check whether we can read from the file if (!file.get()) - throw DeadlyImportError("Failed to open NFF file " + pFile + "."); + throw DeadlyImportError("Failed to open NFF file ", pFile, "."); // allocate storage and copy the contents of the file to a memory buffer // (terminate it with zero) diff --git a/code/AssetLib/OFF/OFFLoader.cpp b/code/AssetLib/OFF/OFFLoader.cpp index 79f006fca..fa981e439 100644 --- a/code/AssetLib/OFF/OFFLoader.cpp +++ b/code/AssetLib/OFF/OFFLoader.cpp @@ -123,7 +123,7 @@ void OFFImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS // Check whether we can read from the file if( file.get() == nullptr) { - throw DeadlyImportError( "Failed to open OFF file " + pFile + "."); + throw DeadlyImportError( "Failed to open OFF file ", pFile, "."); } // allocate storage and copy the contents of the file to a memory buffer diff --git a/code/AssetLib/Obj/ObjFileImporter.cpp b/code/AssetLib/Obj/ObjFileImporter.cpp index 4fa122c45..b07bc135e 100644 --- a/code/AssetLib/Obj/ObjFileImporter.cpp +++ b/code/AssetLib/Obj/ObjFileImporter.cpp @@ -112,7 +112,7 @@ void ObjFileImporter::InternReadFile(const std::string &file, aiScene *pScene, I }; std::unique_ptr fileStream(pIOHandler->Open(file, mode), streamCloser); if (!fileStream.get()) { - throw DeadlyImportError("Failed to open file " + file + "."); + throw DeadlyImportError("Failed to open file ", file, "."); } // Get the file-size and validate it, throwing an exception when fails diff --git a/code/AssetLib/Ogre/OgreBinarySerializer.cpp b/code/AssetLib/Ogre/OgreBinarySerializer.cpp index 360da898f..6f6a19bd9 100644 --- a/code/AssetLib/Ogre/OgreBinarySerializer.cpp +++ b/code/AssetLib/Ogre/OgreBinarySerializer.cpp @@ -187,8 +187,8 @@ Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream) { /// @todo Check what we can actually support. std::string version = serializer.ReadLine(); if (version != MESH_VERSION_1_8) { - throw DeadlyExportError(Formatter::format() << "Mesh version " << version << " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again." - << " Supported versions: " << MESH_VERSION_1_8); + throw DeadlyExportError("Mesh version ", version, " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again.", + " Supported versions: ", MESH_VERSION_1_8); } Mesh *mesh = new Mesh(); @@ -471,7 +471,7 @@ void OgreBinarySerializer::ReadSubMeshNames(Mesh *mesh) { uint16_t submeshIndex = Read(); SubMesh *submesh = mesh->GetSubMesh(submeshIndex); if (!submesh) { - throw DeadlyImportError(Formatter::format() << "Ogre Mesh does not include submesh " << submeshIndex << " referenced in M_SUBMESH_NAME_TABLE_ELEMENT. Invalid mesh file."); + throw DeadlyImportError("Ogre Mesh does not include submesh ", submeshIndex, " referenced in M_SUBMESH_NAME_TABLE_ELEMENT. Invalid mesh file."); } submesh->name = ReadLine(); @@ -788,7 +788,7 @@ MemoryStreamReaderPtr OgreBinarySerializer::OpenReader(Assimp::IOSystem *pIOHand IOStream *f = pIOHandler->Open(filename, "rb"); if (!f) { - throw DeadlyImportError("Failed to open skeleton file " + filename); + throw DeadlyImportError("Failed to open skeleton file ", filename); } return MemoryStreamReaderPtr(new MemoryStreamReader(f)); @@ -803,8 +803,8 @@ void OgreBinarySerializer::ReadSkeleton(Skeleton *skeleton) { // This deserialization supports both versions of the skeleton spec std::string version = ReadLine(); if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1) { - throw DeadlyExportError(Formatter::format() << "Skeleton version " << version << " not supported by this importer." - << " Supported versions: " << SKELETON_VERSION_1_8 << " and " << SKELETON_VERSION_1_1); + throw DeadlyExportError("Skeleton version ", version, " not supported by this importer.", + " Supported versions: ", SKELETON_VERSION_1_8, " and ", SKELETON_VERSION_1_1); } ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton"); @@ -871,7 +871,7 @@ void OgreBinarySerializer::ReadBone(Skeleton *skeleton) { // Bone indexes need to start from 0 and be contiguous if (bone->id != skeleton->bones.size()) { - throw DeadlyImportError(Formatter::format() << "Ogre Skeleton bone indexes not contiguous. Error at bone index " << bone->id); + throw DeadlyImportError("Ogre Skeleton bone indexes not contiguous. Error at bone index ", bone->id); } ASSIMP_LOG_VERBOSE_DEBUG_F(" ", bone->id, " ", bone->name); @@ -889,7 +889,7 @@ void OgreBinarySerializer::ReadBoneParent(Skeleton *skeleton) { if (child && parent) parent->AddChild(child); else - throw DeadlyImportError(Formatter::format() << "Failed to find bones for parenting: Child id " << childId << " for parent id " << parentId); + throw DeadlyImportError("Failed to find bones for parenting: Child id ", childId, " for parent id ", parentId); } void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton) { @@ -926,7 +926,7 @@ void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton * /*skeleton*/, A uint16_t boneId = Read(); Bone *bone = dest->parentSkeleton->BoneById(boneId); if (!bone) { - throw DeadlyImportError(Formatter::format() << "Cannot read animation track, target bone " << boneId << " not in target Skeleton"); + throw DeadlyImportError("Cannot read animation track, target bone ", boneId, " not in target Skeleton"); } VertexAnimationTrack track; diff --git a/code/AssetLib/Ogre/OgreImporter.cpp b/code/AssetLib/Ogre/OgreImporter.cpp index 9d85a0a96..636c903d5 100644 --- a/code/AssetLib/Ogre/OgreImporter.cpp +++ b/code/AssetLib/Ogre/OgreImporter.cpp @@ -100,7 +100,7 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass // Open source file IOStream *f = pIOHandler->Open(pFile, "rb"); if (!f) { - throw DeadlyImportError("Failed to open file " + pFile); + throw DeadlyImportError("Failed to open file ", pFile); } // Binary .mesh import diff --git a/code/AssetLib/Ogre/OgreStructs.cpp b/code/AssetLib/Ogre/OgreStructs.cpp index 4a4f9479e..b915c742f 100644 --- a/code/AssetLib/Ogre/OgreStructs.cpp +++ b/code/AssetLib/Ogre/OgreStructs.cpp @@ -476,7 +476,7 @@ void SubMesh::Reset(){ aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent) { if (operationType != OT_TRIANGLE_LIST) { - throw DeadlyImportError(Formatter::format() << "Only mesh operation type OT_TRIANGLE_LIST is supported. Found " << operationType); + throw DeadlyImportError("Only mesh operation type OT_TRIANGLE_LIST is supported. Found ", operationType); } aiMesh *dest = new aiMesh(); @@ -944,7 +944,7 @@ void Bone::AddChild(Bone *bone) { if (!bone) return; if (bone->IsParented()) - throw DeadlyImportError("Attaching child Bone that is already parented: " + bone->name); + throw DeadlyImportError("Attaching child Bone that is already parented: ", bone->name); bone->parent = this; bone->parentId = id; @@ -963,7 +963,7 @@ void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton) { for (auto boneId : children) { Bone *child = skeleton->BoneById(boneId); if (!child) { - throw DeadlyImportError(Formatter::format() << "CalculateWorldMatrixAndDefaultPose: Failed to find child bone " << boneId << " for parent " << id << " " << name); + throw DeadlyImportError("CalculateWorldMatrixAndDefaultPose: Failed to find child bone ", boneId, " for parent ", id, " ", name); } child->CalculateWorldMatrixAndDefaultPose(skeleton); } @@ -983,7 +983,7 @@ aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode) { for (size_t i = 0, len = children.size(); i < len; ++i) { Bone *child = skeleton->BoneById(children[i]); if (!child) { - throw DeadlyImportError(Formatter::format() << "ConvertToAssimpNode: Failed to find child bone " << children[i] << " for parent " << id << " " << name); + throw DeadlyImportError("ConvertToAssimpNode: Failed to find child bone ", children[i], " for parent ", id, " ", name); } node->mChildren[i] = child->ConvertToAssimpNode(skeleton, node); } @@ -1022,7 +1022,7 @@ aiNodeAnim *VertexAnimationTrack::ConvertToAssimpAnimationNode(Skeleton *skeleto Bone *bone = skeleton->BoneByName(boneName); if (!bone) { - throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Failed to find bone " + boneName + " from parent Skeleton"); + throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Failed to find bone ", boneName, " from parent Skeleton"); } // Keyframes diff --git a/code/AssetLib/Ogre/OgreXmlSerializer.cpp b/code/AssetLib/Ogre/OgreXmlSerializer.cpp index 31c2ee74e..c1a9245aa 100644 --- a/code/AssetLib/Ogre/OgreXmlSerializer.cpp +++ b/code/AssetLib/Ogre/OgreXmlSerializer.cpp @@ -59,9 +59,9 @@ namespace Ogre { AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error) { if (!error.empty()) { - throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'"); + throw DeadlyImportError(error, " in node '", reader->getNodeName(), "' and attribute '", name, "'"); } else { - throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'"); + throw DeadlyImportError("Attribute '", name, "' does not exist in node '", reader->getNodeName(), "'"); } } @@ -265,7 +265,7 @@ MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) { void OgreXmlSerializer::ReadMesh(MeshXml *mesh) { if (NextNode() != nnMesh) { - throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting "); + throw DeadlyImportError("Root node is <", m_currentNodeName, "> expecting "); } ASSIMP_LOG_VERBOSE_DEBUG("Reading Mesh"); @@ -430,18 +430,18 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) { // Sanity checks if (dest->positions.size() != dest->count) { - throw DeadlyImportError(Formatter::format() << "Read only " << dest->positions.size() << " positions when should have read " << dest->count); + throw DeadlyImportError("Read only ", dest->positions.size(), " positions when should have read ", dest->count); } if (normals && dest->normals.size() != dest->count) { - throw DeadlyImportError(Formatter::format() << "Read only " << dest->normals.size() << " normals when should have read " << dest->count); + throw DeadlyImportError("Read only ", dest->normals.size(), " normals when should have read ", dest->count); } if (tangents && dest->tangents.size() != dest->count) { - throw DeadlyImportError(Formatter::format() << "Read only " << dest->tangents.size() << " tangents when should have read " << dest->count); + throw DeadlyImportError("Read only ", dest->tangents.size(), " tangents when should have read ", dest->count); } for (unsigned int i = 0; i < dest->uvs.size(); ++i) { if (dest->uvs[i].size() != dest->count) { - throw DeadlyImportError(Formatter::format() << "Read only " << dest->uvs[i].size() - << " uvs for uv index " << i << " when should have read " << dest->count); + throw DeadlyImportError("Read only ", dest->uvs[i].size(), + " uvs for uv index ", i, " when should have read ", dest->count); } } } @@ -507,7 +507,7 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) { if (submesh->indexData->faces.size() == submesh->indexData->faceCount) { ASSIMP_LOG_VERBOSE_DEBUG_F(" - Faces ", submesh->indexData->faceCount); } else { - throw DeadlyImportError(Formatter::format() << "Read only " << submesh->indexData->faces.size() << " faces when should have read " << submesh->indexData->faceCount); + throw DeadlyImportError("Read only ", submesh->indexData->faces.size(), " faces when should have read ", submesh->indexData->faceCount); } } else if (m_currentNodeName == nnGeometry) { if (submesh->usesSharedVertexData) { @@ -632,20 +632,20 @@ XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const s std::unique_ptr file(pIOHandler->Open(filename)); if (!file.get()) { - throw DeadlyImportError("Failed to open skeleton file " + filename); + throw DeadlyImportError("Failed to open skeleton file ", filename); } std::unique_ptr stream(new CIrrXML_IOStreamReader(file.get())); XmlReaderPtr reader = XmlReaderPtr(irr::io::createIrrXMLReader(stream.get())); if (!reader.get()) { - throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename); + throw DeadlyImportError("Failed to create XML reader for skeleton file ", filename); } return reader; } void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) { if (NextNode() != nnSkeleton) { - throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting "); + throw DeadlyImportError("Root node is <", m_currentNodeName, "> expecting "); } ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton"); @@ -687,7 +687,7 @@ void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) { anim->length = ReadAttribute("length"); if (NextNode() != nnTracks) { - throw DeadlyImportError(Formatter::format() << "No found in " << anim->name); + throw DeadlyImportError("No found in ", anim->name); } ReadAnimationTracks(anim); @@ -705,7 +705,7 @@ void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) { track.boneName = ReadAttribute("bone"); if (NextNode() != nnKeyFrames) { - throw DeadlyImportError(Formatter::format() << "No found in " << dest->name); + throw DeadlyImportError("No found in ", dest->name); } ReadAnimationKeyFrames(dest, &track); @@ -732,7 +732,7 @@ void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationT float angle = ReadAttribute("angle"); if (NextNode() != nnAxis) { - throw DeadlyImportError("No axis specified for keyframe rotation in animation " + anim->name); + throw DeadlyImportError("No axis specified for keyframe rotation in animation ", anim->name); } aiVector3D axis; @@ -774,7 +774,7 @@ void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) { if (bone && parent) parent->AddChild(bone); else - throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName); + throw DeadlyImportError("Failed to find bones for parenting: Child ", name, " for parent ", parentName); } // Calculate bone matrices for root bones. Recursively calculates their children. @@ -813,7 +813,7 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton) { float angle = ReadAttribute("angle"); if (NextNode() != nnAxis) { - throw DeadlyImportError(Formatter::format() << "No axis specified for bone rotation in bone " << bone->id); + throw DeadlyImportError("No axis specified for bone rotation in bone ", bone->id); } aiVector3D axis; @@ -854,7 +854,7 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton) { ASSIMP_LOG_VERBOSE_DEBUG_F(" ", b->id, " ", b->name); if (b->id != static_cast(i)) { - throw DeadlyImportError(Formatter::format() << "Bone ids are not in sequence starting from 0. Missing index " << i); + throw DeadlyImportError("Bone ids are not in sequence starting from 0. Missing index ", i); } } } diff --git a/code/AssetLib/OpenGEX/OpenGEXImporter.cpp b/code/AssetLib/OpenGEX/OpenGEXImporter.cpp index 880303065..ff6af63f6 100644 --- a/code/AssetLib/OpenGEX/OpenGEXImporter.cpp +++ b/code/AssetLib/OpenGEX/OpenGEXImporter.cpp @@ -302,7 +302,7 @@ void OpenGEXImporter::InternReadFile( const std::string &filename, aiScene *pSce // open source file IOStream *file = pIOHandler->Open( filename, "rb" ); if( !file ) { - throw DeadlyImportError( "Failed to open file " + filename ); + throw DeadlyImportError( "Failed to open file ", filename ); } std::vector buffer; diff --git a/code/AssetLib/Ply/PlyLoader.cpp b/code/AssetLib/Ply/PlyLoader.cpp index b8dbf2598..4a8aaf17b 100644 --- a/code/AssetLib/Ply/PlyLoader.cpp +++ b/code/AssetLib/Ply/PlyLoader.cpp @@ -151,13 +151,13 @@ void PLYImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy const std::string mode = "rb"; std::unique_ptr fileStream(pIOHandler->Open(pFile, mode)); if (!fileStream.get()) { - throw DeadlyImportError("Failed to open file " + pFile + "."); + throw DeadlyImportError("Failed to open file ", pFile, "."); } // Get the file-size const size_t fileSize(fileStream->FileSize()); if (0 == fileSize) { - throw DeadlyImportError("File " + pFile + " is empty."); + throw DeadlyImportError("File ", pFile, " is empty."); } IOStreamBuffer streamedBuffer(1024 * 1024); diff --git a/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp b/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp index 52a2b7503..e9de3f5b3 100644 --- a/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp +++ b/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp @@ -180,7 +180,7 @@ const aiImporterDesc *Q3BSPFileImporter::GetInfo() const { void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene *scene, IOSystem *ioHandler) { ZipArchiveIOSystem Archive(ioHandler, rFile); if (!Archive.isOpen()) { - throw DeadlyImportError("Failed to open file " + rFile + "."); + throw DeadlyImportError("Failed to open file ", rFile, "."); } std::string archiveName(""), mapName(""); diff --git a/code/AssetLib/Q3D/Q3DLoader.cpp b/code/AssetLib/Q3D/Q3DLoader.cpp index 717b5702e..786f96e8a 100644 --- a/code/AssetLib/Q3D/Q3DLoader.cpp +++ b/code/AssetLib/Q3D/Q3DLoader.cpp @@ -110,13 +110,12 @@ void Q3DImporter::InternReadFile(const std::string &pFile, // The header is 22 bytes large if (stream.GetRemainingSize() < 22) - throw DeadlyImportError("File is either empty or corrupt: " + pFile); + throw DeadlyImportError("File is either empty or corrupt: ", pFile); // Check the file's signature if (ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Do", 8) && ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Ds", 8)) { - throw DeadlyImportError("Not a Quick3D file. Signature string is: " + - std::string((const char *)stream.GetPtr(), 8)); + throw DeadlyImportError("Not a Quick3D file. Signature string is: ", std::string((const char *)stream.GetPtr(), 8)); } // Print the file format version diff --git a/code/AssetLib/Raw/RawLoader.cpp b/code/AssetLib/Raw/RawLoader.cpp index 1363e29c1..f9812bfe5 100644 --- a/code/AssetLib/Raw/RawLoader.cpp +++ b/code/AssetLib/Raw/RawLoader.cpp @@ -101,7 +101,7 @@ void RAWImporter::InternReadFile(const std::string &pFile, // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open RAW file " + pFile + "."); + throw DeadlyImportError("Failed to open RAW file ", pFile, "."); } // allocate storage and copy the contents of the file to a memory buffer diff --git a/code/AssetLib/SIB/SIBImporter.cpp b/code/AssetLib/SIB/SIBImporter.cpp index 33beb0087..8edcd50fa 100644 --- a/code/AssetLib/SIB/SIBImporter.cpp +++ b/code/AssetLib/SIB/SIBImporter.cpp @@ -808,7 +808,7 @@ void SIBImporter::InternReadFile(const std::string &pFile, // We should have at least one chunk if (stream.GetRemainingSize() < 16) - throw DeadlyImportError("SIB file is either empty or corrupt: " + pFile); + throw DeadlyImportError("SIB file is either empty or corrupt: ", pFile); SIB sib; diff --git a/code/AssetLib/SMD/SMDLoader.cpp b/code/AssetLib/SMD/SMDLoader.cpp index 8a7625f93..ea6135fd2 100644 --- a/code/AssetLib/SMD/SMDLoader.cpp +++ b/code/AssetLib/SMD/SMDLoader.cpp @@ -695,7 +695,7 @@ void SMDImporter::ReadSmd(const std::string &pFile, IOSystem* pIOHandler) { // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open SMD/VTA file " + pFile + "."); + throw DeadlyImportError("Failed to open SMD/VTA file ", pFile, "."); } iFileSize = (unsigned int)file->FileSize(); diff --git a/code/AssetLib/STL/STLLoader.cpp b/code/AssetLib/STL/STLLoader.cpp index 2d710b084..592ec6b77 100644 --- a/code/AssetLib/STL/STLLoader.cpp +++ b/code/AssetLib/STL/STLLoader.cpp @@ -181,7 +181,7 @@ void STLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open STL file " + pFile + "."); + throw DeadlyImportError("Failed to open STL file ", pFile, "."); } mFileSize = (unsigned int)file->FileSize(); @@ -207,7 +207,7 @@ void STLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy } else if (IsAsciiSTL(mBuffer, mFileSize)) { LoadASCIIFile(mScene->mRootNode); } else { - throw DeadlyImportError("Failed to determine STL storage representation for " + pFile + "."); + throw DeadlyImportError("Failed to determine STL storage representation for ", pFile, "."); } // create a single default material, using a white diffuse color for consistency with diff --git a/code/AssetLib/Terragen/TerragenLoader.cpp b/code/AssetLib/Terragen/TerragenLoader.cpp index 0d0a140c3..3c57de4fb 100644 --- a/code/AssetLib/Terragen/TerragenLoader.cpp +++ b/code/AssetLib/Terragen/TerragenLoader.cpp @@ -121,7 +121,7 @@ void TerragenImporter::InternReadFile(const std::string &pFile, // Check whether we can read from the file if (file == nullptr) - throw DeadlyImportError("Failed to open TERRAGEN TERRAIN file " + pFile + "."); + throw DeadlyImportError("Failed to open TERRAGEN TERRAIN file ", pFile, "."); // Construct a stream reader to read all data in the correct endianness StreamReaderLE reader(file); diff --git a/code/AssetLib/X/XFileImporter.cpp b/code/AssetLib/X/XFileImporter.cpp index 6c57c9dd2..44c3b375d 100644 --- a/code/AssetLib/X/XFileImporter.cpp +++ b/code/AssetLib/X/XFileImporter.cpp @@ -114,7 +114,7 @@ void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, I // read file into memory std::unique_ptr file( pIOHandler->Open( pFile)); if ( file.get() == nullptr ) { - throw DeadlyImportError( "Failed to open file " + pFile + "." ); + throw DeadlyImportError( "Failed to open file ", pFile, "." ); } static const size_t MinSize = 16; diff --git a/code/AssetLib/X/XFileParser.cpp b/code/AssetLib/X/XFileParser.cpp index f0b751498..276d46b2e 100644 --- a/code/AssetLib/X/XFileParser.cpp +++ b/code/AssetLib/X/XFileParser.cpp @@ -82,6 +82,17 @@ static void dummy_free(void * /*opaque*/, void *address) { #endif // !! ASSIMP_BUILD_NO_COMPRESSED_X +// ------------------------------------------------------------------------------------------------ +// Throws an exception with a line number and the given text. +template +AI_WONT_RETURN void XFileParser::ThrowException(T&&... args) { + if (mIsBinaryFormat) { + throw DeadlyImportError(args...); + } else { + throw DeadlyImportError("Line ", mLineNumber, ": ", args...); + } +} + // ------------------------------------------------------------------------------------------------ // Constructor. Creates a data structure out of the XFile given in the memory block. XFileParser::XFileParser(const std::vector &pBuffer) : @@ -122,13 +133,13 @@ XFileParser::XFileParser(const std::vector &pBuffer) : mIsBinaryFormat = true; compressed = true; } else - ThrowException(format() << "Unsupported xfile format '" << mP[8] << mP[9] << mP[10] << mP[11] << "'"); + ThrowException("Unsupported xfile format '", mP[8], mP[9], mP[10], mP[11], "'"); // float size mBinaryFloatSize = (unsigned int)(mP[12] - 48) * 1000 + (unsigned int)(mP[13] - 48) * 100 + (unsigned int)(mP[14] - 48) * 10 + (unsigned int)(mP[15] - 48); if (mBinaryFloatSize != 32 && mBinaryFloatSize != 64) - ThrowException(format() << "Unknown float size " << mBinaryFloatSize << " specified in xfile header."); + ThrowException("Unknown float size ", mBinaryFloatSize, " specified in xfile header."); // The x format specifies size in bits, but we work in bytes mBinaryFloatSize /= 8; @@ -864,7 +875,7 @@ void XFileParser::ParseDataObjectAnimationKey(AnimBone *pAnimBone) { } default: - ThrowException(format() << "Unknown key type " << keyType << " in animation."); + ThrowException("Unknown key type ", keyType, " in animation."); break; } // end switch @@ -1355,16 +1366,6 @@ aiColor3D XFileParser::ReadRGB() { return color; } -// ------------------------------------------------------------------------------------------------ -// Throws an exception with a line number and the given text. -AI_WONT_RETURN void XFileParser::ThrowException(const std::string &pText) { - if (mIsBinaryFormat) { - throw DeadlyImportError(pText); - } else { - throw DeadlyImportError(format() << "Line " << mLineNumber << ": " << pText); - } -} - // ------------------------------------------------------------------------------------------------ // Filters the imported hierarchy for some degenerated cases that some exporters produce. void XFileParser::FilterHierarchy(XFile::Node *pNode) { diff --git a/code/AssetLib/X/XFileParser.h b/code/AssetLib/X/XFileParser.h index 41abe2286..bda904172 100644 --- a/code/AssetLib/X/XFileParser.h +++ b/code/AssetLib/X/XFileParser.h @@ -133,7 +133,8 @@ protected: aiColor4D ReadRGBA(); /** Throws an exception with a line number and the given text. */ - AI_WONT_RETURN void ThrowException( const std::string& pText) AI_WONT_RETURN_SUFFIX; + template + AI_WONT_RETURN void ThrowException(T&&... args) AI_WONT_RETURN_SUFFIX; /** * @brief Filters the imported hierarchy for some degenerated cases that some exporters produce. diff --git a/code/AssetLib/X3D/FIReader.cpp b/code/AssetLib/X3D/FIReader.cpp index c1b439bda..2bee9789e 100644 --- a/code/AssetLib/X3D/FIReader.cpp +++ b/code/AssetLib/X3D/FIReader.cpp @@ -997,18 +997,18 @@ private: if (index < 32) { FIDecoder *decoder = defaultDecoder[index]; if (!decoder) { - throw DeadlyImportError("Invalid encoding algorithm index " + to_string(index)); + throw DeadlyImportError("Invalid encoding algorithm index ", to_string(index)); } return decoder->decode(dataP, len); } else { if (index - 32 >= vocabulary.encodingAlgorithmTable.size()) { - throw DeadlyImportError("Invalid encoding algorithm index " + to_string(index)); + throw DeadlyImportError("Invalid encoding algorithm index ", to_string(index)); } std::string uri = vocabulary.encodingAlgorithmTable[index - 32]; auto it = decoderMap.find(uri); if (it == decoderMap.end()) { - throw DeadlyImportError("Unsupported encoding algorithm " + uri); + throw DeadlyImportError("Unsupported encoding algorithm ", uri); } else { return it->second->decode(dataP, len); @@ -1027,12 +1027,12 @@ private: alphabet = "0123456789-:TZ "; break; default: - throw DeadlyImportError("Invalid restricted alphabet index " + to_string(index)); + throw DeadlyImportError("Invalid restricted alphabet index ", to_string(index)); } } else { if (index - 16 >= vocabulary.restrictedAlphabetTable.size()) { - throw DeadlyImportError("Invalid restricted alphabet index " + to_string(index)); + throw DeadlyImportError("Invalid restricted alphabet index ", to_string(index)); } alphabet = vocabulary.restrictedAlphabetTable[index - 16]; } @@ -1040,7 +1040,7 @@ private: utf8::utf8to32(alphabet.begin(), alphabet.end(), back_inserter(alphabetUTF32)); std::string::size_type alphabetLength = alphabetUTF32.size(); if (alphabetLength < 2) { - throw DeadlyImportError("Invalid restricted alphabet length " + to_string(alphabetLength)); + throw DeadlyImportError("Invalid restricted alphabet length ", to_string(alphabetLength)); } std::string::size_type bitsPerCharacter = 1; while ((1ull << bitsPerCharacter) <= alphabetLength) { @@ -1442,7 +1442,7 @@ private: std::string uri = parseNonEmptyOctetString2(); auto it = vocabularyMap.find(uri); if (it == vocabularyMap.end()) { - throw DeadlyImportError("Unknown vocabulary " + uri); + throw DeadlyImportError("Unknown vocabulary ", uri); } const FIVocabulary *externalVocabulary = it->second; if (externalVocabulary->restrictedAlphabetTable) { diff --git a/code/AssetLib/X3D/X3DImporter.cpp b/code/AssetLib/X3D/X3DImporter.cpp index c9f9a6b6d..d521dcd9c 100644 --- a/code/AssetLib/X3D/X3DImporter.cpp +++ b/code/AssetLib/X3D/X3DImporter.cpp @@ -233,48 +233,48 @@ bool X3DImporter::FindNodeElement(const std::string& pID, const CX3DImporter_Nod void X3DImporter::Throw_ArgOutOfRange(const std::string& pArgument) { - throw DeadlyImportError("Argument value is out of range for: \"" + pArgument + "\"."); + throw DeadlyImportError("Argument value is out of range for: \"", pArgument, "\"."); } void X3DImporter::Throw_CloseNotFound(const std::string& pNode) { - throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt."); + throw DeadlyImportError("Close tag for node <", pNode, "> not found. Seems file is corrupt."); } void X3DImporter::Throw_ConvertFail_Str2ArrF(const std::string& pAttrValue) { - throw DeadlyImportError("In <" + std::string(mReader->getNodeName()) + "> failed to convert attribute value \"" + pAttrValue + + throw DeadlyImportError("In <", mReader->getNodeName(), "> failed to convert attribute value \"", pAttrValue, "\" from string to array of floats."); } void X3DImporter::Throw_DEF_And_USE() { - throw DeadlyImportError("\"DEF\" and \"USE\" can not be defined both in <" + std::string(mReader->getNodeName()) + ">."); + throw DeadlyImportError("\"DEF\" and \"USE\" can not be defined both in <", mReader->getNodeName(), ">."); } void X3DImporter::Throw_IncorrectAttr(const std::string& pAttrName) { - throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\"."); + throw DeadlyImportError("Node <", mReader->getNodeName(), "> has incorrect attribute \"", pAttrName, "\"."); } void X3DImporter::Throw_IncorrectAttrValue(const std::string& pAttrName) { - throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value."); + throw DeadlyImportError("Attribute \"", pAttrName, "\" in node <", mReader->getNodeName(), "> has incorrect value."); } void X3DImporter::Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription) { - throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription); + throw DeadlyImportError("\"", pNodeType, "\" node can be used only once in ", mReader->getNodeName(), ". Description: ", pDescription); } void X3DImporter::Throw_TagCountIncorrect(const std::string& pNode) { - throw DeadlyImportError("Count of open and close tags for node <" + pNode + "> are not equivalent. Seems file is corrupt."); + throw DeadlyImportError("Count of open and close tags for node <", pNode, "> are not equivalent. Seems file is corrupt."); } void X3DImporter::Throw_USE_NotFound(const std::string& pAttrValue) { - throw DeadlyImportError("Not found node with name \"" + pAttrValue + "\" in <" + std::string(mReader->getNodeName()) + ">."); + throw DeadlyImportError("Not found node with name \"", pAttrValue, "\" in <", mReader->getNodeName(), ">."); } /*********************************************************************************************************************************************/ @@ -283,7 +283,7 @@ void X3DImporter::Throw_USE_NotFound(const std::string& pAttrValue) void X3DImporter::XML_CheckNode_MustBeEmpty() { - if(!mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must be empty."); + if(!mReader->isEmptyElement()) throw DeadlyImportError("Node <", mReader->getNodeName(), "> must be empty."); } void X3DImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName) @@ -395,7 +395,7 @@ void X3DImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeNa casu_cres: - if(!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + "."); + if(!found) throw DeadlyImportError("Unknown node \"", nn, "\" in ", pParentNodeName, "."); if(close_found) LogInfo("Skipping node \"" + nn + "\" in " + pParentNodeName + "."); @@ -430,7 +430,7 @@ bool X3DImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) else if(val == "true") return true; else - throw DeadlyImportError("Bool attribute value can contain \"false\" or \"true\" not the \"" + val + "\""); + throw DeadlyImportError("Bool attribute value can contain \"false\" or \"true\" not the \"", val, "\""); } } @@ -971,8 +971,8 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list= norm_arr_copy.size()) - throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + to_string(tind[i]) + - ") is out of range. Normals count: " + to_string(norm_arr_copy.size()) + "."); + throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(", to_string(tind[i]), + ") is out of range. Normals count: ", to_string(norm_arr_copy.size()), "."); pMesh.mNormals[i] = norm_arr_copy[tind[i]]; } @@ -1268,7 +1268,7 @@ void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::vectorregisterVocabulary("urn:web3d:x3d:fi-vocabulary-3.2", &X3D_vocabulary_3_2); mReader->registerVocabulary("urn:web3d:x3d:fi-vocabulary-3.3", &X3D_vocabulary_3_3); @@ -1519,7 +1519,7 @@ void X3DImporter::ParseNode_Scene() auto GroupCounter_Increase = [](size_t& pCounter, const char* pGroupName) -> void { pCounter++; - if(pCounter == 0) throw DeadlyImportError("Group counter overflow. Too much groups with type: " + std::string(pGroupName) + "."); + if(pCounter == 0) throw DeadlyImportError("Group counter overflow. Too much groups with type: ", pGroupName, "."); }; auto GroupCounter_Decrease = [&](size_t& pCounter, const char* pGroupName) -> void diff --git a/code/AssetLib/X3D/X3DImporter_Postprocess.cpp b/code/AssetLib/X3D/X3DImporter_Postprocess.cpp index 993aff02c..a8bf332e5 100644 --- a/code/AssetLib/X3D/X3DImporter_Postprocess.cpp +++ b/code/AssetLib/X3D/X3DImporter_Postprocess.cpp @@ -178,7 +178,7 @@ void X3DImporter::Postprocess_BuildLight(const CX3DImporter_NodeElement& pNodeEl break; default: - throw DeadlyImportError("Postprocess_BuildLight. Unknown type of light: " + to_string(pNodeElement.Type) + "."); + throw DeadlyImportError("Postprocess_BuildLight. Unknown type of light: ", to_string(pNodeElement.Type), "."); } pSceneLightList.push_back(new_light); @@ -300,7 +300,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: " + to_string((*ch_it)->Type) + "."); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: ", to_string((*ch_it)->Type), "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. @@ -337,7 +337,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: " + to_string((*ch_it)->Type) + "."); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: ", to_string((*ch_it)->Type), "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. @@ -368,7 +368,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) {} // skip because already read when mesh created. else - throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: " + to_string((*ch_it)->Type) + "."); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: ", to_string((*ch_it)->Type), "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. @@ -458,7 +458,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) {} // skip because already read when mesh created. else - throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: " + to_string((*ch_it)->Type) + "."); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: ", to_string((*ch_it)->Type), "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. @@ -488,7 +488,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) {} // skip because already read when mesh created. else - throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: " + to_string((*ch_it)->Type) + "."); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: ", to_string((*ch_it)->Type), "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. @@ -525,7 +525,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: " + to_string((*ch_it)->Type) + "."); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleFanSet: ", to_string((*ch_it)->Type), "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. @@ -569,7 +569,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: " + to_string((*ch_it)->Type) + "."); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: ", to_string((*ch_it)->Type), "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. @@ -604,13 +604,13 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate) MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else - throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: " + to_string((*ch_it)->Type) + "."); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: ", to_string((*ch_it)->Type), "."); }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet) - throw DeadlyImportError("Postprocess_BuildMesh. Unknown mesh type: " + to_string(pNodeElement.Type) + "."); + throw DeadlyImportError("Postprocess_BuildMesh. Unknown mesh type: ", to_string(pNodeElement.Type), "."); } void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode, std::list& pSceneMeshList, @@ -672,7 +672,7 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle } else if(!PostprocessHelper_ElementIsMetadata((*it)->Type))// skip metadata { - throw DeadlyImportError("Postprocess_BuildNode. Unknown type: " + to_string((*it)->Type) + "."); + throw DeadlyImportError("Postprocess_BuildNode. Unknown type: ", to_string((*it)->Type), "."); } }// for(std::list::const_iterator it = chit_begin; it != chit_end; it++) diff --git a/code/AssetLib/XGL/XGLLoader.cpp b/code/AssetLib/XGL/XGLLoader.cpp index 938f2a321..7af5aab94 100644 --- a/code/AssetLib/XGL/XGLLoader.cpp +++ b/code/AssetLib/XGL/XGLLoader.cpp @@ -144,7 +144,7 @@ void XGLImporter::InternReadFile(const std::string &pFile, // check whether we can read from the file if (stream.get() == nullptr) { - throw DeadlyImportError("Failed to open XGL/ZGL file " + pFile + ""); + throw DeadlyImportError("Failed to open XGL/ZGL file ", pFile, ""); } // see if its compressed, if so uncompress it diff --git a/code/AssetLib/glTF/glTFAsset.inl b/code/AssetLib/glTF/glTFAsset.inl index 472be41cf..41bdc508a 100644 --- a/code/AssetLib/glTF/glTFAsset.inl +++ b/code/AssetLib/glTF/glTFAsset.inl @@ -235,15 +235,15 @@ Ref LazyDict::Get(const char *id) { // read it from the JSON object if (!mDict) { - throw DeadlyImportError("GLTF: Missing section \"" + std::string(mDictId) + "\""); + throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\""); } Value::MemberIterator obj = mDict->FindMember(id); if (obj == mDict->MemberEnd()) { - throw DeadlyImportError("GLTF: Missing object with id \"" + std::string(id) + "\" in \"" + mDictId + "\""); + throw DeadlyImportError("GLTF: Missing object with id \"", id, "\" in \"", mDictId, "\""); } if (!obj->value.IsObject()) { - throw DeadlyImportError("GLTF: Object with id \"" + std::string(id) + "\" is not a JSON object"); + throw DeadlyImportError("GLTF: Object with id \"", id, "\" is not a JSON object"); } // create an instance of the given type @@ -317,13 +317,13 @@ inline void Buffer::Read(Value &obj, Asset &r) { this->mData.reset(data, std::default_delete()); if (statedLength > 0 && this->byteLength != statedLength) { - throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) + - " bytes, but found " + to_string(dataURI.dataLength)); + throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", to_string(statedLength), + " bytes, but found ", to_string(dataURI.dataLength)); } } else { // assume raw data if (statedLength != dataURI.dataLength) { - throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) + - " bytes, but found " + to_string(dataURI.dataLength)); + throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", to_string(statedLength), + " bytes, but found ", to_string(dataURI.dataLength)); } this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete()); @@ -339,9 +339,9 @@ inline void Buffer::Read(Value &obj, Asset &r) { delete file; if (!ok) - throw DeadlyImportError("GLTF: error while reading referenced file \"" + std::string(uri) + "\""); + throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\""); } else { - throw DeadlyImportError("GLTF: could not open referenced file \"" + std::string(uri) + "\""); + throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\""); } } } @@ -373,7 +373,7 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod char val[val_size]; ai_snprintf(val, val_size, AI_SIZEFMT, pOffset); - throw DeadlyImportError(std::string("GLTF: incorrect offset value (") + val + ") for marking encoded region."); + throw DeadlyImportError("GLTF: incorrect offset value (", val, ") for marking encoded region."); } // Check length @@ -383,7 +383,7 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod char val[val_size]; ai_snprintf(val, val_size, AI_SIZEFMT "/" AI_SIZEFMT, pOffset, pEncodedData_Length); - throw DeadlyImportError(std::string("GLTF: encoded region with offset/length (") + val + ") is out of range."); + throw DeadlyImportError("GLTF: encoded region with offset/length (", val, ") is out of range."); } // Add new region @@ -403,7 +403,7 @@ inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) { } } - throw DeadlyImportError("GLTF: EncodedRegion with ID: \"" + pID + "\" not found."); + throw DeadlyImportError("GLTF: EncodedRegion with ID: \"", pID, "\" not found."); } inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) { @@ -851,7 +851,7 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) { /************** Read data from JSON-document **************/ #define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \ if (!ReadMember(*comp_data, pFieldName, pOut)) { \ - throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pFieldName + "\"."); \ + throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \ } const char *mode_str; @@ -880,7 +880,7 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) { else if (strcmp(mode_str, "ascii") == 0) ext_o3dgc->Binary = false; else - throw DeadlyImportError(std::string("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"") + mode_str + "\"."); + throw DeadlyImportError("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"", mode_str, "\"."); /************************ Decoding ************************/ Decode_O3DGC(*ext_o3dgc, pAsset_Root); @@ -888,7 +888,7 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) { } // if(it_memb->name.GetString() == "Open3DGC-compression") else { - throw DeadlyImportError(std::string("GLTF: Unknown mesh extension: \"") + it_memb->name.GetString() + "\"."); + throw DeadlyImportError("GLTF: Unknown mesh extension: \"", it_memb->name.GetString(), "\"."); } } // for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++) #endif @@ -923,24 +923,24 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG size_t size_coordindex = ifs.GetNCoordIndex() * 3; // See float attributes note. if (primitives[0].indices->count != size_coordindex) - throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + to_string(size_coordindex) + - ") not equal to uncompressed (" + to_string(primitives[0].indices->count) + ")."); + throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (", to_string(size_coordindex), + ") not equal to uncompressed (", to_string(primitives[0].indices->count), ")."); size_coordindex *= sizeof(IndicesType); // Coordinates size_t size_coord = ifs.GetNCoord(); // See float attributes note. if (primitives[0].attributes.position[0]->count != size_coord) - throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + to_string(size_coord) + - ") not equal to uncompressed (" + to_string(primitives[0].attributes.position[0]->count) + ")."); + throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (", to_string(size_coord), + ") not equal to uncompressed (", to_string(primitives[0].attributes.position[0]->count), ")."); size_coord *= 3 * sizeof(float); // Normals size_t size_normal = ifs.GetNNormal(); // See float attributes note. if (primitives[0].attributes.normal[0]->count != size_normal) - throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + to_string(size_normal) + - ") not equal to uncompressed (" + to_string(primitives[0].attributes.normal[0]->count) + ")."); + throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (", to_string(size_normal), + ") not equal to uncompressed (", to_string(primitives[0].attributes.normal[0]->count), ")."); size_normal *= 3 * sizeof(float); // Additional attributes. @@ -961,8 +961,8 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG // Check situation when encoded data contain texture coordinates but primitive not. if (idx_texcoord < primitives[0].attributes.texcoord.size()) { if (primitives[0].attributes.texcoord[idx]->count != tval) - throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (" + to_string(tval) + - ") not equal to uncompressed (" + to_string(primitives[0].attributes.texcoord[idx]->count) + ")."); + throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (", to_string(tval), + ") not equal to uncompressed (", to_string(primitives[0].attributes.texcoord[idx]->count), ")."); idx_texcoord++; } else { @@ -971,7 +971,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG break; default: - throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + to_string(ifs.GetFloatAttributeType(static_cast(idx)))); + throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", to_string(ifs.GetFloatAttributeType(static_cast(idx)))); } tval *= ifs.GetFloatAttributeDim(static_cast(idx)) * sizeof(o3dgc::Real); // After checking count of objects we can get size of array. @@ -990,7 +990,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG break; default: - throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + to_string(ifs.GetIntAttributeType(static_cast(idx)))); + throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", to_string(ifs.GetIntAttributeType(static_cast(idx)))); } tval *= ifs.GetIntAttributeDim(static_cast(idx)) * sizeof(long); // See float attributes note. @@ -1025,7 +1025,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG break; default: - throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + to_string(ifs.GetFloatAttributeType(static_cast(idx)))); + throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", to_string(ifs.GetFloatAttributeType(static_cast(idx)))); } } @@ -1039,7 +1039,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG // ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint))); default: - throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + to_string(ifs.GetIntAttributeType(static_cast(idx)))); + throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", to_string(ifs.GetIntAttributeType(static_cast(idx)))); } } @@ -1231,7 +1231,7 @@ inline void AssetMetadata::Read(Document &doc) { } if (version.empty() || version[0] != '1') { - throw DeadlyImportError("GLTF: Unsupported glTF version: " + version); + throw DeadlyImportError("GLTF: Unsupported glTF version: ", version); } } @@ -1309,7 +1309,7 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) { if (doc.HasParseError()) { char buffer[32]; ai_snprintf(buffer, 32, "%d", static_cast(doc.GetErrorOffset())); - throw DeadlyImportError(std::string("GLTF: JSON parse error, offset ") + buffer + ": " + GetParseError_En(doc.GetParseError())); + throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError())); } if (!doc.IsObject()) { diff --git a/code/AssetLib/glTF/glTFImporter.cpp b/code/AssetLib/glTF/glTFImporter.cpp index c106acf21..512a4334b 100644 --- a/code/AssetLib/glTF/glTFImporter.cpp +++ b/code/AssetLib/glTF/glTFImporter.cpp @@ -234,7 +234,7 @@ void glTFImporter::ImportMeshes(glTF::Asset &r) { buf->EncodedRegion_SetCurrent(mesh.id); } else { - throw DeadlyImportError("GLTF: Can not import mesh: unknown mesh extension (code: \"" + to_string(cur_ext->Type) + + throw DeadlyImportError("GLTF: Can not import mesh: unknown mesh extension (code: \"", to_string(cur_ext->Type), "\"), only Open3DGC is supported."); } } diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 67c066219..ead8ca1dd 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -194,7 +194,7 @@ inline unsigned int ComponentTypeSize(ComponentType t) { case ComponentType_UNSIGNED_BYTE: return 1; default: - throw DeadlyImportError("GLTF: Unsupported Component Type " + to_string(t)); + throw DeadlyImportError("GLTF: Unsupported Component Type ", to_string(t)); } } diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 2dfe2f41e..8ea621911 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -269,21 +269,21 @@ Ref LazyDict::Retrieve(unsigned int i) { // read it from the JSON object if (!mDict) { - throw DeadlyImportError("GLTF: Missing section \"" + std::string(mDictId) + "\""); + throw DeadlyImportError("GLTF: Missing section \"", mDictId, "\""); } if (!mDict->IsArray()) { - throw DeadlyImportError("GLTF: Field is not an array \"" + std::string(mDictId) + "\""); + throw DeadlyImportError("GLTF: Field is not an array \"", mDictId, "\""); } Value &obj = (*mDict)[i]; if (!obj.IsObject()) { - throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" is not a JSON object"); + throw DeadlyImportError("GLTF: Object at index \"", to_string(i), "\" is not a JSON object"); } if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) { - throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" has recursive reference to itself"); + throw DeadlyImportError("GLTF: Object at index \"", to_string(i), "\" has recursive reference to itself"); } mRecursiveReferenceCheck.insert(i); @@ -381,13 +381,13 @@ inline void Buffer::Read(Value &obj, Asset &r) { this->mData.reset(data, std::default_delete()); if (statedLength > 0 && this->byteLength != statedLength) { - throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) + - " bytes, but found " + to_string(dataURI.dataLength)); + throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", to_string(statedLength), + " bytes, but found ", to_string(dataURI.dataLength)); } } else { // assume raw data if (statedLength != dataURI.dataLength) { - throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) + - " bytes, but found " + to_string(dataURI.dataLength)); + throw DeadlyImportError("GLTF: buffer \"", id, "\", expected ", to_string(statedLength), + " bytes, but found ", to_string(dataURI.dataLength)); } this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete()); @@ -403,9 +403,9 @@ inline void Buffer::Read(Value &obj, Asset &r) { delete file; if (!ok) - throw DeadlyImportError("GLTF: error while reading referenced file \"" + std::string(uri) + "\""); + throw DeadlyImportError("GLTF: error while reading referenced file \"", uri, "\""); } else { - throw DeadlyImportError("GLTF: could not open referenced file \"" + std::string(uri) + "\""); + throw DeadlyImportError("GLTF: could not open referenced file \"", uri, "\""); } } } @@ -437,7 +437,7 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod char val[val_size]; ai_snprintf(val, val_size, AI_SIZEFMT, pOffset); - throw DeadlyImportError(std::string("GLTF: incorrect offset value (") + val + ") for marking encoded region."); + throw DeadlyImportError("GLTF: incorrect offset value (", val, ") for marking encoded region."); } // Check length @@ -447,7 +447,7 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod char val[val_size]; ai_snprintf(val, val_size, AI_SIZEFMT "/" AI_SIZEFMT, pOffset, pEncodedData_Length); - throw DeadlyImportError(std::string("GLTF: encoded region with offset/length (") + val + ") is out of range."); + throw DeadlyImportError("GLTF: encoded region with offset/length (", val, ") is out of range."); } // Add new region @@ -467,7 +467,7 @@ inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) { } } - throw DeadlyImportError("GLTF: EncodedRegion with ID: \"" + pID + "\" not found."); + throw DeadlyImportError("GLTF: EncodedRegion with ID: \"", pID, "\" not found."); } inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count) { @@ -1458,7 +1458,7 @@ inline void AssetMetadata::Read(Document &doc) { } if (version.empty() || version[0] != '2') { - throw DeadlyImportError("GLTF: Unsupported glTF version: " + version); + throw DeadlyImportError("GLTF: Unsupported glTF version: ", version); } } @@ -1570,7 +1570,7 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) { if (doc.HasParseError()) { char buffer[32]; ai_snprintf(buffer, 32, "%d", static_cast(doc.GetErrorOffset())); - throw DeadlyImportError(std::string("GLTF: JSON parse error, offset ") + buffer + ": " + GetParseError_En(doc.GetParseError())); + throw DeadlyImportError("GLTF: JSON parse error, offset ", buffer, ": ", GetParseError_En(doc.GetParseError())); } if (!doc.IsObject()) { diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 00c647ed2..972154b5f 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -668,7 +668,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { } if (actualNumFaces == 0) { - throw DeadlyImportError(std::string("Mesh \"") + aim->mName.C_Str() + "\" has no faces"); + throw DeadlyImportError("Mesh \"", aim->mName.C_Str(), "\" has no faces"); } aim->mNumFaces = actualNumFaces; ai_assert(CheckValidFacesIndices(faces, actualNumFaces, aim->mNumVertices)); diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index a727736df..eb3f5df67 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -200,6 +200,7 @@ SET( Common_SRCS Common/simd.cpp Common/material.cpp Common/AssertHandler.cpp + Common/Exceptional.cpp ) SOURCE_GROUP(Common FILES ${Common_SRCS}) diff --git a/code/Common/BaseImporter.cpp b/code/Common/BaseImporter.cpp index bcea076be..efeae03b1 100644 --- a/code/Common/BaseImporter.cpp +++ b/code/Common/BaseImporter.cpp @@ -130,10 +130,11 @@ aiScene *BaseImporter::ReadFile(Importer *pImp, const std::string &pFile, IOSyst // passes scale into ScaleProcess UpdateImporterScale(pImp); - } catch (const std::exception &err) { + } catch( const std::exception &err ) { // extract error description m_ErrorText = err.what(); - ASSIMP_LOG_ERROR(m_ErrorText); + ASSIMP_LOG_ERROR(err.what()); + m_Exception = std::current_exception(); return nullptr; } diff --git a/code/Common/Exceptional.cpp b/code/Common/Exceptional.cpp new file mode 100644 index 000000000..ae5257c19 --- /dev/null +++ b/code/Common/Exceptional.cpp @@ -0,0 +1,52 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file Exceptional.cpp + +Implementations of the exception classes. + +*/ + +#include +#include + +DeadlyErrorBase::DeadlyErrorBase(Assimp::Formatter::format f) : + runtime_error(std::string(f)){} diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index 6b3a50346..207b93fc7 100644 --- a/code/Common/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -140,6 +140,8 @@ void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::E #endif static void setupExporterArray(std::vector &exporters) { + (void)exporters; + #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER exporters.push_back(Exporter::ExportFormatEntry("collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada)); #endif diff --git a/code/Common/Importer.cpp b/code/Common/Importer.cpp index fc50336b4..38eb63f40 100644 --- a/code/Common/Importer.cpp +++ b/code/Common/Importer.cpp @@ -387,6 +387,7 @@ void Importer::FreeScene( ) { pimpl->mScene = nullptr; pimpl->mErrorString = ""; + pimpl->mException = std::exception_ptr(); ASSIMP_END_EXCEPTION_REGION(void); } @@ -399,6 +400,13 @@ const char* Importer::GetErrorString() const { return pimpl->mErrorString.c_str(); } +const std::exception_ptr& Importer::GetException() const { + ai_assert(nullptr != pimpl); + + // Must remain valid as long as ReadFile() or FreeFile() are not called + return pimpl->mException; +} + // ------------------------------------------------------------------------------------------------ // Enable extra-verbose mode void Importer::SetExtraVerbose(bool bDo) { @@ -426,6 +434,7 @@ aiScene* Importer::GetOrphanedScene() { pimpl->mScene = nullptr; pimpl->mErrorString = ""; // reset error string + pimpl->mException = std::exception_ptr(); ASSIMP_END_EXCEPTION_REGION(aiScene*); return s; @@ -502,7 +511,7 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, ReadFile(fbuff,pFlags); SetIOHandler(io); - ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString); + ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException); return pimpl->mScene; } @@ -709,6 +718,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) { // if failed, extract the error string else if( !pimpl->mScene) { pimpl->mErrorString = imp->GetErrorText(); + pimpl->mException = imp->GetException(); } // clear any data allocated by post-process steps @@ -733,7 +743,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) { #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS // either successful or failure - the pointer expresses it anyways - ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString); + ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException); return pimpl->mScene; } diff --git a/code/Common/Importer.h b/code/Common/Importer.h index eaf42e9c5..eb70bc38f 100644 --- a/code/Common/Importer.h +++ b/code/Common/Importer.h @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -97,9 +96,13 @@ public: /** The imported data, if ReadFile() was successful, nullptr otherwise. */ aiScene* mScene; - /** The error description, if there was one. */ + /** The error description, if there was one. In the case of an exception, + * mException will carry the full details. */ std::string mErrorString; + /** Any exception which occurred */ + std::exception_ptr mException; + /** List of integer properties */ IntPropertyMap mIntProperties; @@ -124,26 +127,26 @@ public: }; inline -ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT -: mIOHandler( nullptr ) -, mIsDefaultHandler( false ) -, mProgressHandler( nullptr ) -, mIsDefaultProgressHandler( false ) -, mImporter() -, mPostProcessingSteps() -, mScene( nullptr ) -, mErrorString() -, mIntProperties() -, mFloatProperties() -, mStringProperties() -, mMatrixProperties() -, bExtraVerbose( false ) -, mPPShared( nullptr ) { +ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT : + mIOHandler( nullptr ), + mIsDefaultHandler( false ), + mProgressHandler( nullptr ), + mIsDefaultProgressHandler( false ), + mImporter(), + mPostProcessingSteps(), + mScene( nullptr ), + mErrorString(), + mException(), + mIntProperties(), + mFloatProperties(), + mStringProperties(), + mMatrixProperties(), + bExtraVerbose( false ), + mPPShared( nullptr ) { // empty } //! @endcond - struct BatchData; // --------------------------------------------------------------------------- @@ -154,17 +157,13 @@ struct BatchData; * could, this has not yet been implemented at the moment). * * @note The class may not be used by more than one thread*/ -class ASSIMP_API BatchLoader -{ - // friend of Importer - +class ASSIMP_API BatchLoader { public: //! @cond never // ------------------------------------------------------------------- /** Wraps a full list of configuration properties for an importer. * Properties can be set using SetGenericProperty */ - struct PropertyMap - { + struct PropertyMap { ImporterPimpl::IntPropertyMap ints; ImporterPimpl::FloatPropertyMap floats; ImporterPimpl::StringPropertyMap strings; @@ -181,7 +180,6 @@ public: }; //! @endcond -public: // ------------------------------------------------------------------- /** Construct a batch loader from a given IO system to be used * to access external files diff --git a/code/PostProcessing/ValidateDataStructure.cpp b/code/PostProcessing/ValidateDataStructure.cpp index a288e397d..e7392d9e5 100644 --- a/code/PostProcessing/ValidateDataStructure.cpp +++ b/code/PostProcessing/ValidateDataStructure.cpp @@ -85,7 +85,7 @@ AI_WONT_RETURN void ValidateDSProcess::ReportError(const char *msg, ...) { va_end(args); - throw DeadlyImportError("Validation failed: " + std::string(szBuffer, iLen)); + throw DeadlyImportError("Validation failed: ", std::string(szBuffer, iLen)); } // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::ReportWarning(const char *msg, ...) { diff --git a/doc/dox.h b/doc/dox.h index 910e77eae..a4516dc7a 100644 --- a/doc/dox.h +++ b/doc/dox.h @@ -1626,7 +1626,7 @@ void xxxxImporter::InternReadFile( const std::string& pFile, // Check whether we can read from the file if( file.get() == NULL) { - throw DeadlyImportError( "Failed to open xxxx file " + pFile + "."); + throw DeadlyImportError( "Failed to open xxxx file ", pFile, "."); } // Your task: fill pScene diff --git a/include/assimp/BaseImporter.h b/include/assimp/BaseImporter.h index 06c337853..a8239be8d 100644 --- a/include/assimp/BaseImporter.h +++ b/include/assimp/BaseImporter.h @@ -143,6 +143,8 @@ public: // ------------------------------------------------------------------- /** Returns the error description of the last error that occurred. + * If the error is due to a std::exception, this will return the message. + * Exceptions can also be accessed with GetException(). * @return A description of the last error that occurred. An empty * string if there was no error. */ @@ -150,6 +152,16 @@ public: return m_ErrorText; } + // ------------------------------------------------------------------- + /** Returns the exception of the last exception that occurred. + * Note: Exceptions are not the only source of error details, so GetErrorText + * should be consulted too. + * @return The last exception that occurred. + */ + const std::exception_ptr& GetException() const { + return m_Exception; + } + // ------------------------------------------------------------------- /** Called prior to ReadFile(). * The function is a request to the importer to update its configuration @@ -410,9 +422,11 @@ private: /* Pushes state into importer for the importer scale */ virtual void UpdateImporterScale(Importer *pImp); - protected: +protected: /// Error description in case there was one. std::string m_ErrorText; + /// The exception, in case there was one. + std::exception_ptr m_Exception; /// Currently set progress handler. ProgressHandler *m_progress; }; diff --git a/include/assimp/Exceptional.h b/include/assimp/Exceptional.h index c10b2f982..6c184383d 100644 --- a/include/assimp/Exceptional.h +++ b/include/assimp/Exceptional.h @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #include +#include #include using std::runtime_error; @@ -55,26 +56,33 @@ using std::runtime_error; #pragma warning(disable : 4275) #endif +class ASSIMP_API DeadlyErrorBase : public runtime_error { +protected: + DeadlyErrorBase(Assimp::Formatter::format f); + + template + DeadlyErrorBase(Assimp::Formatter::format f, U&& u, T&&... args) : + DeadlyErrorBase(std::move(f << std::forward(u)), std::forward(args)...) {} +}; + // --------------------------------------------------------------------------- /** FOR IMPORTER PLUGINS ONLY: Simple exception class to be thrown if an * unrecoverable error occurs while importing. Loading APIs return * nullptr instead of a valid aiScene then. */ -class DeadlyImportError : public runtime_error { +class ASSIMP_API DeadlyImportError : public DeadlyErrorBase { public: /** Constructor with arguments */ - explicit DeadlyImportError(const std::string &errorText) : - runtime_error(errorText) { - // empty - } + template + explicit DeadlyImportError(T&&... args) : + DeadlyErrorBase(Assimp::Formatter::format(), std::forward(args)...) {} }; -class DeadlyExportError : public runtime_error { +class ASSIMP_API DeadlyExportError : public DeadlyErrorBase { public: /** Constructor with arguments */ - explicit DeadlyExportError(const std::string &errorText) : - runtime_error(errorText) { - // empty - } + template + explicit DeadlyExportError(T&&... args) : + DeadlyErrorBase(Assimp::Formatter::format(), std::forward(args)...) {} }; #ifdef _MSC_VER @@ -123,17 +131,19 @@ struct ExceptionSwallower { { \ try { -#define ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(type, ASSIMP_END_EXCEPTION_REGION_errorString) \ - } \ - catch (const DeadlyImportError &e) { \ - ASSIMP_END_EXCEPTION_REGION_errorString = e.what(); \ - return ExceptionSwallower()(); \ - } \ - catch (...) { \ - ASSIMP_END_EXCEPTION_REGION_errorString = "Unknown exception"; \ - return ExceptionSwallower()(); \ - } \ - } +#define ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(type, ASSIMP_END_EXCEPTION_REGION_errorString, ASSIMP_END_EXCEPTION_REGION_exception) \ + } \ + catch (const DeadlyImportError &e) { \ + ASSIMP_END_EXCEPTION_REGION_errorString = e.what(); \ + ASSIMP_END_EXCEPTION_REGION_exception = std::current_exception(); \ + return ExceptionSwallower()(); \ + } \ + catch (...) { \ + ASSIMP_END_EXCEPTION_REGION_errorString = "Unknown exception"; \ + ASSIMP_END_EXCEPTION_REGION_exception = std::current_exception(); \ + return ExceptionSwallower()(); \ + } \ +} #define ASSIMP_END_EXCEPTION_REGION(type) \ } \ diff --git a/include/assimp/Importer.hpp b/include/assimp/Importer.hpp index 80eae78b3..9078fbfe6 100644 --- a/include/assimp/Importer.hpp +++ b/include/assimp/Importer.hpp @@ -495,6 +495,15 @@ public: * following methods is called: #ReadFile(), #FreeScene(). */ const char *GetErrorString() const; + // ------------------------------------------------------------------- + /** Returns an exception if one occurred during import. + * + * @return The last exception which occurred. + * + * @note The returned value remains valid until one of the + * following methods is called: #ReadFile(), #FreeScene(). */ + const std::exception_ptr& GetException() const; + // ------------------------------------------------------------------- /** Returns the scene loaded by the last successful call to ReadFile() * diff --git a/include/assimp/LogAux.h b/include/assimp/LogAux.h index 330c5e93e..407820aac 100644 --- a/include/assimp/LogAux.h +++ b/include/assimp/LogAux.h @@ -61,9 +61,10 @@ template class LogFunctions { public: // ------------------------------------------------------------------------------------------------ - static void ThrowException(const std::string& msg) + template + static void ThrowException(T&&... args) { - throw DeadlyImportError(Prefix()+msg); + throw DeadlyImportError(Prefix(), args...); } // ------------------------------------------------------------------------------------------------ diff --git a/include/assimp/TinyFormatter.h b/include/assimp/TinyFormatter.h index 3c6ca66c6..0f2cf6362 100644 --- a/include/assimp/TinyFormatter.h +++ b/include/assimp/TinyFormatter.h @@ -88,6 +88,9 @@ public: underlying << sin; } + basic_formatter(basic_formatter&& other) + : underlying(std::move(other.underlying)) { + } // The problem described here: // https://sourceforge.net/tracker/?func=detail&atid=1067632&aid=3358562&group_id=226462 diff --git a/include/assimp/irrXMLWrapper.h b/include/assimp/irrXMLWrapper.h index 52c174791..ef2b336ac 100644 --- a/include/assimp/irrXMLWrapper.h +++ b/include/assimp/irrXMLWrapper.h @@ -64,7 +64,7 @@ namespace Assimp { * // open the file * std::unique_ptr file( pIOHandler->Open( pFile)); * if( file.get() == nullptr ) { - * throw DeadlyImportError( "Failed to open file " + pFile + "."); + * throw DeadlyImportError( "Failed to open file ", pFile, "."); * } * * // generate a XML reader for it diff --git a/test/unit/utImporter.cpp b/test/unit/utImporter.cpp index 0be0037df..5e84b2ae4 100644 --- a/test/unit/utImporter.cpp +++ b/test/unit/utImporter.cpp @@ -279,3 +279,105 @@ TEST_F(ImporterTest, SearchFileHeaderForTokenTest) { //DefaultIOSystem ioSystem; // BaseImporter::SearchFileHeaderForToken( &ioSystem, assetPath, Token, 2 ) } + + +namespace +{ + // Description for an importer which fails in specific ways. + aiImporterDesc s_failingImporterDescription = { + "Failing importer", + "assimp team", + "", + "", + 0, + 1, + 0, + 1, + 0, + "fail" + }; + + // This importer fails in specific ways. + class FailingImporter : public Assimp::BaseImporter { + public: + virtual ~FailingImporter() = default; + virtual bool CanRead( const std::string&, Assimp::IOSystem*, bool ) const override + { + return true; + } + + protected: + virtual const aiImporterDesc* GetInfo() const override { return &s_failingImporterDescription; } + + virtual void InternReadFile( const std::string& pFile, aiScene*, Assimp::IOSystem* ) override + { + if (pFile == "deadlyImportError.fail") + { + throw DeadlyImportError("Deadly import error test. Details: ", 42, " More Details: ", "Failure"); + } + else if (pFile == "stdException.fail") + { + throw std::runtime_error("std::exception test"); + } + else if (pFile == "unexpectedException.fail") + { + throw 5; + } + } + }; +} + +TEST_F(ImporterTest, deadlyImportError) +{ + pImp->RegisterLoader(new FailingImporter); + pImp->SetIOHandler(new TestIOSystem); + const aiScene* scene = pImp->ReadFile("deadlyImportError.fail", 0); + EXPECT_EQ(scene, nullptr); + EXPECT_STREQ(pImp->GetErrorString(), "Deadly import error test. Details: 42 More Details: Failure"); + EXPECT_NE(pImp->GetException(), std::exception_ptr()); +} + +TEST_F(ImporterTest, stdException) +{ + pImp->RegisterLoader(new FailingImporter); + pImp->SetIOHandler(new TestIOSystem); + const aiScene* scene = pImp->ReadFile("stdException.fail", 0); + EXPECT_EQ(scene, nullptr); + EXPECT_STREQ(pImp->GetErrorString(), "std::exception test"); + EXPECT_NE(pImp->GetException(), std::exception_ptr()); + try + { + std::rethrow_exception(pImp->GetException()); + } + catch(const std::exception& e) + { + EXPECT_STREQ(e.what(), "std::exception test"); + } + catch(...) + { + EXPECT_TRUE(false); + } +} + +TEST_F(ImporterTest, unexpectedException) +{ + pImp->RegisterLoader(new FailingImporter); + pImp->SetIOHandler(new TestIOSystem); + const aiScene* scene = pImp->ReadFile("unexpectedException.fail", 0); + + EXPECT_EQ(scene, nullptr); + EXPECT_STREQ(pImp->GetErrorString(), "Unknown exception"); + ASSERT_NE(pImp->GetException(), std::exception_ptr()); + try + { + std::rethrow_exception(pImp->GetException()); + } + catch(int x) + { + EXPECT_EQ(x, 5); + } + catch(...) + { + EXPECT_TRUE(false); + } +}