diff options
Diffstat (limited to 'modules/fbx/fbx_parser')
-rw-r--r-- | modules/fbx/fbx_parser/FBXAnimation.cpp | 21 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp | 41 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXDeformer.cpp | 10 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXDocument.cpp | 101 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXDocument.h | 149 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXDocumentUtil.cpp | 39 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXDocumentUtil.h | 7 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXMaterial.cpp | 27 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXMeshGeometry.cpp | 8 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXMeshGeometry.h | 6 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXModel.cpp | 5 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXNodeAttribute.cpp | 11 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXParser.cpp | 50 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXParser.h | 13 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXProperties.cpp | 43 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXProperties.h | 28 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXTokenizer.cpp | 4 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXTokenizer.h | 4 | ||||
-rw-r--r-- | modules/fbx/fbx_parser/FBXUtil.cpp | 2 |
19 files changed, 193 insertions, 376 deletions
diff --git a/modules/fbx/fbx_parser/FBXAnimation.cpp b/modules/fbx/fbx_parser/FBXAnimation.cpp index 4ab5edebb1..0fbff035fd 100644 --- a/modules/fbx/fbx_parser/FBXAnimation.cpp +++ b/modules/fbx/fbx_parser/FBXAnimation.cpp @@ -128,11 +128,9 @@ AnimationCurve::~AnimationCurve() { // ------------------------------------------------------------------------------------------------ AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name, - const Document &doc, const char *const *target_prop_whitelist /*= NULL*/, + const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/, size_t whitelist_size /*= 0*/) : - Object(id, element, name), doc(doc) { - const ScopePtr sc = GetRequiredScope(element); - + Object(id, element, name), target(), doc(doc) { // find target node const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" }; const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3); @@ -154,8 +152,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, co prop = con->PropertyName(); break; } - - props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false); } // ------------------------------------------------------------------------------------------------ @@ -187,10 +183,6 @@ const AnimationMap &AnimationCurveNode::Curves() const { // ------------------------------------------------------------------------------------------------ AnimationLayer::AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : Object(id, element, name), doc(doc) { - const ScopePtr sc = GetRequiredScope(element); - - // note: the props table here bears little importance and is usually absent - props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true); } // ------------------------------------------------------------------------------------------------ @@ -248,11 +240,6 @@ const AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_pro // ------------------------------------------------------------------------------------------------ AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : Object(id, element, name) { - const ScopePtr sc = GetRequiredScope(element); - - // note: we don't currently use any of these properties so we shouldn't bother if it is missing - props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true); - // resolve attached animation layers const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer"); layers.reserve(conns.size()); @@ -282,9 +269,5 @@ AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std: // ------------------------------------------------------------------------------------------------ AnimationStack::~AnimationStack() { - if (props != nullptr) { - delete props; - props = nullptr; - } } } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp index 1d2b7765c5..1eee10b251 100644 --- a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp +++ b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp @@ -130,6 +130,7 @@ Token::Token(const char *sbegin, const char *send, TokenType type, size_t offset line(offset), column(BINARY_MARKER) { #ifdef DEBUG_ENABLED + // contents is bad.. :/ contents = std::string(sbegin, static_cast<size_t>(send - sbegin)); #endif // calc length @@ -232,9 +233,11 @@ unsigned int ReadString(const char *&sbegin_out, const char *&send_out, const ch } // ------------------------------------------------------------------------------------------------ -void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end) { +void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end, bool &corrupt) { if (Offset(cursor, end) < 1) { TokenizeError("cannot ReadData, out of bounds reading length", input, cursor); + corrupt = true; + return; } const char type = *cursor; @@ -328,9 +331,7 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, } cursor += comp_len; break; - } - - // string + } // string case 'S': { const char *sb, *se; // 0 characters can legally happen in such strings @@ -338,11 +339,15 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, break; } default: + corrupt = true; // must exit TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1), input, cursor); + return; } if (cursor > end) { + corrupt = true; // must exit TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1), input, cursor); + return; } // the type code is contained in the returned range @@ -350,7 +355,7 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, } // ------------------------------------------------------------------------------------------------ -bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits) { +bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits, bool &corrupt) { // the first word contains the offset at which this block ends const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); @@ -364,8 +369,12 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, if (end_offset > Offset(input, end)) { TokenizeError("block offset is out of range", input, cursor); + corrupt = true; + return false; } else if (end_offset < Offset(input, cursor)) { TokenizeError("block offset is negative out of range", input, cursor); + corrupt = true; + return false; } // the second data word contains the number of properties in the scope @@ -375,7 +384,7 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // now comes the name of the scope/key - const char *sbeg, *send; + const char *sbeg = nullptr, *send = nullptr; ReadString(sbeg, send, input, cursor, end); output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor))); @@ -383,7 +392,10 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, // now come the individual properties const char *begin_cursor = cursor; for (unsigned int i = 0; i < prop_count; ++i) { - ReadData(sbeg, send, input, cursor, begin_cursor + prop_length); + ReadData(sbeg, send, input, cursor, begin_cursor + prop_length, corrupt); + if (corrupt) { + return false; + } output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor))); @@ -394,6 +406,8 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, if (Offset(begin_cursor, cursor) != prop_length) { TokenizeError("property length not reached, something is wrong", input, cursor); + corrupt = true; + return false; } // at the end of each nested block, there is a NUL record to indicate @@ -410,13 +424,18 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, // XXX this is vulnerable to stack overflowing .. while (Offset(input, cursor) < end_offset - sentinel_block_length) { - ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits); + ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits, corrupt); + if (corrupt) { + return false; + } } output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor))); for (unsigned int i = 0; i < sentinel_block_length; ++i) { if (cursor[i] != '\0') { TokenizeError("failed to read nested block sentinel, expected all bytes to be 0", input, cursor); + corrupt = true; + return false; } } cursor += sentinel_block_length; @@ -424,6 +443,8 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, if (Offset(input, cursor) != end_offset) { TokenizeError("scope length not reached, something is wrong", input, cursor); + corrupt = true; + return false; } return true; @@ -432,7 +453,7 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, // ------------------------------------------------------------------------------------------------ // TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent -void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length) { +void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) { if (length < 0x1b) { //TokenizeError("file is too short",0); } @@ -459,7 +480,7 @@ void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length) const bool is64bits = version >= 7500; const char *end = input + length; while (cursor < end) { - if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { + if (!ReadScope(output_tokens, input, cursor, input + length, is64bits, corrupt)) { break; } } diff --git a/modules/fbx/fbx_parser/FBXDeformer.cpp b/modules/fbx/fbx_parser/FBXDeformer.cpp index 4b774e6b2a..4220ba62a7 100644 --- a/modules/fbx/fbx_parser/FBXDeformer.cpp +++ b/modules/fbx/fbx_parser/FBXDeformer.cpp @@ -78,7 +78,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXMeshGeometry.h" #include "FBXParser.h" #include "core/math/math_funcs.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include <iostream> @@ -89,10 +89,6 @@ using namespace Util; // ------------------------------------------------------------------------------------------------ Deformer::Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : Object(id, element, name) { - const ScopePtr sc = GetRequiredScope(element); - - const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2)); - props = GetPropertyTable(doc, "Deformer.Fbx" + classname, element, sc, true); } // ------------------------------------------------------------------------------------------------ @@ -101,10 +97,6 @@ Deformer::~Deformer() { Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : Object(id, element, name) { - const ScopePtr sc = GetRequiredScope(element); - const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2)); - // used something.fbx as this is a cache name. - props = GetPropertyTable(doc, "Something.Fbx" + classname, element, sc, true); } Constraint::~Constraint() { diff --git a/modules/fbx/fbx_parser/FBXDocument.cpp b/modules/fbx/fbx_parser/FBXDocument.cpp index d156db201b..89c69d2ee8 100644 --- a/modules/fbx/fbx_parser/FBXDocument.cpp +++ b/modules/fbx/fbx_parser/FBXDocument.cpp @@ -228,7 +228,7 @@ ObjectPtr LazyObject::LoadObject() { // ------------------------------------------------------------------------------------------------ Object::Object(uint64_t id, const ElementPtr element, const std::string &name) : - element(element), name(name), id(id) { + PropertyTable(element), element(element), name(name), id(id) { } // ------------------------------------------------------------------------------------------------ @@ -237,17 +237,13 @@ Object::~Object() { } // ------------------------------------------------------------------------------------------------ -FileGlobalSettings::FileGlobalSettings(const Document &doc, const PropertyTable *props) : - props(props), doc(doc) { +FileGlobalSettings::FileGlobalSettings(const Document &doc) : + PropertyTable(), doc(doc) { // empty } // ------------------------------------------------------------------------------------------------ FileGlobalSettings::~FileGlobalSettings() { - if (props != nullptr) { - delete props; - props = nullptr; - } } // ------------------------------------------------------------------------------------------------ @@ -287,15 +283,12 @@ Document::~Document() { delete v.second; } - if (metadata_properties != nullptr) { - delete metadata_properties; - } // clear globals import pointer globals.reset(); } // ------------------------------------------------------------------------------------------------ -static const unsigned int LowerSupportedVersion = 7300; +static const unsigned int LowerSupportedVersion = 7100; static const unsigned int UpperSupportedVersion = 7700; bool Document::ReadHeader() { @@ -306,6 +299,11 @@ bool Document::ReadHeader() { DOMError("no FBXHeaderExtension dictionary found"); } + if (parser.IsCorrupt()) { + DOMError("File is corrupt"); + return false; + } + const ScopePtr shead = ehead->Compound(); fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead, "FBXVersion", ehead), 0)); @@ -325,18 +323,11 @@ bool Document::ReadHeader() { creator = ParseTokenAsString(GetRequiredToken(ecreator, 0)); } - // // Scene Info - // - const ElementPtr scene_info = shead->GetElement("SceneInfo"); if (scene_info) { - PropertyTable *fileExportProps = const_cast<PropertyTable *>(GetPropertyTable(*this, "", scene_info, scene_info->Compound(), true)); - - if (fileExportProps) { - metadata_properties = fileExportProps; - } + metadata_properties.Setup(scene_info); } const ElementPtr etimestamp = shead->GetElement("CreationTimeStamp"); @@ -358,23 +349,7 @@ bool Document::ReadHeader() { void Document::ReadGlobalSettings() { ERR_FAIL_COND_MSG(globals != nullptr, "Global settings is already setup this is a serious error and should be reported"); - const ScopePtr sc = parser.GetRootScope(); - const ElementPtr ehead = sc->GetElement("GlobalSettings"); - if (nullptr == ehead || !ehead->Compound()) { - DOMWarning("no GlobalSettings dictionary found"); - globals = std::make_shared<FileGlobalSettings>(*this, new PropertyTable()); - return; - } - - const PropertyTable *props = GetPropertyTable(*this, "", ehead, ehead->Compound(), true); - - //double v = PropertyGet<float>( *props, std::string("UnitScaleFactor"), 1.0 ); - - if (!props) { - DOMError("GlobalSettings dictionary contains no property table"); - } - - globals = std::make_shared<FileGlobalSettings>(*this, props); + globals = std::make_shared<FileGlobalSettings>(*this); } // ------------------------------------------------------------------------------------------------ @@ -445,58 +420,6 @@ void Document::ReadObjects() { // ------------------------------------------------------------------------------------------------ void Document::ReadPropertyTemplates() { - const ScopePtr sc = parser.GetRootScope(); - // read property templates from "Definitions" section - const ElementPtr edefs = sc->GetElement("Definitions"); - if (!edefs || !edefs->Compound()) { - DOMWarning("no Definitions dictionary found"); - return; - } - - const ScopePtr sdefs = edefs->Compound(); - const ElementCollection otypes = sdefs->GetCollection("ObjectType"); - for (ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) { - const ElementPtr el = (*it).second; - const ScopePtr sc_2 = el->Compound(); - if (!sc_2) { - DOMWarning("expected nested scope in ObjectType, ignoring", el); - continue; - } - - const TokenList &tok = el->Tokens(); - if (tok.empty()) { - DOMWarning("expected name for ObjectType element, ignoring", el); - continue; - } - - const std::string &oname = ParseTokenAsString(tok[0]); - - const ElementCollection templs = sc_2->GetCollection("PropertyTemplate"); - for (ElementMap::const_iterator iter = templs.first; iter != templs.second; ++iter) { - const ElementPtr el_2 = (*iter).second; - const ScopePtr sc_3 = el_2->Compound(); - if (!sc_3) { - DOMWarning("expected nested scope in PropertyTemplate, ignoring", el); - continue; - } - - const TokenList &tok_2 = el_2->Tokens(); - if (tok_2.empty()) { - DOMWarning("expected name for PropertyTemplate element, ignoring", el); - continue; - } - - const std::string &pname = ParseTokenAsString(tok_2[0]); - - const ElementPtr Properties70 = sc_3->GetElement("Properties70"); - if (Properties70) { - // PropertyTable(const ElementPtr element, const PropertyTable* templateProps); - const PropertyTable *props = new PropertyTable(Properties70, nullptr); - - templates[oname + "." + pname] = props; - } - } - } } // ------------------------------------------------------------------------------------------------ @@ -564,7 +487,7 @@ const std::vector<const AnimationStack *> &Document::AnimationStacks() const { const AnimationStack *stack = lazy->Get<AnimationStack>(); ERR_CONTINUE_MSG(!stack, "invalid ptr to AnimationStack - conversion failure"); - // We push back the weak reference :) to keep things simple, as ownership is on the parser side so it wont be cleaned up. + // We push back the weak reference :) to keep things simple, as ownership is on the parser side so it won't be cleaned up. animationStacksResolved.push_back(stack); } diff --git a/modules/fbx/fbx_parser/FBXDocument.h b/modules/fbx/fbx_parser/FBXDocument.h index 20e635a6a4..885ff8fca4 100644 --- a/modules/fbx/fbx_parser/FBXDocument.h +++ b/modules/fbx/fbx_parser/FBXDocument.h @@ -37,7 +37,7 @@ #include "FBXCommon.h" #include "FBXParser.h" #include "FBXProperties.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector2.h" #include "core/math/vector3.h" #include "core/string/print_string.h" @@ -130,7 +130,7 @@ private: }; /** Base class for in-memory (DOM) representations of FBX objects */ -class Object { +class Object : public PropertyTable { public: Object(uint64_t id, const ElementPtr element, const std::string &name); @@ -149,9 +149,9 @@ public: } protected: - const ElementPtr element; + const ElementPtr element = nullptr; const std::string name; - const uint64_t id = 0; + const uint64_t id; }; /** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table, @@ -159,22 +159,13 @@ protected: class NodeAttribute : public Object { public: NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~NodeAttribute(); - - const PropertyTable *Props() const { - return props; - } - -private: - const PropertyTable *props; }; /** DOM base class for FBX camera settings attached to a node */ class CameraSwitcher : public NodeAttribute { public: CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~CameraSwitcher(); int CameraID() const { @@ -190,26 +181,26 @@ public: } private: - int cameraId; + int cameraId = 0; std::string cameraName; std::string cameraIndexName; }; #define fbx_stringize(a) #a -#define fbx_simple_property(name, type, default_value) \ - type name() const { \ - return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \ +#define fbx_simple_property(name, type, default_value) \ + type name() const { \ + return PropertyGet<type>(this, fbx_stringize(name), (default_value)); \ } // XXX improve logging -#define fbx_simple_enum_property(name, type, default_value) \ - type name() const { \ - const int ival = PropertyGet<int>(Props(), fbx_stringize(name), static_cast<int>(default_value)); \ - if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \ - return static_cast<type>(default_value); \ - } \ - return static_cast<type>(ival); \ +#define fbx_simple_enum_property(name, type, default_value) \ + type name() const { \ + const int ival = PropertyGet<int>(this, fbx_stringize(name), static_cast<int>(default_value)); \ + if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \ + return static_cast<type>(default_value); \ + } \ + return static_cast<type>(ival); \ } class FbxPoseNode; @@ -251,20 +242,19 @@ public: return target_id; } - Transform GetBindPose() const { + Transform3D GetBindPose() const { return transform; } private: - uint64_t target_id; - Transform transform; + uint64_t target_id = 0; + Transform3D transform; }; /** DOM base class for FBX cameras attached to a node */ class Camera : public NodeAttribute { public: Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Camera(); fbx_simple_property(Position, Vector3, Vector3(0, 0, 0)); @@ -380,7 +370,6 @@ public: }; Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Model(); fbx_simple_property(QuaternionInterpolate, int, 0); @@ -466,10 +455,6 @@ public: return culling; } - const PropertyTable *Props() const { - return props; - } - /** Get material links */ const std::vector<const Material *> &GetMaterials() const { return materials; @@ -498,13 +483,11 @@ private: std::string shading; std::string culling; - const PropertyTable *props = nullptr; }; class ModelLimbNode : public Model { public: ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~ModelLimbNode(); }; @@ -512,7 +495,6 @@ public: class Texture : public Object { public: Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); - virtual ~Texture(); const std::string &Type() const { @@ -539,10 +521,6 @@ public: return uvScaling; } - const PropertyTable *Props() const { - return props; - } - // return a 4-tuple const unsigned int *Crop() const { return crop; @@ -560,10 +538,8 @@ private: std::string relativeFileName; std::string fileName; std::string alphaSource; - const PropertyTable *props = nullptr; unsigned int crop[4] = { 0 }; - const Video *media = nullptr; }; @@ -626,8 +602,8 @@ public: private: std::vector<const Texture *> textures; - BlendMode blendMode; - float alpha; + BlendMode blendMode = BlendMode::BlendMode_Additive; + float alpha = 0; }; typedef std::map<std::string, const Texture *> TextureMap; @@ -656,10 +632,6 @@ public: return relativeFileName; } - const PropertyTable *Props() const { - return props; - } - const uint8_t *Content() const { return content; } @@ -687,7 +659,6 @@ private: std::string type; std::string relativeFileName; std::string fileName; - const PropertyTable *props = nullptr; uint64_t contentLength = 0; uint8_t *content = nullptr; @@ -708,10 +679,6 @@ public: return multilayer; } - const PropertyTable *Props() const { - return props; - } - const TextureMap &Textures() const { return textures; } @@ -722,8 +689,7 @@ public: private: std::string shading; - bool multilayer; - const PropertyTable *props; + bool multilayer = false; TextureMap textures; LayeredTextureMap layeredTextures; @@ -733,7 +699,7 @@ private: typedef std::vector<int64_t> KeyTimeList; typedef std::vector<float> KeyValueList; -/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefor) */ +/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefore) */ class AnimationCurve : public Object { public: AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); @@ -791,13 +757,9 @@ public: virtual ~AnimationCurveNode(); - const PropertyTable *Props() const { - return props; - } - const AnimationMap &Curves() const; - /** Object the curve is assigned to, this can be NULL if the + /** Object the curve is assigned to, this can be nullptr if the * target object has no DOM representation or could not * be read for other reasons.*/ Object *Target() const { @@ -819,7 +781,6 @@ public: private: Object *target = nullptr; - const PropertyTable *props; mutable AnimationMap curves; std::string prop; const Document &doc; @@ -837,18 +798,12 @@ public: AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); virtual ~AnimationLayer(); - const PropertyTable *Props() const { - //ai_assert(props.get()); - return props; - } - /* the optional white list specifies a list of property names for which the caller wants animations for. Curves not matching this list will not be added to the animation layer. */ const AnimationCurveNodeList Nodes(const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0) const; private: - const PropertyTable *props; const Document &doc; }; @@ -863,16 +818,11 @@ public: fbx_simple_property(ReferenceStart, int64_t, 0L); fbx_simple_property(ReferenceStop, int64_t, 0L); - const PropertyTable *Props() const { - return props; - } - const AnimationLayerList &Layers() const { return layers; } private: - const PropertyTable *props = nullptr; AnimationLayerList layers; }; @@ -881,14 +831,6 @@ class Deformer : public Object { public: Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Deformer(); - - const PropertyTable *Props() const { - //ai_assert(props.get()); - return props; - } - -private: - const PropertyTable *props; }; /** Constraints are from Maya they can help us with BoneAttachments :) **/ @@ -896,9 +838,6 @@ class Constraint : public Object { public: Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Constraint(); - -private: - const PropertyTable *props; }; typedef std::vector<float> WeightArray; @@ -924,7 +863,7 @@ public: } private: - float percent; + float percent = 0; WeightArray fullWeights; std::vector<const ShapeGeometry *> shapeGeometries; }; @@ -966,11 +905,11 @@ public: } /** */ - const Transform &GetTransform() const { + const Transform3D &GetTransform() const { return transform; } - const Transform &TransformLink() const { + const Transform3D &TransformLink() const { return transformLink; } @@ -978,7 +917,7 @@ public: return node; } - const Transform &TransformAssociateModel() const { + const Transform3D &TransformAssociateModel() const { return transformAssociateModel; } @@ -1002,11 +941,11 @@ private: std::vector<float> weights; std::vector<unsigned int> indices; - Transform transform; - Transform transformLink; - Transform transformAssociateModel; + Transform3D transform; + Transform3D transformLink; + Transform3D transformAssociateModel; SkinLinkMode link_mode; - bool valid_transformAssociateModel; + bool valid_transformAssociateModel = false; const Model *node = nullptr; }; @@ -1037,8 +976,8 @@ public: } private: - float accuracy; - SkinType skinType; + float accuracy = 0; + SkinType skinType = SkinType::Skin_Linear; std::vector<const Cluster *> clusters; }; @@ -1050,7 +989,7 @@ public: // note: a connection ensures that the source and dest objects exist, but // not that they have DOM representations, so the return value of one of - // these functions can still be NULL. + // these functions can still be nullptr. Object *SourceObject() const; Object *DestinationObject() const; @@ -1087,10 +1026,10 @@ public: } public: - uint64_t insertionOrder; + uint64_t insertionOrder = 0; const std::string prop; - uint64_t src, dest; + uint64_t src = 0, dest = 0; const Document &doc; }; @@ -1105,15 +1044,10 @@ typedef std::multimap<uint64_t, const Connection *> ConnectionMap; /** DOM class for global document settings, a single instance per document can * be accessed via Document.Globals(). */ -class FileGlobalSettings { +class FileGlobalSettings : public PropertyTable { public: - FileGlobalSettings(const Document &doc, const PropertyTable *props); - - ~FileGlobalSettings(); - - const PropertyTable *Props() const { - return props; - } + FileGlobalSettings(const Document &doc); + virtual ~FileGlobalSettings(); const Document &GetDocument() const { return doc; @@ -1158,7 +1092,6 @@ public: fbx_simple_property(CustomFrameRate, float, -1.0f); private: - const PropertyTable *props = nullptr; const Document &doc; }; @@ -1196,7 +1129,7 @@ public: return globals.get(); } - const PropertyTable *GetMetadataProperties() const { + const PropertyTable &GetMetadataProperties() const { return metadata_properties; } @@ -1293,7 +1226,7 @@ private: std::vector<uint64_t> materials; std::vector<uint64_t> skins; mutable std::vector<const AnimationStack *> animationStacksResolved; - PropertyTable *metadata_properties = nullptr; + PropertyTable metadata_properties; std::shared_ptr<FileGlobalSettings> globals = nullptr; }; } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp index df50a32c39..4a33024969 100644 --- a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp +++ b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp @@ -95,14 +95,14 @@ void DOMError(const std::string &message, const std::shared_ptr<Token> token) { print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str())); } -void DOMError(const std::string &message, const Element *element /*= NULL*/) { +void DOMError(const std::string &message, const Element *element /*= nullptr*/) { if (element) { DOMError(message, element->KeyToken()); } print_error("[FBX-DOM] " + String(message.c_str())); } -void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) { +void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) { if (element) { DOMError(message, element->KeyToken()); } @@ -117,7 +117,7 @@ void DOMWarning(const std::string &message, const Token *token) { print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str())); } -void DOMWarning(const std::string &message, const Element *element /*= NULL*/) { +void DOMWarning(const std::string &message, const Element *element /*= nullptr*/) { if (element) { DOMWarning(message, element->KeyToken()); return; @@ -129,7 +129,7 @@ void DOMWarning(const std::string &message, const std::shared_ptr<Token> token) print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str())); } -void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) { +void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) { if (element) { DOMWarning(message, element->KeyToken()); return; @@ -137,36 +137,5 @@ void DOMWarning(const std::string &message, const std::shared_ptr<Element> eleme print_verbose("[FBX-DOM] warning:" + String(message.c_str())); } -// ------------------------------------------------------------------------------------------------ -// fetch a property table and the corresponding property template -const PropertyTable *GetPropertyTable(const Document &doc, - const std::string &templateName, - const ElementPtr element, - const ScopePtr sc, - bool no_warn /*= false*/) { - // todo: make this an abstraction - const ElementPtr Properties70 = sc->GetElement("Properties70"); - const PropertyTable *templateProps = static_cast<const PropertyTable *>(nullptr); - - if (templateName.length()) { - PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName); - if (it != doc.Templates().end()) { - templateProps = (*it).second; - } - } - - if (!Properties70 || !Properties70->Compound()) { - if (!no_warn) { - DOMWarning("property table (Properties70) not found", element); - } - if (templateProps) { - return new const PropertyTable(templateProps); - } else { - return new const PropertyTable(); - } - } - - return new PropertyTable(Properties70, templateProps); -} } // namespace Util } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.h b/modules/fbx/fbx_parser/FBXDocumentUtil.h index daa9de4a33..ba86191c4a 100644 --- a/modules/fbx/fbx_parser/FBXDocumentUtil.h +++ b/modules/fbx/fbx_parser/FBXDocumentUtil.h @@ -98,13 +98,6 @@ void DOMWarning(const std::string &message, const Element *element); void DOMWarning(const std::string &message, const std::shared_ptr<Token> token); void DOMWarning(const std::string &message, const std::shared_ptr<Element> element); -// fetch a property table and the corresponding property template -const PropertyTable *GetPropertyTable(const Document &doc, - const std::string &templateName, - const ElementPtr element, - const ScopePtr sc, - bool no_warn = false); - // ------------------------------------------------------------------------------------------------ template <typename T> const T *ProcessSimpleConnection(const Connection &con, diff --git a/modules/fbx/fbx_parser/FBXMaterial.cpp b/modules/fbx/fbx_parser/FBXMaterial.cpp index 219da1b2f4..bf8922267e 100644 --- a/modules/fbx/fbx_parser/FBXMaterial.cpp +++ b/modules/fbx/fbx_parser/FBXMaterial.cpp @@ -118,8 +118,6 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c DOMWarning("shading mode not recognized: " + shading, element); } - props = GetPropertyTable(doc, templateName, element, sc); - // resolve texture links const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID()); for (const Connection *con : conns) { @@ -163,10 +161,6 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c // ------------------------------------------------------------------------------------------------ Material::~Material() { - if (props != nullptr) { - delete props; - props = nullptr; - } } // ------------------------------------------------------------------------------------------------ @@ -219,17 +213,15 @@ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, con alphaSource = ParseTokenAsString(GetRequiredToken(Texture_Alpha_Source, 0)); } - props = GetPropertyTable(doc, "Texture.FbxFileTexture", element, sc); - // 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available. - bool ok; - const Vector3 &scaling = PropertyGet<Vector3>(props, "Scaling", ok); + bool ok = true; + const Vector3 &scaling = PropertyGet<Vector3>(this, "Scaling", ok); if (ok) { uvScaling.x = scaling.x; uvScaling.y = scaling.y; } - const Vector3 &trans = PropertyGet<Vector3>(props, "Translation", ok); + const Vector3 &trans = PropertyGet<Vector3>(this, "Translation", ok); if (ok) { uvTrans.x = trans.x; uvTrans.y = trans.y; @@ -254,10 +246,6 @@ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, con } Texture::~Texture() { - if (props != nullptr) { - delete props; - props = nullptr; - } } LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Document & /*doc*/, const std::string &name) : @@ -337,7 +325,7 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s DOMError("embedded content is not surrounded by quotation marks", element); } else { size_t targetLength = 0; - auto numTokens = Content->Tokens().size(); + const size_t numTokens = Content->Tokens().size(); // First time compute size (it could be large like 64Gb and it is good to allocate it once) for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) { const Token *dataToken = GetRequiredToken(Content, tokenIdx); @@ -390,18 +378,11 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s // runtimeError.what()); } } - - props = GetPropertyTable(doc, "Video.FbxVideo", element, sc); } Video::~Video() { if (content) { delete[] content; } - - if (props != nullptr) { - delete props; - props = nullptr; - } } } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp index a28e7565c6..2cc25a0690 100644 --- a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp +++ b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp @@ -125,7 +125,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::str ScopePtr sc = element->Compound(); ERR_FAIL_COND_MSG(sc == nullptr, "failed to read geometry, prevented crash"); - ERR_FAIL_COND_MSG(!HasElement(sc, "Vertices"), "Detected mesh with no vertexes, didn't populate the mesh"); + ERR_FAIL_COND_MSG(!HasElement(sc, "Vertices"), "Detected mesh with no vertices, didn't populate the mesh"); // must have Mesh elements: const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element); @@ -140,7 +140,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::str ParseVectorDataArray(m_vertices, Vertices); ParseVectorDataArray(m_face_indices, PolygonVertexIndex); - ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertexes in FBX file, did you mean to delete it?"); + ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertices in FBX file, did you mean to delete it?"); ERR_FAIL_COND_MSG(m_face_indices.empty(), "mesh has no faces, was this intended?"); // Retrieve layer elements, for all of the mesh @@ -278,7 +278,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::str } } // As the algorithm above, this check is useless. Because the first - // ever vertex is always considered the begining of a polygon. + // ever vertex is always considered the beginning of a polygon. ERR_FAIL_COND_MSG(found_it == false, "Was not possible to find the first vertex of this polygon. FBX file is corrupted."); } else { @@ -418,7 +418,7 @@ MeshGeometry::MappingData<T> MeshGeometry::resolve_vertex_data_array( // parse data into array ParseVectorDataArray(tempData.data, GetRequiredElement(source, dataElementName)); - // index array wont always exist + // index array won't always exist const ElementPtr element = GetOptionalElement(source, indexDataElementName); if (element) { ParseVectorDataArray(tempData.index, element); diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.h b/modules/fbx/fbx_parser/FBXMeshGeometry.h index 710e644c68..c9b25f008d 100644 --- a/modules/fbx/fbx_parser/FBXMeshGeometry.h +++ b/modules/fbx/fbx_parser/FBXMeshGeometry.h @@ -96,7 +96,7 @@ public: Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); virtual ~Geometry(); - /** Get the Skin attached to this geometry or NULL */ + /** Get the Skin attached to this geometry or nullptr */ const Skin *DeformerSkin() const; const std::vector<const BlendShape *> &get_blend_shapes() const; @@ -122,7 +122,7 @@ typedef std::vector<int> MatIndexArray; /// ## Map Type: /// * None The mapping is undetermined. /// * ByVertex There will be one mapping coordinate for each surface control point/vertex (ControlPoint is a vertex). -/// * If you have direct reference type verticies[x] +/// * If you have direct reference type vertices[x] /// * If you have IndexToDirect reference type the UV /// * ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex) /// * ByPolygon There can be only one mapping coordinate for the whole polygon. @@ -186,7 +186,7 @@ public: /// Returns -1 if the vertices doesn't form an edge. Vertex order, doesn't // matter. static int get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b); - // Retuns the edge point bu that ID, or the edge with -1 vertices if the + // Returns the edge point bu that ID, or the edge with -1 vertices if the // id is not valid. static Edge get_edge(const std::vector<Edge> &p_map, int p_id); diff --git a/modules/fbx/fbx_parser/FBXModel.cpp b/modules/fbx/fbx_parser/FBXModel.cpp index 767994441f..03c9de0c35 100644 --- a/modules/fbx/fbx_parser/FBXModel.cpp +++ b/modules/fbx/fbx_parser/FBXModel.cpp @@ -98,16 +98,11 @@ Model::Model(uint64_t id, const ElementPtr element, const Document &doc, const s culling = ParseTokenAsString(GetRequiredToken(Culling, 0)); } - props = GetPropertyTable(doc, "Model.FbxNode", element, sc); ResolveLinks(element, doc); } // ------------------------------------------------------------------------------------------------ Model::~Model() { - if (props != nullptr) { - delete props; - props = nullptr; - } } ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : diff --git a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp index 2749fc9f4d..15184a0f5d 100644 --- a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp +++ b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp @@ -84,16 +84,7 @@ using namespace Util; // ------------------------------------------------------------------------------------------------ NodeAttribute::NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name), props() { - const ScopePtr sc = GetRequiredScope(element); - - const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2)); - - // hack on the deriving type but Null/LimbNode attributes are the only case in which - // the property table is by design absent and no warning should be generated - // for it. - const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode"); - props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb); + Object(id, element, name) { } // ------------------------------------------------------------------------------------------------ diff --git a/modules/fbx/fbx_parser/FBXParser.cpp b/modules/fbx/fbx_parser/FBXParser.cpp index 166d98bb8c..a92b23f4ee 100644 --- a/modules/fbx/fbx_parser/FBXParser.cpp +++ b/modules/fbx/fbx_parser/FBXParser.cpp @@ -74,15 +74,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the FBX parser and the rudimentary DOM that we use */ -#include "thirdparty/zlib/zlib.h" #include <stdlib.h> /* strtol */ +#include <zlib.h> #include "ByteSwapper.h" #include "FBXParseTools.h" #include "FBXParser.h" #include "FBXTokenizer.h" #include "core/math/math_defs.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" #include "core/string/print_string.h" @@ -131,6 +131,8 @@ Element::Element(const TokenPtr key_token, Parser &parser) : if (!n) { print_error("unexpected end of file, expected bracket, comma or key" + String(parser.LastToken()->StringContents().c_str())); + parser.corrupt = true; + return; } const TokenType ty = n->Type(); @@ -143,6 +145,8 @@ Element::Element(const TokenPtr key_token, Parser &parser) : if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) { print_error("unexpected token; expected bracket, comma or key" + String(n->StringContents().c_str())); + parser.corrupt = true; + return; } } @@ -150,11 +154,17 @@ Element::Element(const TokenPtr key_token, Parser &parser) : compound = new_Scope(parser); parser.scopes.push_back(compound); + if (parser.corrupt) { + return; + } + // current token should be a TOK_CLOSE_BRACKET n = parser.CurrentToken(); if (n && n->Type() != TokenType_CLOSE_BRACKET) { print_error("expected closing bracket" + String(n->StringContents().c_str())); + parser.corrupt = true; + return; } parser.AdvanceToNextToken(); @@ -173,22 +183,31 @@ Scope::Scope(Parser &parser, bool topLevel) { TokenPtr t = parser.CurrentToken(); if (t->Type() != TokenType_OPEN_BRACKET) { print_error("expected open bracket" + String(t->StringContents().c_str())); + parser.corrupt = true; + return; } } TokenPtr n = parser.AdvanceToNextToken(); if (n == nullptr) { print_error("unexpected end of file"); + parser.corrupt = true; + return; } // note: empty scopes are allowed while (n && n->Type() != TokenType_CLOSE_BRACKET) { if (n->Type() != TokenType_KEY) { print_error("unexpected token, expected TOK_KEY" + String(n->StringContents().c_str())); + parser.corrupt = true; + return; } const std::string str = n->StringContents(); + if (parser.corrupt) { + return; + } // std::multimap<std::string, ElementPtr> (key and value) elements.insert(ElementMap::value_type(str, new_Element(n, parser))); @@ -216,7 +235,7 @@ Scope::~Scope() { // ------------------------------------------------------------------------------------------------ Parser::Parser(const TokenList &tokens, bool is_binary) : - tokens(tokens), cursor(tokens.begin()), is_binary(is_binary) { + corrupt(false), tokens(tokens), cursor(tokens.begin()), is_binary(is_binary) { root = new_Scope(*this, true); scopes.push_back(root); } @@ -1138,7 +1157,7 @@ void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el) { } // ------------------------------------------------------------------------------------------------ -Transform ReadMatrix(const ElementPtr element) { +Transform3D ReadMatrix(const ElementPtr element) { std::vector<float> values; ParseVectorDataArray(values, element); @@ -1148,12 +1167,12 @@ Transform ReadMatrix(const ElementPtr element) { // clean values to prevent any IBM damage on inverse() / affine_inverse() for (float &value : values) { - if (::Math::is_equal_approx(0, value)) { + if (::Math::is_zero_approx(value)) { value = 0; } } - Transform xform; + Transform3D xform; Basis basis; basis.set( @@ -1187,7 +1206,7 @@ std::string ParseTokenAsString(const TokenPtr t) { // ------------------------------------------------------------------------------------------------ // extract a required element from a scope, abort if the element cannot be found -ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= NULL*/) { +ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= nullptr*/) { const ElementPtr el = sc->GetElement(index); TokenPtr token = el->KeyToken(); ERR_FAIL_COND_V(!token, nullptr); @@ -1208,7 +1227,7 @@ bool HasElement(const ScopePtr sc, const std::string &index) { // ------------------------------------------------------------------------------------------------ // extract a required element from a scope, abort if the element cannot be found -ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= NULL*/) { +ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= nullptr*/) { const ElementPtr el = sc->GetElement(index); return el; } @@ -1231,6 +1250,21 @@ ScopePtr GetRequiredScope(const ElementPtr el) { } // ------------------------------------------------------------------------------------------------ +// extract optional compound scope +ScopePtr GetOptionalScope(const ElementPtr el) { + if (el) { + ScopePtr s = el->Compound(); + TokenPtr token = el->KeyToken(); + + if (token && s) { + return s; + } + } + + return nullptr; +} + +// ------------------------------------------------------------------------------------------------ // get token at a particular index TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index) { if (el) { diff --git a/modules/fbx/fbx_parser/FBXParser.h b/modules/fbx/fbx_parser/FBXParser.h index 37d27d3dca..93836c2205 100644 --- a/modules/fbx/fbx_parser/FBXParser.h +++ b/modules/fbx/fbx_parser/FBXParser.h @@ -81,7 +81,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <memory> #include "core/math/color.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector2.h" #include "core/math/vector3.h" @@ -160,7 +160,7 @@ public: } ElementPtr FindElementCaseInsensitive(const std::string &elementName) const { - for (auto element = elements.begin(); element != elements.end(); ++element) { + for (FBXDocParser::ElementMap::const_iterator element = elements.begin(); element != elements.end(); ++element) { if (element->first.compare(elementName)) { return element->second; } @@ -199,6 +199,10 @@ public: return is_binary; } + bool IsCorrupt() const { + return corrupt; + } + private: friend class Scope; friend class Element; @@ -208,6 +212,7 @@ private: TokenPtr CurrentToken() const; private: + bool corrupt = false; ScopeList scopes; const TokenList &tokens; @@ -249,6 +254,8 @@ bool HasElement(const ScopePtr sc, const std::string &index); // extract a required element from a scope, abort if the element cannot be found ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr); ScopePtr GetRequiredScope(const ElementPtr el); // New in 2020. (less likely to destroy application) +ScopePtr GetOptionalScope(const ElementPtr el); // New in 2021. (even LESS likely to destroy application now) + ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr); // extract required compound scope ScopePtr GetRequiredScope(const ElementPtr el); @@ -257,7 +264,7 @@ TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index); // ------------------------------------------------------------------------------------------------ // read a 4x4 matrix from an array of 16 floats -Transform ReadMatrix(const ElementPtr element); +Transform3D ReadMatrix(const ElementPtr element); } // namespace FBXDocParser #endif // FBX_PARSER_H diff --git a/modules/fbx/fbx_parser/FBXProperties.cpp b/modules/fbx/fbx_parser/FBXProperties.cpp index 84e71512d6..37717e9109 100644 --- a/modules/fbx/fbx_parser/FBXProperties.cpp +++ b/modules/fbx/fbx_parser/FBXProperties.cpp @@ -94,7 +94,7 @@ Property::~Property() { namespace { // ------------------------------------------------------------------------------------------------ -// read a typed property out of a FBX element. The return value is NULL if the property cannot be read. +// read a typed property out of a FBX element. The return value is nullptr if the property cannot be read. PropertyPtr ReadTypedProperty(const ElementPtr element) { //ai_assert(element.KeyToken().StringContents() == "P"); @@ -145,19 +145,33 @@ std::string PeekPropertyName(const Element &element) { } // namespace // ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable() { +PropertyTable::PropertyTable() : + element(nullptr) { } -// ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable(const PropertyTable *templateProps) : - templateProps(templateProps), element() { +// Is used when dealing with FBX Objects not metadata. +PropertyTable::PropertyTable(const ElementPtr element) : + element(element) { + Setup(element); } // ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *templateProps) : - templateProps(templateProps), element(element) { - const ScopePtr scope = GetRequiredScope(element); - ERR_FAIL_COND(!scope); +PropertyTable::~PropertyTable() { + for (PropertyMap::value_type &v : props) { + delete v.second; + } +} + +void PropertyTable::Setup(ElementPtr ptr) { + const ScopePtr sc = GetRequiredScope(ptr); + const ElementPtr Properties70 = sc->GetElement("Properties70"); + const ScopePtr scope = GetOptionalScope(Properties70); + + // no scope, no care. + if (!scope) { + return; // NOTE: this is not an error this is actually a Object, without properties, here we will nullptr it. + } + for (const ElementMap::value_type &v : scope->Elements()) { if (v.first != "P") { DOMWarning("expected only P elements in property table", v.second); @@ -182,13 +196,6 @@ PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *temp } // ------------------------------------------------------------------------------------------------ -PropertyTable::~PropertyTable() { - for (PropertyMap::value_type &v : props) { - delete v.second; - } -} - -// ------------------------------------------------------------------------------------------------ PropertyPtr PropertyTable::Get(const std::string &name) const { PropertyMap::const_iterator it = props.find(name); if (it == props.end()) { @@ -203,10 +210,6 @@ PropertyPtr PropertyTable::Get(const std::string &name) const { if (it == props.end()) { // check property template - if (templateProps) { - return templateProps->Get(name); - } - return nullptr; } } diff --git a/modules/fbx/fbx_parser/FBXProperties.h b/modules/fbx/fbx_parser/FBXProperties.h index 0595b25fa7..bfd27ac94e 100644 --- a/modules/fbx/fbx_parser/FBXProperties.h +++ b/modules/fbx/fbx_parser/FBXProperties.h @@ -137,36 +137,31 @@ class PropertyTable { public: // in-memory property table with no source element PropertyTable(); - PropertyTable(const PropertyTable *templateProps); - PropertyTable(const ElementPtr element, const PropertyTable *templateProps); - ~PropertyTable(); + PropertyTable(const ElementPtr element); + virtual ~PropertyTable(); PropertyPtr Get(const std::string &name) const; + void Setup(ElementPtr ptr); // PropertyTable's need not be coupled with FBX elements so this can be NULL - ElementPtr GetElement() const { + ElementPtr GetElement() { return element; } - PropertyMap &GetProperties() const { + PropertyMap &GetProperties() { return props; } - const LazyPropertyMap &GetLazyProperties() const { + const LazyPropertyMap &GetLazyProperties() { return lazyProps; } - const PropertyTable *TemplateProps() const { - return templateProps; - } - DirectPropertyMap GetUnparsedProperties() const; private: LazyPropertyMap lazyProps; mutable PropertyMap props; - const PropertyTable *templateProps = nullptr; - const ElementPtr element = nullptr; + ElementPtr element = nullptr; }; // ------------------------------------------------------------------------------------------------ @@ -191,16 +186,11 @@ template <typename T> inline T PropertyGet(const PropertyTable *in, const std::string &name, bool &result, bool useTemplate = false) { PropertyPtr prop = in->Get(name); if (nullptr == prop) { - if (!useTemplate) { - result = false; - return T(); - } - const PropertyTable *templ = in->TemplateProps(); - if (nullptr == templ) { + if (nullptr == in) { result = false; return T(); } - prop = templ->Get(name); + prop = in->Get(name); if (nullptr == prop) { result = false; return T(); diff --git a/modules/fbx/fbx_parser/FBXTokenizer.cpp b/modules/fbx/fbx_parser/FBXTokenizer.cpp index ea4568fe32..81c5b128e8 100644 --- a/modules/fbx/fbx_parser/FBXTokenizer.cpp +++ b/modules/fbx/fbx_parser/FBXTokenizer.cpp @@ -141,7 +141,7 @@ void ProcessDataToken(TokenList &output_tokens, const char *&start, const char * } // namespace // ------------------------------------------------------------------------------------------------ -void Tokenize(TokenList &output_tokens, const char *input, size_t length) { +void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) { // line and column numbers numbers are one-based unsigned int line = 1; unsigned int column = 1; @@ -185,6 +185,8 @@ void Tokenize(TokenList &output_tokens, const char *input, size_t length) { case '\"': if (token_begin) { TokenizeError("unexpected double-quote", line, column); + corrupt = true; + return; } token_begin = cur; in_double_quotes = true; diff --git a/modules/fbx/fbx_parser/FBXTokenizer.h b/modules/fbx/fbx_parser/FBXTokenizer.h index 1e7e5e6535..184d0fd894 100644 --- a/modules/fbx/fbx_parser/FBXTokenizer.h +++ b/modules/fbx/fbx_parser/FBXTokenizer.h @@ -187,7 +187,7 @@ typedef std::vector<TokenPtr> TokenList; * @param output_tokens Receives a list of all tokens in the input data. * @param input_buffer Textual input buffer to be processed, 0-terminated. * @print_error if something goes wrong */ -void Tokenize(TokenList &output_tokens, const char *input, size_t length); +void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt); /** Tokenizer function for binary FBX files. * @@ -197,7 +197,7 @@ void Tokenize(TokenList &output_tokens, const char *input, size_t length); * @param input_buffer Binary input buffer to be processed. * @param length Length of input buffer, in bytes. There is no 0-terminal. * @print_error if something goes wrong */ -void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length); +void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt); } // namespace FBXDocParser #endif // FBX_TOKENIZER_H diff --git a/modules/fbx/fbx_parser/FBXUtil.cpp b/modules/fbx/fbx_parser/FBXUtil.cpp index 4295cb6f5e..1f14a69099 100644 --- a/modules/fbx/fbx_parser/FBXUtil.cpp +++ b/modules/fbx/fbx_parser/FBXUtil.cpp @@ -121,7 +121,7 @@ static const uint8_t base64DecodeTable[128] = { }; uint8_t DecodeBase64(char ch) { - const auto idx = static_cast<uint8_t>(ch); + const uint8_t idx = static_cast<uint8_t>(ch); if (idx > 127) { return 255; } |