Kim Kulling пре 5 година
родитељ
комит
904f17f29f
2 измењених фајлова са 259 додато и 406 уклоњено
  1. 238 406
      code/AssetLib/Collada/ColladaParser.cpp
  2. 21 0
      include/assimp/XmlParser.h

+ 238 - 406
code/AssetLib/Collada/ColladaParser.cpp

@@ -826,12 +826,12 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
                 // we don't support, but which could confuse the loader if
                 // we don't support, but which could confuse the loader if
                 // they're not skipped.
                 // they're not skipped.
                 int v = currentNode.attribute("ref").as_int();
                 int v = currentNode.attribute("ref").as_int();
-/*                if (v y) {
+                /*                if (v y) {
                     ASSIMP_LOG_WARN("Collada: Ignoring texture array index");
                     ASSIMP_LOG_WARN("Collada: Ignoring texture array index");
                     continue;
                     continue;
                 }*/
                 }*/
 
 
-                v  = currentNode.attribute("mip_index").as_int();
+                v = currentNode.attribute("mip_index").as_int();
                 /*if (attrib != -1 && v > 0) {
                 /*if (attrib != -1 && v > 0) {
                     ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer");
                     ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer");
                     continue;
                     continue;
@@ -1023,7 +1023,6 @@ void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) {
             pLight.mOuterAngle = ReadFloatFromTextContent();
             pLight.mOuterAngle = ReadFloatFromTextContent();
         }
         }
     }
     }
-
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -1093,10 +1092,10 @@ void ColladaParser::ReadEffectProfileCommon(XmlNode &node, Collada::Effect &pEff
             // save ID
             // save ID
             std::string sid = currentNode.attribute("sid").as_string();
             std::string sid = currentNode.attribute("sid").as_string();
             //std::string sid = GetAttribute("sid");
             //std::string sid = GetAttribute("sid");
-             //= mReader->getAttributeValue(attrSID);
+            //= mReader->getAttributeValue(attrSID);
             pEffect.mParams[sid] = EffectParam();
             pEffect.mParams[sid] = EffectParam();
             ReadEffectParam(currentNode, pEffect.mParams[sid]);
             ReadEffectParam(currentNode, pEffect.mParams[sid]);
-        } else if (currentName == "technique" || currentName == "extra" ) {
+        } else if (currentName == "technique" || currentName == "extra") {
             // just syntactic sugar
             // just syntactic sugar
         } else if (mFormat == FV_1_4_n && currentName == "image") {
         } else if (mFormat == FV_1_4_n && currentName == "image") {
             // read ID. Another entry which is "optional" by design but obligatory in reality
             // read ID. Another entry which is "optional" by design but obligatory in reality
@@ -1196,15 +1195,15 @@ void ColladaParser::ReadSamplerProperties(XmlNode &node, Sampler &out) {
             out.mMirrorU = ReadBoolFromTextContent();
             out.mMirrorU = ReadBoolFromTextContent();
         } else if (currentName == "mirrorV") {
         } else if (currentName == "mirrorV") {
             out.mMirrorV = ReadBoolFromTextContent();
             out.mMirrorV = ReadBoolFromTextContent();
-        } else if (currentName  == "repeatU") {
+        } else if (currentName == "repeatU") {
             out.mTransform.mScaling.x = ReadFloatFromTextContent();
             out.mTransform.mScaling.x = ReadFloatFromTextContent();
         } else if (currentName == "repeatV") {
         } else if (currentName == "repeatV") {
             out.mTransform.mScaling.y = ReadFloatFromTextContent();
             out.mTransform.mScaling.y = ReadFloatFromTextContent();
-        } else if (currentName  == "offsetU") {
+        } else if (currentName == "offsetU") {
             out.mTransform.mTranslation.x = ReadFloatFromTextContent();
             out.mTransform.mTranslation.x = ReadFloatFromTextContent();
-        } else if (currentName  == "offsetV") {
+        } else if (currentName == "offsetV") {
             out.mTransform.mTranslation.y = ReadFloatFromTextContent();
             out.mTransform.mTranslation.y = ReadFloatFromTextContent();
-        } else if (currentName  == "rotateUV") {
+        } else if (currentName == "rotateUV") {
             out.mTransform.mRotation = ReadFloatFromTextContent();
             out.mTransform.mRotation = ReadFloatFromTextContent();
         } else if (currentName == "blend_mode") {
         } else if (currentName == "blend_mode") {
 
 
@@ -1225,12 +1224,12 @@ void ColladaParser::ReadSamplerProperties(XmlNode &node, Sampler &out) {
         // -------------------------------------------------------
         // -------------------------------------------------------
         else if (currentName == "weighting") {
         else if (currentName == "weighting") {
             out.mWeighting = ReadFloatFromTextContent();
             out.mWeighting = ReadFloatFromTextContent();
-        } else if (currentName  == "mix_with_previous_layer") {
+        } else if (currentName == "mix_with_previous_layer") {
             out.mMixWithPrevious = ReadFloatFromTextContent();
             out.mMixWithPrevious = ReadFloatFromTextContent();
         }
         }
         // MAX3D extensions
         // MAX3D extensions
         // -------------------------------------------------------
         // -------------------------------------------------------
-        else if (currentName  == "amount") {
+        else if (currentName == "amount") {
             out.mWeighting = ReadFloatFromTextContent();
             out.mWeighting = ReadFloatFromTextContent();
         }
         }
     }
     }
@@ -1262,84 +1261,26 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p
             SkipSpacesAndLineEnd(&content);
             SkipSpacesAndLineEnd(&content);
         } else if (currentName == "texture") {
         } else if (currentName == "texture") {
             // get name of source texture/sampler
             // get name of source texture/sampler
-            int attrTex = GetAttribute("texture");
-            pSampler.mName = mReader->getAttributeValue(attrTex);
+            XmlParser::getStdStrAttribute(currentNode, "texture", pSampler.mName);
 
 
             // get name of UV source channel. Specification demands it to be there, but some exporters
             // get name of UV source channel. Specification demands it to be there, but some exporters
             // don't write it. It will be the default UV channel in case it's missing.
             // don't write it. It will be the default UV channel in case it's missing.
-            attrTex = TestAttribute("texcoord");
-            if (attrTex >= 0)
-                pSampler.mUVChannel = mReader->getAttributeValue(attrTex);
-            //SkipElement();
+            XmlParser::getStdStrAttribute(currentNode, "texcoord", pSampler.mUVChannel);
 
 
             // as we've read texture, the color needs to be 1,1,1,1
             // as we've read texture, the color needs to be 1,1,1,1
             pColor = aiColor4D(1.f, 1.f, 1.f, 1.f);
             pColor = aiColor4D(1.f, 1.f, 1.f, 1.f);
-        } else if (currentName == "technique" ) {
-            const int _profile = GetAttribute("profile");
-            const char *profile = mReader->getAttributeValue(_profile);
+        } else if (currentName == "technique") {
+            std::string profile;
+            XmlParser::getStdStrAttribute(currentNode, "profile", profile);
+            //const int _profile = GetAttribute("profile");
+            //const char *profile = mReader->getAttributeValue(_profile);
 
 
             // Some extensions are quite useful ... ReadSamplerProperties processes
             // Some extensions are quite useful ... ReadSamplerProperties processes
             // several extensions in MAYA, OKINO and MAX3D profiles.
             // several extensions in MAYA, OKINO and MAX3D profiles.
-            if (!::strcmp(profile, "MAYA") || !::strcmp(profile, "MAX3D") || !::strcmp(profile, "OKINO")) {
+            if (!::strcmp(profile.c_str(), "MAYA") || !::strcmp(profile.c_str(), "MAX3D") || !::strcmp(profile.c_str(), "OKINO")) {
                 // get more information on this sampler
                 // get more information on this sampler
-                ReadSamplerProperties(pSampler);
+                ReadSamplerProperties(currentNode, pSampler);
             }
             }
-        } 
-    }
-
-    // Save current element name
-    const std::string curElem = mReader->getNodeName();
-
-    while (mReader->read()) {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
-            if (IsElement("color")) {
-                // text content contains 4 floats
-                const char *content = GetTextContent();
-
-                content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.r);
-                SkipSpacesAndLineEnd(&content);
-
-                content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.g);
-                SkipSpacesAndLineEnd(&content);
-
-                content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.b);
-                SkipSpacesAndLineEnd(&content);
-
-                content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.a);
-                SkipSpacesAndLineEnd(&content);
-                TestClosing("color");
-            } else if (IsElement("texture")) {
-                // get name of source texture/sampler
-                int attrTex = GetAttribute("texture");
-                pSampler.mName = mReader->getAttributeValue(attrTex);
-
-                // get name of UV source channel. Specification demands it to be there, but some exporters
-                // don't write it. It will be the default UV channel in case it's missing.
-                attrTex = TestAttribute("texcoord");
-                if (attrTex >= 0)
-                    pSampler.mUVChannel = mReader->getAttributeValue(attrTex);
-                //SkipElement();
-
-                // as we've read texture, the color needs to be 1,1,1,1
-                pColor = aiColor4D(1.f, 1.f, 1.f, 1.f);
-            } else if (IsElement("technique")) {
-                const int _profile = GetAttribute("profile");
-                const char *profile = mReader->getAttributeValue(_profile);
-
-                // Some extensions are quite useful ... ReadSamplerProperties processes
-                // several extensions in MAYA, OKINO and MAX3D profiles.
-                if (!::strcmp(profile, "MAYA") || !::strcmp(profile, "MAX3D") || !::strcmp(profile, "OKINO")) {
-                    // get more information on this sampler
-                    ReadSamplerProperties(pSampler);
-                } else
-                    SkipElement();
-            } else if (!IsElement("extra")) {
-                // ignore the rest
-                SkipElement();
-            }
-        } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
-            if (mReader->getNodeName() == curElem)
-                break;
         }
         }
     }
     }
 }
 }
@@ -1347,67 +1288,41 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads an effect entry containing a float
 // Reads an effect entry containing a float
 void ColladaParser::ReadEffectFloat(XmlNode &node, ai_real &pFloat) {
 void ColladaParser::ReadEffectFloat(XmlNode &node, ai_real &pFloat) {
-    while (mReader->read()) {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
-            if (IsElement("float")) {
-                // text content contains a single floats
-                const char *content = GetTextContent();
-                content = fast_atoreal_move<ai_real>(content, pFloat);
-                SkipSpacesAndLineEnd(&content);
-
-                TestClosing("float");
-            } else {
-                // ignore the rest
-                SkipElement();
-            }
-        } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
-            break;
-        }
+    pFloat = 0.f;
+    if (node.name() == "float") {
+        XmlParser::getFloatAttribute(node, "float", pFloat);
     }
     }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads an effect parameter specification of any kind
 // Reads an effect parameter specification of any kind
 void ColladaParser::ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam) {
 void ColladaParser::ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam) {
-    while (mReader->read()) {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
-            if (IsElement("surface")) {
-                // image ID given inside <init_from> tags
-                TestOpening("init_from");
-                const char *content = GetTextContent();
-                pParam.mType = Param_Surface;
-                pParam.mReference = content;
-                TestClosing("init_from");
-
-                // don't care for remaining stuff
-                SkipElement("surface");
-            } else if (IsElement("sampler2D") && (FV_1_4_n == mFormat || FV_1_3_n == mFormat)) {
-                // surface ID is given inside <source> tags
-                TestOpening("source");
-                const char *content = GetTextContent();
-                pParam.mType = Param_Sampler;
-                pParam.mReference = content;
-                TestClosing("source");
-
-                // don't care for remaining stuff
-                SkipElement("sampler2D");
-            } else if (IsElement("sampler2D")) {
-                // surface ID is given inside <instance_image> tags
-                TestOpening("instance_image");
-                int attrURL = GetAttribute("url");
-                const char *url = mReader->getAttributeValue(attrURL);
-                if (url[0] != '#')
-                    ThrowException("Unsupported URL format in instance_image");
-                url++;
-                pParam.mType = Param_Sampler;
-                pParam.mReference = url;
-                SkipElement("sampler2D");
-            } else {
-                // ignore unknown element
-                SkipElement();
-            }
-        } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
-            break;
+    if (node.empty()) {
+        return;
+    }
+
+    for (XmlNode &currentNode : node.children()) {
+        const std::string &currentName = currentNode.name();
+        if (currentName == "surface") {
+            // image ID given inside <init_from> tags
+            const char *content = currentNode.value();
+            pParam.mType = Param_Surface;
+            pParam.mReference = content;
+
+            // don't care for remaining stuff
+        } else if (currentName == "sampler2D" && (FV_1_4_n == mFormat || FV_1_3_n == mFormat)) {
+            // surface ID is given inside <source> tags
+            const char *content = currentNode.value();
+            pParam.mType = Param_Sampler;
+            pParam.mReference = content;
+        } else if (currentName == "sampler2D") {
+            // surface ID is given inside <instance_image> tags
+            std::string url;
+            XmlParser::getStdStrAttribute(currentNode, "url", url);
+            if (url[0] != '#')
+                ThrowException("Unsupported URL format in instance_image");
+            pParam.mType = Param_Sampler;
+            pParam.mReference = url.c_str() + 1;
         }
         }
     }
     }
 }
 }
@@ -1418,44 +1333,25 @@ void ColladaParser::ReadGeometryLibrary(XmlNode &node) {
     if (node.empty()) {
     if (node.empty()) {
         return;
         return;
     }
     }
-    /*if (mReader->isEmptyElement())
-        return;*/
-
-    while (mReader->read()) {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
-            if (IsElement("geometry")) {
-                // read ID. Another entry which is "optional" by design but obligatory in reality
-                int indexID = GetAttribute("id");
-                std::string id = mReader->getAttributeValue(indexID);
+    for (XmlNode &currentNode : node.children()) {
+        const std::string &currentName = currentNode.name();
+        if (currentName == "geometry") {
+            // read ID. Another entry which is "optional" by design but obligatory in reality
 
 
-                // create a mesh and store it in the library under its (resolved) ID
-                // Skip and warn if ID is not unique
-                if (mMeshLibrary.find(id) == mMeshLibrary.cend()) {
-                    std::unique_ptr<Mesh> mesh(new Mesh(id));
+            std::string id;
+            XmlParser::getStdStrAttribute(currentNode, "id", id);
+            // create a mesh and store it in the library under its (resolved) ID
+            // Skip and warn if ID is not unique
+            if (mMeshLibrary.find(id) == mMeshLibrary.cend()) {
+                std::unique_ptr<Mesh> mesh(new Mesh(id));
 
 
-                    // read the mesh name if it exists
-                    const int nameIndex = TestAttribute("name");
-                    if (nameIndex != -1) {
-                        mesh->mName = mReader->getAttributeValue(nameIndex);
-                    }
+                XmlParser::getStdStrAttribute(currentNode, "name", mesh->mName);
 
 
-                    // read on from there
-                    ReadGeometry(*mesh);
-                    // Read successfully, add to library
-                    mMeshLibrary.insert({ id, mesh.release() });
-                } else {
-                    ASSIMP_LOG_ERROR_F("Collada: Skipped duplicate geometry id: \"", id, "\"");
-                    SkipElement();
-                }
-            } else {
-                // ignore the rest
-                SkipElement();
+                // read on from there
+                ReadGeometry(currentNode, *mesh);
+                // Read successfully, add to library
+                mMeshLibrary.insert({ id, mesh.release() });
             }
             }
-        } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
-            if (strcmp(mReader->getNodeName(), "library_geometries") != 0)
-                ThrowException("Expected end of <library_geometries> element.");
-
-            break;
         }
         }
     }
     }
 }
 }
@@ -1466,23 +1362,10 @@ void ColladaParser::ReadGeometry(XmlNode &node, Collada::Mesh &pMesh) {
     if (node.empty()) {
     if (node.empty()) {
         return;
         return;
     }
     }
-    /*if (mReader->isEmptyElement())
-        return;*/
-
-    while (mReader->read()) {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
-            if (IsElement("mesh")) {
-                // read on from there
-                ReadMesh(pMesh);
-            } else {
-                // ignore the rest
-                SkipElement();
-            }
-        } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
-            if (strcmp(mReader->getNodeName(), "geometry") != 0)
-                ThrowException("Expected end of <geometry> element.");
-
-            break;
+    for (XmlNode &currentNode : node.children()) {
+        const std::string &currentName = currentNode.name();
+        if (currentName == "mesh") {
+            ReadMesh(currentNode, pMesh);
         }
         }
     }
     }
 }
 }
@@ -1493,34 +1376,15 @@ void ColladaParser::ReadMesh(XmlNode &node, Mesh &pMesh) {
     if (node.empty()) {
     if (node.empty()) {
         return;
         return;
     }
     }
-    /*if (mReader->isEmptyElement())
-        return;*/
 
 
-    while (mReader->read()) {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
-            if (IsElement("source")) {
-                // we have professionals dealing with this
-                ReadSource();
-            } else if (IsElement("vertices")) {
-                // read per-vertex mesh data
-                ReadVertexData(pMesh);
-            } else if (IsElement("triangles") || IsElement("lines") || IsElement("linestrips") || IsElement("polygons") || IsElement("polylist") || IsElement("trifans") || IsElement("tristrips")) {
-                // read per-index mesh data and faces setup
-                ReadIndexData(pMesh);
-            } else {
-                // ignore the restf
-                SkipElement();
-            }
-        } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
-            if (strcmp(mReader->getNodeName(), "technique_common") == 0) {
-                // end of another meaningless element - read over it
-            } else if (strcmp(mReader->getNodeName(), "mesh") == 0) {
-                // end of <mesh> element - we're done here
-                break;
-            } else {
-                // everything else should be punished
-                ThrowException("Expected end of <mesh> element.");
-            }
+    for (XmlNode &currentNode : node.children()) {
+        const std::string &currentName = currentNode.name();
+        if (currentName == "source") {
+            ReadSource(currentNode);
+        } else if (currentName == "vertices") {
+            ReadVertexData(currentNode, pMesh);
+        } else if (currentName == "triangles" || currentName == "lines" || currentName == "linestrips" || currentName == "polygons" || currentName == "polylist" || currentName == "trifans" || currentName == "tristrips") {
+            ReadIndexData(currentNode, pMesh);
         }
         }
     }
     }
 }
 }
@@ -1528,31 +1392,20 @@ void ColladaParser::ReadMesh(XmlNode &node, Mesh &pMesh) {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads a source element
 // Reads a source element
 void ColladaParser::ReadSource(XmlNode &node) {
 void ColladaParser::ReadSource(XmlNode &node) {
-    int indexID = GetAttribute("id");
-    std::string sourceID = mReader->getAttributeValue(indexID);
+    if (node.empty()) {
+        return;
+    }
 
 
-    while (mReader->read()) {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
-            if (IsElement("float_array") || IsElement("IDREF_array") || IsElement("Name_array")) {
-                ReadDataArray();
-            } else if (IsElement("technique_common")) {
-                // I don't care for your profiles
-            } else if (IsElement("accessor")) {
-                ReadAccessor(sourceID);
-            } else {
-                // ignore the rest
-                SkipElement();
-            }
-        } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
-            if (strcmp(mReader->getNodeName(), "source") == 0) {
-                // end of <source> - we're done
-                break;
-            } else if (strcmp(mReader->getNodeName(), "technique_common") == 0) {
-                // end of another meaningless element - read over it
-            } else {
-                // everything else should be punished
-                ThrowException("Expected end of <source> element.");
-            }
+    std::string sourceID;
+    XmlParser::getStdStrAttribute(node, "id", sourceID);
+    for (XmlNode &currentNode : node.children()) {
+        const std::string &currentName = currentNode.name();
+        if (currentName == "float_array" || currentName == "IDREF_array" || currentName == "Name_array") {
+            ReadDataArray(currentNode);
+        } else if (currentName == "technique_common") {
+            // I don't care for your profiles
+        } else if (currentName == "accessor") {
+            ReadAccessor(currentNode, sourceID);
         }
         }
     }
     }
 }
 }
@@ -1560,16 +1413,16 @@ void ColladaParser::ReadSource(XmlNode &node) {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads a data array holding a number of floats, and stores it in the global library
 // Reads a data array holding a number of floats, and stores it in the global library
 void ColladaParser::ReadDataArray(XmlNode &node) {
 void ColladaParser::ReadDataArray(XmlNode &node) {
-    std::string elmName = mReader->getNodeName();
-    bool isStringArray = (elmName == "IDREF_array" || elmName == "Name_array");
-    bool isEmptyElement = mReader->isEmptyElement();
+    std::string name = node.name();
+    bool isStringArray = (name == "IDREF_array" || name == "Name_array");
+    bool isEmptyElement = node.empty();
 
 
     // read attributes
     // read attributes
-    int indexID = GetAttribute("id");
-    std::string id = mReader->getAttributeValue(indexID);
-    int indexCount = GetAttribute("count");
-    unsigned int count = (unsigned int)mReader->getAttributeValueAsInt(indexCount);
-    const char *content = TestTextContent();
+    std::string id;
+    XmlParser::getStdStrAttribute(node, "id", id);
+    int count;
+    XmlParser::getIntAttribute(node, "count", count);
+    const char *content = node.value();
 
 
     // read values and store inside an array in the data library
     // read values and store inside an array in the data library
     mDataLibrary[id] = Data();
     mDataLibrary[id] = Data();
@@ -1609,113 +1462,98 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
             }
             }
         }
         }
     }
     }
-
-    // test for closing tag
-    if (!isEmptyElement)
-        TestClosing(elmName.c_str());
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads an accessor and stores it in the global library
 // Reads an accessor and stores it in the global library
 void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) {
 void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) {
     // read accessor attributes
     // read accessor attributes
-    int attrSource = GetAttribute("source");
-    const char *source = mReader->getAttributeValue(attrSource);
+    std::string source;
+    XmlParser::getStdStrAttribute(node, "source", source);
     if (source[0] != '#')
     if (source[0] != '#')
         ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of <accessor> element.");
         ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of <accessor> element.");
-    int attrCount = GetAttribute("count");
-    unsigned int count = (unsigned int)mReader->getAttributeValueAsInt(attrCount);
-    int attrOffset = TestAttribute("offset");
+    int count;
+    XmlParser::getIntAttribute(node, "count", count);
+
     unsigned int offset = 0;
     unsigned int offset = 0;
-    if (attrOffset > -1)
-        offset = (unsigned int)mReader->getAttributeValueAsInt(attrOffset);
-    int attrStride = TestAttribute("stride");
+    if (XmlParser::hasAttribute(node, "offset")) {
+        XmlParser::getUIntAttribute(node, "offset", offset);
+    }
     unsigned int stride = 1;
     unsigned int stride = 1;
-    if (attrStride > -1)
-        stride = (unsigned int)mReader->getAttributeValueAsInt(attrStride);
-
+    if (XmlParser::hasAttribute(node, "stride")) {
+        XmlParser::getUIntAttribute(node, "stride", stride);
+    }
     // store in the library under the given ID
     // store in the library under the given ID
     mAccessorLibrary[pID] = Accessor();
     mAccessorLibrary[pID] = Accessor();
     Accessor &acc = mAccessorLibrary[pID];
     Accessor &acc = mAccessorLibrary[pID];
     acc.mCount = count;
     acc.mCount = count;
     acc.mOffset = offset;
     acc.mOffset = offset;
     acc.mStride = stride;
     acc.mStride = stride;
-    acc.mSource = source + 1; // ignore the leading '#'
+    acc.mSource = source.c_str() + 1; // ignore the leading '#'
     acc.mSize = 0; // gets incremented with every param
     acc.mSize = 0; // gets incremented with every param
 
 
-    // and read the components
-    while (mReader->read()) {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
-            if (IsElement("param")) {
-                // read data param
-                int attrName = TestAttribute("name");
-                std::string name;
-                if (attrName > -1) {
-                    name = mReader->getAttributeValue(attrName);
-
-                    // analyse for common type components and store it's sub-offset in the corresponding field
-
-                    /* Cartesian coordinates */
-                    if (name == "X")
-                        acc.mSubOffset[0] = acc.mParams.size();
-                    else if (name == "Y")
-                        acc.mSubOffset[1] = acc.mParams.size();
-                    else if (name == "Z")
-                        acc.mSubOffset[2] = acc.mParams.size();
-
-                    /* RGBA colors */
-                    else if (name == "R")
-                        acc.mSubOffset[0] = acc.mParams.size();
-                    else if (name == "G")
-                        acc.mSubOffset[1] = acc.mParams.size();
-                    else if (name == "B")
-                        acc.mSubOffset[2] = acc.mParams.size();
-                    else if (name == "A")
-                        acc.mSubOffset[3] = acc.mParams.size();
-
-                    /* UVWQ (STPQ) texture coordinates */
-                    else if (name == "S")
-                        acc.mSubOffset[0] = acc.mParams.size();
-                    else if (name == "T")
-                        acc.mSubOffset[1] = acc.mParams.size();
-                    else if (name == "P")
-                        acc.mSubOffset[2] = acc.mParams.size();
-                    //  else if( name == "Q") acc.mSubOffset[3] = acc.mParams.size();
-                    /* 4D uv coordinates are not supported in Assimp */
-
-                    /* Generic extra data, interpreted as UV data, too*/
-                    else if (name == "U")
-                        acc.mSubOffset[0] = acc.mParams.size();
-                    else if (name == "V")
-                        acc.mSubOffset[1] = acc.mParams.size();
-                    //else
-                    //  DefaultLogger::get()->warn( format() << "Unknown accessor parameter \"" << name << "\". Ignoring data channel." );
-                }
-
+    for (XmlNode &currentNode : node.children()) {
+        const std::string &currentName = currentNode.name();
+        if (currentName == "param") {
+            // read data param
+            //int attrName = TestAttribute("name");
+            std::string name;
+            if (XmlParser::hasAttribute(currentNode, "name")) {
+                XmlParser::getStdStrAttribute(currentNode, "name", name);
+                //name = mReader->getAttributeValue(attrName);
+
+                // analyse for common type components and store it's sub-offset in the corresponding field
+
+                /* Cartesian coordinates */
+                if (name == "X")
+                    acc.mSubOffset[0] = acc.mParams.size();
+                else if (name == "Y")
+                    acc.mSubOffset[1] = acc.mParams.size();
+                else if (name == "Z")
+                    acc.mSubOffset[2] = acc.mParams.size();
+
+                /* RGBA colors */
+                else if (name == "R")
+                    acc.mSubOffset[0] = acc.mParams.size();
+                else if (name == "G")
+                    acc.mSubOffset[1] = acc.mParams.size();
+                else if (name == "B")
+                    acc.mSubOffset[2] = acc.mParams.size();
+                else if (name == "A")
+                    acc.mSubOffset[3] = acc.mParams.size();
+
+                /* UVWQ (STPQ) texture coordinates */
+                else if (name == "S")
+                    acc.mSubOffset[0] = acc.mParams.size();
+                else if (name == "T")
+                    acc.mSubOffset[1] = acc.mParams.size();
+                else if (name == "P")
+                    acc.mSubOffset[2] = acc.mParams.size();
+                //  else if( name == "Q") acc.mSubOffset[3] = acc.mParams.size();
+                /* 4D uv coordinates are not supported in Assimp */
+
+                /* Generic extra data, interpreted as UV data, too*/
+                else if (name == "U")
+                    acc.mSubOffset[0] = acc.mParams.size();
+                else if (name == "V")
+                    acc.mSubOffset[1] = acc.mParams.size();
+                //else
+                //  DefaultLogger::get()->warn( format() << "Unknown accessor parameter \"" << name << "\". Ignoring data channel." );
+            }
+            if (XmlParser::hasAttribute(currentNode, "type")) {
                 // read data type
                 // read data type
-                int attrType = TestAttribute("type");
-                if (attrType > -1) {
-                    // for the moment we only distinguish between a 4x4 matrix and anything else.
-                    // TODO: (thom) I don't have a spec here at work. Check if there are other multi-value types
-                    // which should be tested for here.
-                    std::string type = mReader->getAttributeValue(attrType);
-                    if (type == "float4x4")
-                        acc.mSize += 16;
-                    else
-                        acc.mSize += 1;
-                }
-
-                acc.mParams.push_back(name);
-
-                // skip remaining stuff of this element, if any
-                SkipElement();
-            } else {
-                ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <accessor>");
+                // TODO: (thom) I don't have a spec here at work. Check if there are other multi-value types
+                // which should be tested for here.
+                std::string type;
+                
+                XmlParser::getStdStrAttribute(currentNode, "type", type);
+                if (type == "float4x4")
+                    acc.mSize += 16;
+                else
+                    acc.mSize += 1;
             }
             }
-        } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
-            if (strcmp(mReader->getNodeName(), "accessor") != 0)
-                ThrowException("Expected end of <accessor> element.");
-            break;
+
+            acc.mParams.push_back(name);
         }
         }
     }
     }
 }
 }
@@ -1724,22 +1562,13 @@ void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) {
 // Reads input declarations of per-vertex mesh data into the given mesh
 // Reads input declarations of per-vertex mesh data into the given mesh
 void ColladaParser::ReadVertexData(XmlNode &node, Mesh &pMesh) {
 void ColladaParser::ReadVertexData(XmlNode &node, Mesh &pMesh) {
     // extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about
     // extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about
-    int attrID = GetAttribute("id");
-    pMesh.mVertexID = mReader->getAttributeValue(attrID);
-
-    // a number of <input> elements
-    while (mReader->read()) {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
-            if (IsElement("input")) {
-                ReadInputChannel(pMesh.mPerVertexData);
-            } else {
-                ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <vertices>");
-            }
-        } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
-            if (strcmp(mReader->getNodeName(), "vertices") != 0)
-                ThrowException("Expected end of <vertices> element.");
-
-            break;
+    XmlParser::getStdStrAttribute(node, "id", pMesh.mVertexID);
+    for (XmlNode &currentNode : node.children()) {
+        const std::string &currentName = currentNode.name();
+        if (currentName == "input" ) {
+            ReadInputChannel(currentNode, pMesh.mPerVertexData);
+        } else {
+            ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <vertices>");
         }
         }
     }
     }
 }
 }
@@ -1750,80 +1579,76 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
     std::vector<size_t> vcount;
     std::vector<size_t> vcount;
     std::vector<InputChannel> perIndexData;
     std::vector<InputChannel> perIndexData;
 
 
+    XmlParser::getIntAttribute(node, "count", (int) numPrimitives);
     // read primitive count from the attribute
     // read primitive count from the attribute
-    int attrCount = GetAttribute("count");
-    size_t numPrimitives = (size_t)mReader->getAttributeValueAsInt(attrCount);
+    //int attrCount = GetAttribute("count");
+    //size_t numPrimitives = (size_t)mReader->getAttributeValueAsInt(attrCount);
     // some mesh types (e.g. tristrips) don't specify primitive count upfront,
     // some mesh types (e.g. tristrips) don't specify primitive count upfront,
     // so we need to sum up the actual number of primitives while we read the <p>-tags
     // so we need to sum up the actual number of primitives while we read the <p>-tags
     size_t actualPrimitives = 0;
     size_t actualPrimitives = 0;
-
-    // material subgroup
-    int attrMaterial = TestAttribute("material");
     SubMesh subgroup;
     SubMesh subgroup;
-    if (attrMaterial > -1)
-        subgroup.mMaterial = mReader->getAttributeValue(attrMaterial);
+    if (XmlParser::hasAttribute("material")) {
+        XmlParser::getStdStrAttribute(node, "material", subgroup.mMaterial);
+    }
+    // material subgroup
+//    int attrMaterial = TestAttribute("material");
+    
+    //if (attrMaterial > -1)
+      //  subgroup.mMaterial = mReader->getAttributeValue(attrMaterial);
 
 
     // distinguish between polys and triangles
     // distinguish between polys and triangles
-    std::string elementName = mReader->getNodeName();
+    std::string elementName = node.name();
     PrimitiveType primType = Prim_Invalid;
     PrimitiveType primType = Prim_Invalid;
-    if (IsElement("lines"))
+    if (elementName == "lines")
         primType = Prim_Lines;
         primType = Prim_Lines;
-    else if (IsElement("linestrips"))
+    else if (elementName == "linestrips")
         primType = Prim_LineStrip;
         primType = Prim_LineStrip;
-    else if (IsElement("polygons"))
+    else if (elementName == "polygons")
         primType = Prim_Polygon;
         primType = Prim_Polygon;
-    else if (IsElement("polylist"))
+    else if (elementName == "polylist")
         primType = Prim_Polylist;
         primType = Prim_Polylist;
-    else if (IsElement("triangles"))
+    else if (elementName == "triangles")
         primType = Prim_Triangles;
         primType = Prim_Triangles;
-    else if (IsElement("trifans"))
+    else if (elementName == "trifans")
         primType = Prim_TriFans;
         primType = Prim_TriFans;
-    else if (IsElement("tristrips"))
+    else if (elementName == "tristrips")
         primType = Prim_TriStrips;
         primType = Prim_TriStrips;
 
 
     ai_assert(primType != Prim_Invalid);
     ai_assert(primType != Prim_Invalid);
 
 
     // also a number of <input> elements, but in addition a <p> primitive collection and probably index counts for all primitives
     // also a number of <input> elements, but in addition a <p> primitive collection and probably index counts for all primitives
-    while (mReader->read()) {
-        if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
-            if (IsElement("input")) {
-                ReadInputChannel(perIndexData);
-            } else if (IsElement("vcount")) {
-                if (!mReader->isEmptyElement()) {
-                    if (numPrimitives) // It is possible to define a mesh without any primitives
-                    {
-                        // case <polylist> - specifies the number of indices for each polygon
-                        const char *content = GetTextContent();
-                        vcount.reserve(numPrimitives);
-                        for (unsigned int a = 0; a < numPrimitives; a++) {
-                            if (*content == 0)
-                                ThrowException("Expected more values while reading <vcount> contents.");
-                            // read a number
-                            vcount.push_back((size_t)strtoul10(content, &content));
-                            // skip whitespace after it
-                            SkipSpacesAndLineEnd(&content);
-                        }
+    for (XmlNode &currentNode : node.children()) {
+        const std::string &currentName = currentNode.name();
+        if (currentName == "input") {
+            ReadInputChannel(currentNode, perIndexData);
+        } else if (currentName == "vcount") {
+            if (!currentNode.empty()) {
+                if (numPrimitives) // It is possible to define a mesh without any primitives
+                {
+                    // case <polylist> - specifies the number of indices for each polygon
+                    const char *content = GetTextContent();
+                    vcount.reserve(numPrimitives);
+                    for (unsigned int a = 0; a < numPrimitives; a++) {
+                        if (*content == 0)
+                            ThrowException("Expected more values while reading <vcount> contents.");
+                        // read a number
+                        vcount.push_back((size_t)strtoul10(content, &content));
+                        // skip whitespace after it
+                        SkipSpacesAndLineEnd(&content);
                     }
                     }
-
-                    TestClosing("vcount");
                 }
                 }
-            } else if (IsElement("p")) {
-                if (!mReader->isEmptyElement()) {
-                    // now here the actual fun starts - these are the indices to construct the mesh data from
-                    actualPrimitives += ReadPrimitives(pMesh, perIndexData, numPrimitives, vcount, primType);
-                }
-            } else if (IsElement("extra")) {
-                SkipElement("extra");
-            } else if (IsElement("ph")) {
-                SkipElement("ph");
-            } else {
-                ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">");
             }
             }
-        } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
-            if (mReader->getNodeName() != elementName)
-                ThrowException(format() << "Expected end of <" << elementName << "> element.");
-
-            break;
+        } else if (currentName == "p") {
+            if (!currentNode.empty()) {
+                // now here the actual fun starts - these are the indices to construct the mesh data from
+                actualPrimitives += ReadPrimitives(currentNode, pMesh, perIndexData, numPrimitives, vcount, primType);
+            }
+        } else if (currentName == "extra") {
+            // skip
+        } else if (currentName ==  "ph") {
+            // skip
+        } else {
+            ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">");
         }
         }
     }
     }
 
 
@@ -1845,21 +1670,28 @@ void ColladaParser::ReadInputChannel(XmlNode &node, std::vector<InputChannel> &p
     InputChannel channel;
     InputChannel channel;
 
 
     // read semantic
     // read semantic
-    int attrSemantic = GetAttribute("semantic");
-    std::string semantic = mReader->getAttributeValue(attrSemantic);
+    std::string semantic;
+    XmlParser::getStdStrAttribute(node, "semantic", semantic);
+    //int attrSemantic = GetAttribute("semantic");
+    //std::string semantic = mReader->getAttributeValue(attrSemantic);
     channel.mType = GetTypeForSemantic(semantic);
     channel.mType = GetTypeForSemantic(semantic);
 
 
     // read source
     // read source
-    int attrSource = GetAttribute("source");
-    const char *source = mReader->getAttributeValue(attrSource);
+    std::string source;
+    XmlParser::getStdStrAttribute(node, "source", source);
+    //int attrSource = GetAttribute("source");
+    //const char *source = mReader->getAttributeValue(attrSource);
     if (source[0] != '#')
     if (source[0] != '#')
         ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of <input> element.");
         ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of <input> element.");
-    channel.mAccessor = source + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only
+    channel.mAccessor = source.c_str() + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only
 
 
     // read index offset, if per-index <input>
     // read index offset, if per-index <input>
-    int attrOffset = TestAttribute("offset");
-    if (attrOffset > -1)
-        channel.mOffset = mReader->getAttributeValueAsInt(attrOffset);
+    if (XmlParser::hasAttribute("offset")) {
+        XmlParser::getStdStrAttribute(node, "offset", channel.mOffset);
+    } 
+    //int attrOffset = TestAttribute("offset");
+    //if (attrOffset > -1)
+//        channel.mOffset = mReader->getAttributeValueAsInt(attrOffset);
 
 
     // read set if texture coordinates
     // read set if texture coordinates
     if (channel.mType == IT_Texcoord || channel.mType == IT_Color) {
     if (channel.mType == IT_Texcoord || channel.mType == IT_Color) {

+ 21 - 0
include/assimp/XmlParser.h

@@ -158,6 +158,16 @@ public:
         return !attr.empty();
         return !attr.empty();
     }
     }
 
 
+    static inline bool getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val) {
+        pugi::xml_attribute attr = xmlNode.attribute(name);
+        if (attr.empty()) {
+            return false;
+        }
+
+        val = attr.as_uint();
+        return true;
+    }
+
     static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val ) {
     static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val ) {
         pugi::xml_attribute attr = xmlNode.attribute(name);
         pugi::xml_attribute attr = xmlNode.attribute(name);
         if (attr.empty()) {
         if (attr.empty()) {
@@ -168,6 +178,17 @@ public:
         return true;
         return true;
     }
     }
 
 
+    static inline bool getFloatAttribute( XmlNode &xmlNode, const char *name, float &val ) {
+        pugi::xml_attribute attr = xmlNode.attribute(name);
+        if (attr.empty()) {
+            return false;
+        }
+
+        val = attr.as_float();
+        return true;
+
+    }
+
     static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) {
     static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) {
         pugi::xml_attribute attr = xmlNode.attribute(name);
         pugi::xml_attribute attr = xmlNode.attribute(name);
         if (attr.empty()) {
         if (attr.empty()) {