closes https://github.com/assimp/assimp/issues/3178: throw exception in case of invalid export stream.

pull/3197/head
Kim Kulling 2020-05-02 21:06:55 +02:00
parent f8e6512a63
commit 3329e76263
1 changed files with 81 additions and 93 deletions

View File

@ -9,16 +9,16 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information
#ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER #ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
#include <assimp/Importer.hpp> #include <assimp/scene.h>
#include <assimp/Exporter.hpp> #include <assimp/Exporter.hpp>
#include <assimp/IOStream.hpp> #include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/scene.h> #include <assimp/Importer.hpp>
#include <sstream>
#include <limits>
#include <cassert> #include <cassert>
#include <limits>
#include <memory> #include <memory>
#include <sstream>
#define CURRENT_FORMAT_VERSION 100 #define CURRENT_FORMAT_VERSION 100
@ -28,11 +28,11 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information
#include "mesh_splitter.h" #include "mesh_splitter.h"
extern "C" { extern "C" {
#include "cencode.h" #include "cencode.h"
} }
namespace Assimp { namespace Assimp {
void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*); void ExportAssimp2Json(const char *, Assimp::IOSystem *, const aiScene *, const Assimp::ExportProperties *);
// small utility class to simplify serializing the aiScene to Json // small utility class to simplify serializing the aiScene to Json
class JSONWriter { class JSONWriter {
@ -42,10 +42,8 @@ public:
Flag_WriteSpecialFloats = 0x2, Flag_WriteSpecialFloats = 0x2,
}; };
JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u) JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
: out(out) out(out), first(), flags(flags) {
, first()
, flags(flags) {
// make sure that all formatting happens using the standard, C locale and not the user's current locale // make sure that all formatting happens using the standard, C locale and not the user's current locale
buff.imbue(std::locale("C")); buff.imbue(std::locale("C"));
} }
@ -68,30 +66,30 @@ public:
indent.erase(indent.end() - 1); indent.erase(indent.end() - 1);
} }
void Key(const std::string& name) { void Key(const std::string &name) {
AddIndentation(); AddIndentation();
Delimit(); Delimit();
buff << '\"' + name + "\": "; buff << '\"' + name + "\": ";
} }
template<typename Literal> template <typename Literal>
void Element(const Literal& name) { void Element(const Literal &name) {
AddIndentation(); AddIndentation();
Delimit(); Delimit();
LiteralToString(buff, name) << '\n'; LiteralToString(buff, name) << '\n';
} }
template<typename Literal> template <typename Literal>
void SimpleValue(const Literal& s) { void SimpleValue(const Literal &s) {
LiteralToString(buff, s) << '\n'; LiteralToString(buff, s) << '\n';
} }
void SimpleValue(const void* buffer, size_t len) { void SimpleValue(const void *buffer, size_t len) {
base64_encodestate s; base64_encodestate s;
base64_init_encodestate(&s); base64_init_encodestate(&s);
char* const cur_out = new char[std::max(len * 2, static_cast<size_t>(16u))]; char *const cur_out = new char[std::max(len * 2, static_cast<size_t>(16u))];
const int n = base64_encode_block(reinterpret_cast<const char *>(buffer), static_cast<int>(len), cur_out, &s); const int n = base64_encode_block(reinterpret_cast<const char *>(buffer), static_cast<int>(len), cur_out, &s);
cur_out[n + base64_encode_blockend(cur_out + n, &s)] = '\0'; cur_out[n + base64_encode_blockend(cur_out + n, &s)] = '\0';
@ -156,21 +154,20 @@ public:
void Delimit() { void Delimit() {
if (!first) { if (!first) {
buff << ','; buff << ',';
} } else {
else {
buff << ' '; buff << ' ';
first = false; first = false;
} }
} }
private: private:
template<typename Literal> template <typename Literal>
std::stringstream& LiteralToString(std::stringstream& stream, const Literal& s) { std::stringstream &LiteralToString(std::stringstream &stream, const Literal &s) {
stream << s; stream << s;
return stream; return stream;
} }
std::stringstream& LiteralToString(std::stringstream& stream, const aiString& s) { std::stringstream &LiteralToString(std::stringstream &stream, const aiString &s) {
std::string t; std::string t;
// escape backslashes and single quotes, both would render the JSON invalid if left as is // escape backslashes and single quotes, both would render the JSON invalid if left as is
@ -189,7 +186,7 @@ private:
return stream; return stream;
} }
std::stringstream& LiteralToString(std::stringstream& stream, float f) { std::stringstream &LiteralToString(std::stringstream &stream, float f) {
if (!std::numeric_limits<float>::is_iec559) { if (!std::numeric_limits<float>::is_iec559) {
// on a non IEEE-754 platform, we make no assumptions about the representation or existence // on a non IEEE-754 platform, we make no assumptions about the representation or existence
// of special floating-point numbers. // of special floating-point numbers.
@ -228,7 +225,7 @@ private:
} }
private: private:
Assimp::IOStream& out; Assimp::IOStream &out;
std::string indent, newline; std::string indent, newline;
std::stringstream buff; std::stringstream buff;
bool first; bool first;
@ -236,7 +233,7 @@ private:
unsigned int flags; unsigned int flags;
}; };
void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiVector3D &ai, bool is_elem = true) {
out.StartArray(is_elem); out.StartArray(is_elem);
out.Element(ai.x); out.Element(ai.x);
out.Element(ai.y); out.Element(ai.y);
@ -244,7 +241,7 @@ void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) {
out.EndArray(); out.EndArray();
} }
void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiQuaternion &ai, bool is_elem = true) {
out.StartArray(is_elem); out.StartArray(is_elem);
out.Element(ai.w); out.Element(ai.w);
out.Element(ai.x); out.Element(ai.x);
@ -253,7 +250,7 @@ void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) {
out.EndArray(); out.EndArray();
} }
void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiColor3D &ai, bool is_elem = true) {
out.StartArray(is_elem); out.StartArray(is_elem);
out.Element(ai.r); out.Element(ai.r);
out.Element(ai.g); out.Element(ai.g);
@ -261,7 +258,7 @@ void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) {
out.EndArray(); out.EndArray();
} }
void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiMatrix4x4 &ai, bool is_elem = true) {
out.StartArray(is_elem); out.StartArray(is_elem);
for (unsigned int x = 0; x < 4; ++x) { for (unsigned int x = 0; x < 4; ++x) {
for (unsigned int y = 0; y < 4; ++y) { for (unsigned int y = 0; y < 4; ++y) {
@ -271,7 +268,7 @@ void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) {
out.EndArray(); out.EndArray();
} }
void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiBone &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -292,7 +289,7 @@ void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiFace &ai, bool is_elem = true) {
out.StartArray(is_elem); out.StartArray(is_elem);
for (unsigned int i = 0; i < ai.mNumIndices; ++i) { for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
out.Element(ai.mIndices[i]); out.Element(ai.mIndices[i]);
@ -300,7 +297,7 @@ void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) {
out.EndArray(); out.EndArray();
} }
void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiMesh &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -411,7 +408,7 @@ void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiNode &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -441,13 +438,13 @@ void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("properties"); out.Key("properties");
out.StartArray(); out.StartArray();
for (unsigned int i = 0; i < ai.mNumProperties; ++i) { for (unsigned int i = 0; i < ai.mNumProperties; ++i) {
const aiMaterialProperty* const prop = ai.mProperties[i]; const aiMaterialProperty *const prop = ai.mProperties[i];
out.StartObj(true); out.StartObj(true);
out.Key("key"); out.Key("key");
out.SimpleValue(prop->mKey); out.SimpleValue(prop->mKey);
@ -461,46 +458,41 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
out.Key("value"); out.Key("value");
switch (prop->mType) { switch (prop->mType) {
case aiPTI_Float: case aiPTI_Float:
if (prop->mDataLength / sizeof(float) > 1) { if (prop->mDataLength / sizeof(float) > 1) {
out.StartArray(); out.StartArray();
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) { for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) {
out.Element(reinterpret_cast<float*>(prop->mData)[ii]); out.Element(reinterpret_cast<float *>(prop->mData)[ii]);
}
out.EndArray();
} }
else { out.EndArray();
out.SimpleValue(*reinterpret_cast<float*>(prop->mData)); } else {
} out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
break; }
break;
case aiPTI_Integer: case aiPTI_Integer:
if (prop->mDataLength / sizeof(int) > 1) { if (prop->mDataLength / sizeof(int) > 1) {
out.StartArray(); out.StartArray();
for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) { for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) {
out.Element(reinterpret_cast<int*>(prop->mData)[ii]); out.Element(reinterpret_cast<int *>(prop->mData)[ii]);
}
out.EndArray();
} else {
out.SimpleValue(*reinterpret_cast<int*>(prop->mData));
} }
break; out.EndArray();
} else {
out.SimpleValue(*reinterpret_cast<int *>(prop->mData));
}
break;
case aiPTI_String: case aiPTI_String: {
{ aiString s;
aiString s; aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s); out.SimpleValue(s);
out.SimpleValue(s); } break;
} case aiPTI_Buffer: {
break; // binary data is written as series of hex-encoded octets
case aiPTI_Buffer: out.SimpleValue(prop->mData, prop->mDataLength);
{ } break;
// binary data is written as series of hex-encoded octets default:
out.SimpleValue(prop->mData, prop->mDataLength); assert(false);
}
break;
default:
assert(false);
} }
out.EndObj(); out.EndObj();
@ -510,7 +502,7 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiTexture &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("width"); out.Key("width");
@ -525,13 +517,12 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
out.Key("data"); out.Key("data");
if (!ai.mHeight) { if (!ai.mHeight) {
out.SimpleValue(ai.pcData, ai.mWidth); out.SimpleValue(ai.pcData, ai.mWidth);
} } else {
else {
out.StartArray(); out.StartArray();
for (unsigned int y = 0; y < ai.mHeight; ++y) { for (unsigned int y = 0; y < ai.mHeight; ++y) {
out.StartArray(true); out.StartArray(true);
for (unsigned int x = 0; x < ai.mWidth; ++x) { for (unsigned int x = 0; x < ai.mWidth; ++x) {
const aiTexel& tx = ai.pcData[y*ai.mWidth + x]; const aiTexel &tx = ai.pcData[y * ai.mWidth + x];
out.StartArray(true); out.StartArray(true);
out.Element(static_cast<unsigned int>(tx.r)); out.Element(static_cast<unsigned int>(tx.r));
out.Element(static_cast<unsigned int>(tx.g)); out.Element(static_cast<unsigned int>(tx.g));
@ -547,7 +538,7 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiLight &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -585,7 +576,6 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
if (ai.mType != aiLightSource_POINT) { if (ai.mType != aiLightSource_POINT) {
out.Key("direction"); out.Key("direction");
Write(out, ai.mDirection, false); Write(out, ai.mDirection, false);
} }
if (ai.mType != aiLightSource_DIRECTIONAL) { if (ai.mType != aiLightSource_DIRECTIONAL) {
@ -596,7 +586,7 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiNodeAnim &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -612,7 +602,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
out.Key("positionkeys"); out.Key("positionkeys");
out.StartArray(); out.StartArray();
for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) { for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) {
const aiVectorKey& pos = ai.mPositionKeys[n]; const aiVectorKey &pos = ai.mPositionKeys[n];
out.StartArray(true); out.StartArray(true);
out.Element(pos.mTime); out.Element(pos.mTime);
Write(out, pos.mValue); Write(out, pos.mValue);
@ -625,7 +615,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
out.Key("rotationkeys"); out.Key("rotationkeys");
out.StartArray(); out.StartArray();
for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) { for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) {
const aiQuatKey& rot = ai.mRotationKeys[n]; const aiQuatKey &rot = ai.mRotationKeys[n];
out.StartArray(true); out.StartArray(true);
out.Element(rot.mTime); out.Element(rot.mTime);
Write(out, rot.mValue); Write(out, rot.mValue);
@ -638,7 +628,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
out.Key("scalingkeys"); out.Key("scalingkeys");
out.StartArray(); out.StartArray();
for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) { for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) {
const aiVectorKey& scl = ai.mScalingKeys[n]; const aiVectorKey &scl = ai.mScalingKeys[n];
out.StartArray(true); out.StartArray(true);
out.Element(scl.mTime); out.Element(scl.mTime);
Write(out, scl.mValue); Write(out, scl.mValue);
@ -649,7 +639,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiAnimation &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -670,7 +660,7 @@ void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) { void Write(JSONWriter &out, const aiCamera &ai, bool is_elem = true) {
out.StartObj(is_elem); out.StartObj(is_elem);
out.Key("name"); out.Key("name");
@ -697,7 +687,7 @@ void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) {
out.EndObj(); out.EndObj();
} }
void WriteFormatInfo(JSONWriter& out) { void WriteFormatInfo(JSONWriter &out) {
out.StartObj(); out.StartObj();
out.Key("format"); out.Key("format");
out.SimpleValue("\"assimp2json\""); out.SimpleValue("\"assimp2json\"");
@ -706,7 +696,7 @@ void WriteFormatInfo(JSONWriter& out) {
out.EndObj(); out.EndObj();
} }
void Write(JSONWriter& out, const aiScene& ai) { void Write(JSONWriter &out, const aiScene &ai) {
out.StartObj(); out.StartObj();
out.Key("__metadata__"); out.Key("__metadata__");
@ -774,15 +764,14 @@ void Write(JSONWriter& out, const aiScene& ai) {
out.EndObj(); out.EndObj();
} }
void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) {
void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) {
std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt")); std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
if (!str) { if (!str) {
//throw Assimp::DeadlyExportError("could not open output file"); throw Assimp::DeadlyExportError("could not open output file");
} }
// get a copy of the scene so we can modify it // get a copy of the scene so we can modify it
aiScene* scenecopy_tmp; aiScene *scenecopy_tmp;
aiCopyScene(scene, &scenecopy_tmp); aiCopyScene(scene, &scenecopy_tmp);
try { try {
@ -795,15 +784,14 @@ void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* sc
JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats); JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
Write(s, *scenecopy_tmp); Write(s, *scenecopy_tmp);
} } catch (...) {
catch (...) {
aiFreeScene(scenecopy_tmp); aiFreeScene(scenecopy_tmp);
throw; throw;
} }
aiFreeScene(scenecopy_tmp); aiFreeScene(scenecopy_tmp);
} }
} } // namespace Assimp
#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER #endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT #endif // ASSIMP_BUILD_NO_EXPORT