Build formatting into DeadlyImportError

pull/3375/head
Malcolm Tyrrell 2020-08-18 16:32:34 +01:00
parent 974252bd8f
commit 0ffcdf160e
20 changed files with 221 additions and 154 deletions

View File

@ -71,6 +71,13 @@ static const aiImporterDesc desc = {
"bvh" "bvh"
}; };
// ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception
template<typename... T>
AI_WONT_RETURN void BVHLoader::ThrowException(T&&... args) {
throw DeadlyImportError(mFileName, ":", mLine, " - ", args...);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
BVHLoader::BVHLoader() : BVHLoader::BVHLoader() :
@ -176,12 +183,12 @@ aiNode *BVHLoader::ReadNode() {
// first token is name // first token is name
std::string nodeName = GetNextToken(); std::string nodeName = GetNextToken();
if (nodeName.empty() || nodeName == "{") 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 // then an opening brace should follow
std::string openBrace = GetNextToken(); std::string openBrace = GetNextToken();
if (openBrace != "{") if (openBrace != "{")
ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\".");
// Create a node // Create a node
aiNode *node = new aiNode(nodeName); aiNode *node = new aiNode(nodeName);
@ -211,7 +218,7 @@ aiNode *BVHLoader::ReadNode() {
siteToken.clear(); siteToken.clear();
siteToken = GetNextToken(); siteToken = GetNextToken();
if (siteToken != "Site") 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); aiNode *child = ReadEndSite(nodeName);
child->mParent = node; child->mParent = node;
@ -221,7 +228,7 @@ aiNode *BVHLoader::ReadNode() {
break; break;
} else { } else {
// everything else is a parse error // 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 // check opening brace
std::string openBrace = GetNextToken(); std::string openBrace = GetNextToken();
if (openBrace != "{") if (openBrace != "{")
ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"."); ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\".");
// Create a node // Create a node
aiNode *node = new aiNode("EndSite_" + pParentName); aiNode *node = new aiNode("EndSite_" + pParentName);
@ -261,7 +268,7 @@ aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
break; break;
} else { } else {
// everything else is a parse error // 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") else if (channelToken == "Zrotation")
pNode.mChannels.push_back(Channel_RotationZ); pNode.mChannels.push_back(Channel_RotationZ);
else 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 // Read number of frames
std::string tokenFrames = GetNextToken(); std::string tokenFrames = GetNextToken();
if (tokenFrames != "Frames:") if (tokenFrames != "Frames:")
ThrowException(format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\"."); ThrowException("Expected frame count \"Frames:\", but found \"", tokenFrames, "\".");
float numFramesFloat = GetNextTokenAsFloat(); float numFramesFloat = GetNextTokenAsFloat();
mAnimNumFrames = (unsigned int)numFramesFloat; mAnimNumFrames = (unsigned int)numFramesFloat;
@ -326,7 +333,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
std::string tokenDuration1 = GetNextToken(); std::string tokenDuration1 = GetNextToken();
std::string tokenDuration2 = GetNextToken(); std::string tokenDuration2 = GetNextToken();
if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:") 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(); mAnimTickDuration = GetNextTokenAsFloat();
@ -393,17 +400,11 @@ float BVHLoader::GetNextTokenAsFloat() {
ctoken = fast_atoreal_move<float>(ctoken, result); ctoken = fast_atoreal_move<float>(ctoken, result);
if (ctoken != token.c_str() + token.length()) 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; 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 // Constructs an animation for the motion data and stores it in the given scene
void BVHLoader::CreateAnimation(aiScene *pScene) { void BVHLoader::CreateAnimation(aiScene *pScene) {

View File

@ -134,7 +134,8 @@ protected:
float GetNextTokenAsFloat(); float GetNextTokenAsFloat();
/** Aborts the file reading with an exception */ /** Aborts the file reading with an exception */
AI_WONT_RETURN void ThrowException(const std::string &pError) AI_WONT_RETURN_SUFFIX; template<typename... T>
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 */ /** Constructs an animation for the motion data and stores it in the given scene */
void CreateAnimation(aiScene *pScene); void CreateAnimation(aiScene *pScene);

View File

@ -149,7 +149,7 @@ bool isValidCustomDataType(const int cdtype) {
bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) { bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
if (!isValidCustomDataType(cdtype)) { 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]; const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];

View File

@ -130,9 +130,7 @@ void DNAParser::Parse() {
uint16_t n = stream.GetI2(); uint16_t n = stream.GetI2();
if (n >= types.size()) { if (n >= types.size()) {
throw DeadlyImportError((format(), throw DeadlyImportError("BlenderDNA: Invalid type index in structure name", n, " (there are only ", types.size(), " entries)");
"BlenderDNA: Invalid type index in structure name", n,
" (there are only ", types.size(), " entries)"));
} }
// maintain separate indexes // maintain separate indexes
@ -151,9 +149,7 @@ void DNAParser::Parse() {
uint16_t j = stream.GetI2(); uint16_t j = stream.GetI2();
if (j >= types.size()) { if (j >= types.size()) {
throw DeadlyImportError((format(), throw DeadlyImportError("BlenderDNA: Invalid type index in structure field ", j, " (there are only ", types.size(), " entries)");
"BlenderDNA: Invalid type index in structure field ", j,
" (there are only ", types.size(), " entries)"));
} }
s.fields.push_back(Field()); s.fields.push_back(Field());
Field &f = s.fields.back(); Field &f = s.fields.back();
@ -164,9 +160,7 @@ void DNAParser::Parse() {
j = stream.GetI2(); j = stream.GetI2();
if (j >= names.size()) { if (j >= names.size()) {
throw DeadlyImportError((format(), throw DeadlyImportError("BlenderDNA: Invalid name index in structure field ", j, " (there are only ", names.size(), " entries)");
"BlenderDNA: Invalid name index in structure field ", j,
" (there are only ", names.size(), " entries)"));
} }
f.name = names[j]; f.name = names[j];
@ -188,9 +182,7 @@ void DNAParser::Parse() {
if (*f.name.rbegin() == ']') { if (*f.name.rbegin() == ']') {
const std::string::size_type rb = f.name.find('['); const std::string::size_type rb = f.name.find('[');
if (rb == std::string::npos) { if (rb == std::string::npos) {
throw DeadlyImportError((format(), throw DeadlyImportError("BlenderDNA: Encountered invalid array declaration ", f.name);
"BlenderDNA: Encountered invalid array declaration ",
f.name));
} }
f.flags |= FieldFlag_Array; f.flags |= FieldFlag_Array;

View File

@ -83,9 +83,10 @@ class ObjectCache;
* ancestry. */ * ancestry. */
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
struct Error : DeadlyImportError { struct Error : DeadlyImportError {
Error(const std::string &s) : template<typename... T>
DeadlyImportError(s) { explicit Error(T&&... args)
// empty : DeadlyImportError(args...)
{
} }
}; };

View File

@ -57,9 +57,7 @@ const Field& Structure :: operator [] (const std::string& ss) const
{ {
std::map<std::string, size_t>::const_iterator it = indices.find(ss); std::map<std::string, size_t>::const_iterator it = indices.find(ss);
if (it == indices.end()) { if (it == indices.end()) {
throw Error((Formatter::format(), throw Error("BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`");
"BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`"
));
} }
return fields[(*it).second]; 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 const Field& Structure :: operator [] (const size_t i) const
{ {
if (i >= fields.size()) { if (i >= fields.size()) {
throw Error((Formatter::format(), throw Error("BlendDNA: There is no field with index `",i,"` in structure `",name,"`");
"BlendDNA: There is no field with index `",i,"` in structure `",name,"`"
));
} }
return fields[i]; return fields[i];
@ -109,9 +105,7 @@ void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatab
// is the input actually an array? // is the input actually an array?
if (!(f.flags & FieldFlag_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);
this->name,"` ought to be an array of size ",M
));
} }
db.reader->IncPtr(f.offset); 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? // is the input actually an array?
if (!(f.flags & FieldFlag_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 this->name,"` ought to be an array of size ",M,"*",N
)); );
} }
db.reader->IncPtr(f.offset); db.reader->IncPtr(f.offset);
@ -195,8 +189,8 @@ bool Structure :: ReadFieldPtr(TOUT<T>& out, const char* name, const FileDatabas
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) { if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(),"Field `",name,"` of structure `", throw Error("Field `",name,"` of structure `",
this->name,"` ought to be a pointer")); this->name,"` ought to be a pointer");
} }
db.reader->IncPtr(f->offset); db.reader->IncPtr(f->offset);
@ -241,8 +235,8 @@ bool Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
#ifdef _DEBUG #ifdef _DEBUG
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) { if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
throw Error((Formatter::format(),"Field `",name,"` of structure `", throw Error("Field `",name,"` of structure `",
this->name,"` ought to be a pointer AND an array")); this->name,"` ought to be a pointer AND an array");
} }
#endif // _DEBUG #endif // _DEBUG
@ -322,8 +316,8 @@ bool Structure::ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, con
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) { if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(), "Field `", name, "` of structure `", throw Error("Field `", name, "` of structure `",
this->name, "` ought to be a pointer")); this->name, "` ought to be a pointer");
} }
db.reader->IncPtr(f->offset); db.reader->IncPtr(f->offset);
@ -369,8 +363,8 @@ bool Structure::ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const
// sanity check, should never happen if the genblenddna script is right // sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) { if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(), "Field `", name, "` of structure `", throw Error("Field `", name, "` of structure `",
this->name, "` ought to be a pointer")); this->name, "` ought to be a pointer");
} }
db.reader->IncPtr(f->offset); db.reader->IncPtr(f->offset);
@ -428,9 +422,9 @@ bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const Fil
// and check if it matches the type which we expect. // and check if it matches the type which we expect.
const Structure& ss = db.dna[block->dna_index]; const Structure& ss = db.dna[block->dna_index];
if (ss != s) { 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" "` but seemingly it is a `",ss.name,"` instead"
)); );
} }
// try to retrieve the object from the cache // try to retrieve the object from the cache
@ -614,16 +608,14 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv
if (it == db.entries.end()) { if (it == db.entries.end()) {
// this is crucial, pointers may not be invalid. // this is crucial, pointers may not be invalid.
// this is either a corrupted file or an attempted attack. // this is either a corrupted file or an attempted attack.
throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x", throw DeadlyImportError("Failure resolving pointer 0x",
std::hex,ptrval.val,", no file block falls into this address range" std::hex,ptrval.val,", no file block falls into this address range");
));
} }
if (ptrval.val >= (*it).address.val + (*it).size) { 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", std::hex,ptrval.val,", nearest file block starting at 0x",
(*it).address.val," ends at 0x", (*it).address.val," ends at 0x",
(*it).address.val + (*it).size (*it).address.val + (*it).size);
));
} }
return &*it; return &*it;
} }
@ -676,7 +668,7 @@ template <typename T> inline void ConvertDispatcher(T& out, const Structure& in,
out = static_cast<T>(db.reader->GetF8()); out = static_cast<T>(db.reader->GetF8());
} }
else { 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<std::string, size_t>::const_iterator it = indices.find(ss); std::map<std::string, size_t>::const_iterator it = indices.find(ss);
if (it == indices.end()) { if (it == indices.end()) {
throw Error((Formatter::format(), throw Error("BlendDNA: Did not find a structure named `",ss,"`");
"BlendDNA: Did not find a structure named `",ss,"`"
));
} }
return structures[(*it).second]; 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 const Structure& DNA :: operator [] (const size_t i) const
{ {
if (i >= structures.size()) { if (i >= structures.size()) {
throw Error((Formatter::format(), throw Error("BlendDNA: There is no structure with index `",i,"`");
"BlendDNA: There is no structure with index `",i,"`"
));
} }
return structures[i]; return structures[i];

View File

@ -748,9 +748,8 @@ void BlenderImporter::BuildMaterials(ConversionData &conv_data) {
void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) { void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) {
ai_assert(dt); ai_assert(dt);
if (strcmp(dt->dna_type, check)) { if (strcmp(dt->dna_type, check)) {
ThrowException((format(), ThrowException("Expected object at ", std::hex, dt, " to be of type `", check,
"Expected object at ", std::hex, dt, " to be of type `", check, "`, but it claims to be a `", dt->dna_type, "`instead");
"`, but it claims to be a `", dt->dna_type, "`instead"));
} }
} }

View File

@ -1251,7 +1251,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
// time count and value count must match // time count and value count must match
if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount) 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) { if (e.mTimeAccessor->mCount > 0) {
// find bounding times // find bounding times

View File

@ -66,6 +66,13 @@ using namespace Assimp;
using namespace Assimp::Collada; using namespace Assimp::Collada;
using namespace Assimp::Formatter; using namespace Assimp::Formatter;
// ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception
template<typename... T>
AI_WONT_RETURN void ColladaParser::ThrowException(T&&... args) const {
throw DeadlyImportError("Collada: ", mFileName, " - ", args...);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) : ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
@ -853,7 +860,7 @@ void ColladaParser::ReadControllerJoints(Collada::Controller &pController) {
// local URLS always start with a '#'. We don't support global URLs // local URLS always start with a '#'. We don't support global URLs
if (attrSource[0] != '#') if (attrSource[0] != '#')
ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of <joints> data <input> element"); ThrowException("Unsupported URL format in \"", attrSource, "\" in source attribute of <joints> data <input> element");
attrSource++; attrSource++;
// parse source URL to corresponding source // parse source URL to corresponding source
@ -862,7 +869,7 @@ void ColladaParser::ReadControllerJoints(Collada::Controller &pController) {
else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0)
pController.mJointOffsetMatrixSource = attrSource; pController.mJointOffsetMatrixSource = attrSource;
else else
ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in <joints> data <input> element"); ThrowException("Unknown semantic \"", attrSemantic, "\" in <joints> data <input> element");
// skip inner data, if present // skip inner data, if present
if (!mReader->isEmptyElement()) 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 // local URLS always start with a '#'. We don't support global URLs
if (attrSource[0] != '#') if (attrSource[0] != '#')
ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of <vertex_weights> data <input> element"); ThrowException("Unsupported URL format in \"", attrSource, "\" in source attribute of <vertex_weights> data <input> element");
channel.mAccessor = attrSource + 1; channel.mAccessor = attrSource + 1;
// parse source URL to corresponding source // parse source URL to corresponding source
@ -913,7 +920,7 @@ void ColladaParser::ReadControllerWeights(Collada::Controller &pController) {
else if (strcmp(attrSemantic, "WEIGHT") == 0) else if (strcmp(attrSemantic, "WEIGHT") == 0)
pController.mWeightInputWeights = channel; pController.mWeightInputWeights = channel;
else else
ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in <vertex_weights> data <input> element"); ThrowException("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
// skip inner data, if present // skip inner data, if present
if (!mReader->isEmptyElement()) if (!mReader->isEmptyElement())
@ -1901,7 +1908,7 @@ void ColladaParser::ReadAccessor(const std::string &pID) {
int attrSource = GetAttribute("source"); int attrSource = GetAttribute("source");
const char *source = mReader->getAttributeValue(attrSource); const char *source = mReader->getAttributeValue(attrSource);
if (source[0] != '#') if (source[0] != '#')
ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of <accessor> element."); ThrowException("Unknown reference format in url \"", source, "\" in source attribute of <accessor> element.");
int attrCount = GetAttribute("count"); int attrCount = GetAttribute("count");
unsigned int count = (unsigned int)mReader->getAttributeValueAsInt(attrCount); unsigned int count = (unsigned int)mReader->getAttributeValueAsInt(attrCount);
int attrOffset = TestAttribute("offset"); int attrOffset = TestAttribute("offset");
@ -1968,7 +1975,7 @@ void ColladaParser::ReadAccessor(const std::string &pID) {
else if (name == "V") else if (name == "V")
acc.mSubOffset[1] = acc.mParams.size(); acc.mSubOffset[1] = acc.mParams.size();
//else //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 // read data type
@ -1989,7 +1996,7 @@ void ColladaParser::ReadAccessor(const std::string &pID) {
// skip remaining stuff of this element, if any // skip remaining stuff of this element, if any
SkipElement(); SkipElement();
} else { } else {
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <accessor>"); ThrowException("Unexpected sub element <", mReader->getNodeName(), "> in tag <accessor>");
} }
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (strcmp(mReader->getNodeName(), "accessor") != 0) if (strcmp(mReader->getNodeName(), "accessor") != 0)
@ -2012,7 +2019,7 @@ void ColladaParser::ReadVertexData(Mesh &pMesh) {
if (IsElement("input")) { if (IsElement("input")) {
ReadInputChannel(pMesh.mPerVertexData); ReadInputChannel(pMesh.mPerVertexData);
} else { } else {
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <vertices>"); ThrowException("Unexpected sub element <", mReader->getNodeName(), "> in tag <vertices>");
} }
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (strcmp(mReader->getNodeName(), "vertices") != 0) if (strcmp(mReader->getNodeName(), "vertices") != 0)
@ -2096,11 +2103,11 @@ void ColladaParser::ReadIndexData(Mesh &pMesh) {
} else if (IsElement("ph")) { } else if (IsElement("ph")) {
SkipElement("ph"); SkipElement("ph");
} else { } 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) { } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (mReader->getNodeName() != elementName) if (mReader->getNodeName() != elementName)
ThrowException(format() << "Expected end of <" << elementName << "> element."); ThrowException("Expected end of <", elementName, "> element.");
break; break;
} }
@ -2132,7 +2139,7 @@ void ColladaParser::ReadInputChannel(std::vector<InputChannel> &poChannels) {
int attrSource = GetAttribute("source"); int attrSource = GetAttribute("source");
const char *source = mReader->getAttributeValue(attrSource); const char *source = mReader->getAttributeValue(attrSource);
if (source[0] != '#') if (source[0] != '#')
ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of <input> element."); ThrowException("Unknown reference format in url \"", source, "\" in source attribute of <input> element.");
channel.mAccessor = source + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only channel.mAccessor = source + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only
// read index offset, if per-index <input> // read index offset, if per-index <input>
@ -2146,7 +2153,7 @@ void ColladaParser::ReadInputChannel(std::vector<InputChannel> &poChannels) {
if (attrSet > -1) { if (attrSet > -1) {
attrSet = mReader->getAttributeValueAsInt(attrSet); attrSet = mReader->getAttributeValueAsInt(attrSet);
if (attrSet < 0) if (attrSet < 0)
ThrowException(format() << "Invalid index \"" << (attrSet) << "\" in set attribute of <input> element"); ThrowException("Invalid index \"", (attrSet), "\" in set attribute of <input> element");
channel.mIndex = attrSet; channel.mIndex = attrSet;
} }
@ -2369,7 +2376,7 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, siz
const Accessor &acc = *pInput.mResolved; const Accessor &acc = *pInput.mResolved;
if (pLocalIndex >= acc.mCount) 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 // 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; 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, ...) { void ColladaParser::ReportWarning(const char *msg, ...) {
ai_assert(nullptr != msg); ai_assert(nullptr != msg);
@ -2833,17 +2834,17 @@ void ColladaParser::SkipElement(const char *pElement) {
void ColladaParser::TestOpening(const char *pName) { void ColladaParser::TestOpening(const char *pName) {
// read element start // read element start
if (!mReader->read()) { 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 // whitespace in front is ok, just read again if found
if (mReader->getNodeType() == irr::io::EXN_TEXT) { if (mReader->getNodeType() == irr::io::EXN_TEXT) {
if (!mReader->read()) { 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) { 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 not, read some more
if (!mReader->read()) { 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 // whitespace in front is ok, just read again if found
if (mReader->getNodeType() == irr::io::EXN_TEXT) { if (mReader->getNodeType() == irr::io::EXN_TEXT) {
if (!mReader->read()) { 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 // 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) { 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 ColladaParser::GetAttribute(const char *pAttr) const {
int index = TestAttribute(pAttr); int index = TestAttribute(pAttr);
if (index == -1) { 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 // attribute not found -> throw an exception

View File

@ -242,7 +242,9 @@ protected:
protected: protected:
/** Aborts the file reading with an exception */ /** Aborts the file reading with an exception */
AI_WONT_RETURN void ThrowException(const std::string &pError) const AI_WONT_RETURN_SUFFIX; template<typename... T>
AI_WONT_RETURN void ThrowException(T&&... args) const AI_WONT_RETURN_SUFFIX;
void ReportWarning(const char *msg, ...); void ReportWarning(const char *msg, ...);
/** Skips all data until the end node of the current element */ /** Skips all data until the end node of the current element */
@ -383,7 +385,7 @@ template <typename Type>
const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const { const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const {
typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL); typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
if (it == pLibrary.end()) if (it == pLibrary.end())
ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\"."); ThrowException("Unable to resolve library reference \"", pURL, "\".");
return it->second; return it->second;
} }

View File

@ -187,8 +187,8 @@ Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream) {
/// @todo Check what we can actually support. /// @todo Check what we can actually support.
std::string version = serializer.ReadLine(); std::string version = serializer.ReadLine();
if (version != MESH_VERSION_1_8) { 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." 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); " Supported versions: ", MESH_VERSION_1_8);
} }
Mesh *mesh = new Mesh(); Mesh *mesh = new Mesh();
@ -471,7 +471,7 @@ void OgreBinarySerializer::ReadSubMeshNames(Mesh *mesh) {
uint16_t submeshIndex = Read<uint16_t>(); uint16_t submeshIndex = Read<uint16_t>();
SubMesh *submesh = mesh->GetSubMesh(submeshIndex); SubMesh *submesh = mesh->GetSubMesh(submeshIndex);
if (!submesh) { 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(); submesh->name = ReadLine();
@ -803,8 +803,8 @@ void OgreBinarySerializer::ReadSkeleton(Skeleton *skeleton) {
// This deserialization supports both versions of the skeleton spec // This deserialization supports both versions of the skeleton spec
std::string version = ReadLine(); std::string version = ReadLine();
if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1) { if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1) {
throw DeadlyExportError(Formatter::format() << "Skeleton version " << version << " not supported by this importer." throw DeadlyExportError("Skeleton version ", version, " not supported by this importer.",
<< " Supported versions: " << SKELETON_VERSION_1_8 << " and " << SKELETON_VERSION_1_1); " Supported versions: ", SKELETON_VERSION_1_8, " and ", SKELETON_VERSION_1_1);
} }
ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton"); 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 // Bone indexes need to start from 0 and be contiguous
if (bone->id != skeleton->bones.size()) { 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); ASSIMP_LOG_VERBOSE_DEBUG_F(" ", bone->id, " ", bone->name);
@ -889,7 +889,7 @@ void OgreBinarySerializer::ReadBoneParent(Skeleton *skeleton) {
if (child && parent) if (child && parent)
parent->AddChild(child); parent->AddChild(child);
else 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) { void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton) {
@ -926,7 +926,7 @@ void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton * /*skeleton*/, A
uint16_t boneId = Read<uint16_t>(); uint16_t boneId = Read<uint16_t>();
Bone *bone = dest->parentSkeleton->BoneById(boneId); Bone *bone = dest->parentSkeleton->BoneById(boneId);
if (!bone) { 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; VertexAnimationTrack track;

View File

@ -476,7 +476,7 @@ void SubMesh::Reset(){
aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent) { aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent) {
if (operationType != OT_TRIANGLE_LIST) { 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(); aiMesh *dest = new aiMesh();
@ -944,7 +944,7 @@ void Bone::AddChild(Bone *bone) {
if (!bone) if (!bone)
return; return;
if (bone->IsParented()) 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->parent = this;
bone->parentId = id; bone->parentId = id;
@ -963,7 +963,7 @@ void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton) {
for (auto boneId : children) { for (auto boneId : children) {
Bone *child = skeleton->BoneById(boneId); Bone *child = skeleton->BoneById(boneId);
if (!child) { 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); 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) { for (size_t i = 0, len = children.size(); i < len; ++i) {
Bone *child = skeleton->BoneById(children[i]); Bone *child = skeleton->BoneById(children[i]);
if (!child) { 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); node->mChildren[i] = child->ConvertToAssimpNode(skeleton, node);
} }
@ -1022,7 +1022,7 @@ aiNodeAnim *VertexAnimationTrack::ConvertToAssimpAnimationNode(Skeleton *skeleto
Bone *bone = skeleton->BoneByName(boneName); Bone *bone = skeleton->BoneByName(boneName);
if (!bone) { 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 // Keyframes

View File

@ -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 = "") AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error) { AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error) {
if (!error.empty()) { if (!error.empty()) {
throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'"); throw DeadlyImportError(error, " in node '", std::string(reader->getNodeName()), "' and attribute '", name, "'");
} else { } else {
throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'"); throw DeadlyImportError("Attribute '", name, "' does not exist in node '", std::string(reader->getNodeName()), "'");
} }
} }
@ -265,7 +265,7 @@ MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) {
void OgreXmlSerializer::ReadMesh(MeshXml *mesh) { void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
if (NextNode() != nnMesh) { if (NextNode() != nnMesh) {
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>"); throw DeadlyImportError("Root node is <", m_currentNodeName, "> expecting <mesh>");
} }
ASSIMP_LOG_VERBOSE_DEBUG("Reading Mesh"); ASSIMP_LOG_VERBOSE_DEBUG("Reading Mesh");
@ -430,18 +430,18 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) {
// Sanity checks // Sanity checks
if (dest->positions.size() != dest->count) { 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) { 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) { 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) { for (unsigned int i = 0; i < dest->uvs.size(); ++i) {
if (dest->uvs[i].size() != dest->count) { if (dest->uvs[i].size() != dest->count) {
throw DeadlyImportError(Formatter::format() << "Read only " << dest->uvs[i].size() throw DeadlyImportError("Read only ", dest->uvs[i].size(),
<< " uvs for uv index " << i << " when should have read " << dest->count); " 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) { if (submesh->indexData->faces.size() == submesh->indexData->faceCount) {
ASSIMP_LOG_VERBOSE_DEBUG_F(" - Faces ", submesh->indexData->faceCount); ASSIMP_LOG_VERBOSE_DEBUG_F(" - Faces ", submesh->indexData->faceCount);
} else { } 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) { } else if (m_currentNodeName == nnGeometry) {
if (submesh->usesSharedVertexData) { if (submesh->usesSharedVertexData) {
@ -632,20 +632,20 @@ XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const s
std::unique_ptr<IOStream> file(pIOHandler->Open(filename)); std::unique_ptr<IOStream> file(pIOHandler->Open(filename));
if (!file.get()) { if (!file.get()) {
throw DeadlyImportError("Failed to open skeleton file " + filename); throw DeadlyImportError("Failed to open skeleton file ", filename);
} }
std::unique_ptr<CIrrXML_IOStreamReader> stream(new CIrrXML_IOStreamReader(file.get())); std::unique_ptr<CIrrXML_IOStreamReader> stream(new CIrrXML_IOStreamReader(file.get()));
XmlReaderPtr reader = XmlReaderPtr(irr::io::createIrrXMLReader(stream.get())); XmlReaderPtr reader = XmlReaderPtr(irr::io::createIrrXMLReader(stream.get()));
if (!reader.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; return reader;
} }
void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) { void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) {
if (NextNode() != nnSkeleton) { if (NextNode() != nnSkeleton) {
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <skeleton>"); throw DeadlyImportError("Root node is <", m_currentNodeName, "> expecting <skeleton>");
} }
ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton"); ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton");
@ -687,7 +687,7 @@ void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) {
anim->length = ReadAttribute<float>("length"); anim->length = ReadAttribute<float>("length");
if (NextNode() != nnTracks) { if (NextNode() != nnTracks) {
throw DeadlyImportError(Formatter::format() << "No <tracks> found in <animation> " << anim->name); throw DeadlyImportError("No <tracks> found in <animation> ", anim->name);
} }
ReadAnimationTracks(anim); ReadAnimationTracks(anim);
@ -705,7 +705,7 @@ void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) {
track.boneName = ReadAttribute<std::string>("bone"); track.boneName = ReadAttribute<std::string>("bone");
if (NextNode() != nnKeyFrames) { if (NextNode() != nnKeyFrames) {
throw DeadlyImportError(Formatter::format() << "No <keyframes> found in <track> " << dest->name); throw DeadlyImportError("No <keyframes> found in <track> ", dest->name);
} }
ReadAnimationKeyFrames(dest, &track); ReadAnimationKeyFrames(dest, &track);
@ -732,7 +732,7 @@ void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationT
float angle = ReadAttribute<float>("angle"); float angle = ReadAttribute<float>("angle");
if (NextNode() != nnAxis) { 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; aiVector3D axis;
@ -774,7 +774,7 @@ void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) {
if (bone && parent) if (bone && parent)
parent->AddChild(bone); parent->AddChild(bone);
else 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. // Calculate bone matrices for root bones. Recursively calculates their children.
@ -813,7 +813,7 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton) {
float angle = ReadAttribute<float>("angle"); float angle = ReadAttribute<float>("angle");
if (NextNode() != nnAxis) { 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; aiVector3D axis;
@ -854,7 +854,7 @@ void OgreXmlSerializer::ReadBones(Skeleton *skeleton) {
ASSIMP_LOG_VERBOSE_DEBUG_F(" ", b->id, " ", b->name); ASSIMP_LOG_VERBOSE_DEBUG_F(" ", b->id, " ", b->name);
if (b->id != static_cast<uint16_t>(i)) { if (b->id != static_cast<uint16_t>(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);
} }
} }
} }

View File

@ -82,6 +82,17 @@ static void dummy_free(void * /*opaque*/, void *address) {
#endif // !! ASSIMP_BUILD_NO_COMPRESSED_X #endif // !! ASSIMP_BUILD_NO_COMPRESSED_X
// ------------------------------------------------------------------------------------------------
// Throws an exception with a line number and the given text.
template<typename... T>
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. // Constructor. Creates a data structure out of the XFile given in the memory block.
XFileParser::XFileParser(const std::vector<char> &pBuffer) : XFileParser::XFileParser(const std::vector<char> &pBuffer) :
@ -122,13 +133,13 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
mIsBinaryFormat = true; mIsBinaryFormat = true;
compressed = true; compressed = true;
} else } 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 // 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); 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) 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 // The x format specifies size in bits, but we work in bytes
mBinaryFloatSize /= 8; mBinaryFloatSize /= 8;
@ -864,7 +875,7 @@ void XFileParser::ParseDataObjectAnimationKey(AnimBone *pAnimBone) {
} }
default: default:
ThrowException(format() << "Unknown key type " << keyType << " in animation."); ThrowException("Unknown key type ", keyType, " in animation.");
break; break;
} // end switch } // end switch
@ -1355,16 +1366,6 @@ aiColor3D XFileParser::ReadRGB() {
return color; 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. // Filters the imported hierarchy for some degenerated cases that some exporters produce.
void XFileParser::FilterHierarchy(XFile::Node *pNode) { void XFileParser::FilterHierarchy(XFile::Node *pNode) {

View File

@ -133,7 +133,8 @@ protected:
aiColor4D ReadRGBA(); aiColor4D ReadRGBA();
/** Throws an exception with a line number and the given text. */ /** 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<typename... T>
AI_WONT_RETURN void ThrowException(T&&... args) AI_WONT_RETURN_SUFFIX;
/** /**
* @brief Filters the imported hierarchy for some degenerated cases that some exporters produce. * @brief Filters the imported hierarchy for some degenerated cases that some exporters produce.

View File

@ -200,6 +200,7 @@ SET( Common_SRCS
Common/simd.cpp Common/simd.cpp
Common/material.cpp Common/material.cpp
Common/AssertHandler.cpp Common/AssertHandler.cpp
Common/Exceptional.cpp
) )
SOURCE_GROUP(Common FILES ${Common_SRCS}) SOURCE_GROUP(Common FILES ${Common_SRCS})

View File

@ -0,0 +1,58 @@
/*
---------------------------------------------------------------------------
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 <assimp/Exceptional.h>
#include <assimp/TinyFormatter.h>
DeadlyErrorBase::DeadlyErrorBase(const std::string& errorText)
: runtime_error(errorText)
{}
DeadlyErrorBase::DeadlyErrorBase(Assimp::Formatter::format f)
: DeadlyErrorBase(std::string(f))
{
}

View File

@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif #endif
#include <assimp/DefaultIOStream.h> #include <assimp/DefaultIOStream.h>
#include <assimp/TinyFormatter.h>
#include <stdexcept> #include <stdexcept>
using std::runtime_error; using std::runtime_error;
@ -55,25 +56,41 @@ using std::runtime_error;
#pragma warning(disable : 4275) #pragma warning(disable : 4275)
#endif #endif
class ASSIMP_API DeadlyErrorBase : public runtime_error {
protected:
/** Constructor with arguments */
explicit DeadlyErrorBase(const std::string& errorText);
explicit DeadlyErrorBase(Assimp::Formatter::format f);
template<typename... T, typename U>
explicit DeadlyErrorBase(Assimp::Formatter::format f, U&& u, T&&... args)
: DeadlyErrorBase(std::move(f << u), args...)
{
}
};
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** FOR IMPORTER PLUGINS ONLY: Simple exception class to be thrown if an /** FOR IMPORTER PLUGINS ONLY: Simple exception class to be thrown if an
* unrecoverable error occurs while importing. Loading APIs return * unrecoverable error occurs while importing. Loading APIs return
* nullptr instead of a valid aiScene then. */ * nullptr instead of a valid aiScene then. */
class DeadlyImportError : public runtime_error { class ASSIMP_API DeadlyImportError : public DeadlyErrorBase {
public: public:
/** Constructor with arguments */ /** Constructor with arguments */
explicit DeadlyImportError(const std::string &errorText) : template<typename... T>
runtime_error(errorText) { explicit DeadlyImportError(T&&... args)
// empty : DeadlyErrorBase(Assimp::Formatter::format(), args...)
{
} }
}; };
class DeadlyExportError : public runtime_error { class ASSIMP_API DeadlyExportError : public DeadlyErrorBase {
public: public:
/** Constructor with arguments */ /** Constructor with arguments */
explicit DeadlyExportError(const std::string &errorText) : template<typename... T>
runtime_error(errorText) { explicit DeadlyExportError(T&&... args)
// empty : DeadlyErrorBase(Assimp::Formatter::format(), args...)
{
} }
}; };

View File

@ -61,9 +61,10 @@ template<class TDeriving>
class LogFunctions { class LogFunctions {
public: public:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static void ThrowException(const std::string& msg) template<typename... T>
static void ThrowException(T&&... args)
{ {
throw DeadlyImportError(Prefix()+msg); throw DeadlyImportError(Prefix(), args...);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -88,6 +88,9 @@ public:
underlying << sin; underlying << sin;
} }
basic_formatter(basic_formatter&& other)
: underlying(std::move(other.underlying)) {
}
// The problem described here: // The problem described here:
// https://sourceforge.net/tracker/?func=detail&atid=1067632&aid=3358562&group_id=226462 // https://sourceforge.net/tracker/?func=detail&atid=1067632&aid=3358562&group_id=226462