summaryrefslogtreecommitdiff
path: root/modules/fbx/fbx_parser
diff options
context:
space:
mode:
Diffstat (limited to 'modules/fbx/fbx_parser')
-rw-r--r--modules/fbx/fbx_parser/FBXAnimation.cpp19
-rw-r--r--modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp41
-rw-r--r--modules/fbx/fbx_parser/FBXDeformer.cpp8
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.cpp99
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.h125
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.cpp31
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.h7
-rw-r--r--modules/fbx/fbx_parser/FBXMaterial.cpp27
-rw-r--r--modules/fbx/fbx_parser/FBXModel.cpp5
-rw-r--r--modules/fbx/fbx_parser/FBXNodeAttribute.cpp11
-rw-r--r--modules/fbx/fbx_parser/FBXParser.cpp38
-rw-r--r--modules/fbx/fbx_parser/FBXParser.h9
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.cpp41
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.h28
-rw-r--r--modules/fbx/fbx_parser/FBXTokenizer.cpp4
-rw-r--r--modules/fbx/fbx_parser/FBXTokenizer.h4
-rw-r--r--modules/fbx/fbx_parser/FBXUtil.cpp2
17 files changed, 158 insertions, 341 deletions
diff --git a/modules/fbx/fbx_parser/FBXAnimation.cpp b/modules/fbx/fbx_parser/FBXAnimation.cpp
index 4ab5edebb1..1690df6943 100644
--- a/modules/fbx/fbx_parser/FBXAnimation.cpp
+++ b/modules/fbx/fbx_parser/FBXAnimation.cpp
@@ -130,9 +130,7 @@ AnimationCurve::~AnimationCurve() {
AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name,
const Document &doc, const char *const *target_prop_whitelist /*= NULL*/,
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..039718ae15 100644
--- a/modules/fbx/fbx_parser/FBXDeformer.cpp
+++ b/modules/fbx/fbx_parser/FBXDeformer.cpp
@@ -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..bb85d6ff7c 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;
- }
- }
- }
}
// ------------------------------------------------------------------------------------------------
diff --git a/modules/fbx/fbx_parser/FBXDocument.h b/modules/fbx/fbx_parser/FBXDocument.h
index 20e635a6a4..49b7c11c31 100644
--- a/modules/fbx/fbx_parser/FBXDocument.h
+++ b/modules/fbx/fbx_parser/FBXDocument.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;
@@ -256,7 +247,7 @@ public:
}
private:
- uint64_t target_id;
+ uint64_t target_id = 0;
Transform transform;
};
@@ -264,7 +255,6 @@ private:
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;
@@ -791,10 +757,6 @@ 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
@@ -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;
};
@@ -1006,7 +945,7 @@ private:
Transform transformLink;
Transform 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;
};
@@ -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..3930e005c3 100644
--- a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
+++ b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
@@ -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/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..2a76c3f67c 100644
--- a/modules/fbx/fbx_parser/FBXParser.cpp
+++ b/modules/fbx/fbx_parser/FBXParser.cpp
@@ -74,8 +74,8 @@ 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"
@@ -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);
}
@@ -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..8b248e8791 100644
--- a/modules/fbx/fbx_parser/FBXParser.h
+++ b/modules/fbx/fbx_parser/FBXParser.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);
diff --git a/modules/fbx/fbx_parser/FBXProperties.cpp b/modules/fbx/fbx_parser/FBXProperties.cpp
index 84e71512d6..1b3f29ec04 100644
--- a/modules/fbx/fbx_parser/FBXProperties.cpp
+++ b/modules/fbx/fbx_parser/FBXProperties.cpp
@@ -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;
}