2
0
Эх сурвалжийг харах

Merge branch 'master' into slow_xml_load

Kim Kulling 6 жил өмнө
parent
commit
fe4fd00a82
34 өөрчлөгдсөн 2604 нэмэгдсэн , 144 устгасан
  1. 7 0
      .gitignore
  2. 6 6
      code/FBXBinaryTokenizer.cpp
  3. 55 46
      code/FBXConverter.cpp
  4. 7 5
      code/FBXConverter.h
  5. 1 1
      code/FBXDocument.h
  6. 1 1
      code/FBXImporter.cpp
  7. 33 9
      code/FBXMaterial.cpp
  8. 3 3
      code/FBXParser.cpp
  9. 6 6
      code/FBXTokenizer.h
  10. 48 29
      code/FBXUtil.cpp
  11. 11 3
      code/FBXUtil.h
  12. 1 1
      code/Importer/IFC/IFCBoolean.cpp
  13. 1 0
      code/STLLoader.cpp
  14. 2 2
      code/res/resource.h
  15. 1 1
      contrib/irrXML/irrString.h
  16. 1 1
      contrib/poly2tri/AUTHORS
  17. 2 2
      contrib/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs
  18. 1 1
      contrib/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs
  19. 1 1
      contrib/zlib/contrib/dotzlib/DotZLib/CodecBase.cs
  20. 1 1
      contrib/zlib/contrib/dotzlib/DotZLib/Deflater.cs
  21. 1 1
      contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.cs
  22. 1 1
      contrib/zlib/contrib/dotzlib/DotZLib/GZipStream.cs
  23. 1 1
      contrib/zlib/contrib/dotzlib/DotZLib/Inflater.cs
  24. 1 1
      include/assimp/defs.h
  25. 2 1
      port/PyAssimp/pyassimp/core.py
  26. 3 3
      port/PyAssimp/pyassimp/helper.py
  27. 571 0
      test/models/FBX/cubes_nonames.fbx
  28. 571 0
      test/models/FBX/cubes_with_mirroring_and_pivot.fbx
  29. 571 0
      test/models/FBX/cubes_with_names.fbx
  30. 534 0
      test/models/FBX/embedded_ascii/box_embedded_texture_fragmented.fbx
  31. 137 0
      test/unit/utFBXImporterExporter.cpp
  32. 7 2
      tools/assimp_cmd/Info.cpp
  33. 2 2
      tools/assimp_view/stdafx.cpp
  34. 13 13
      tools/assimp_view/stdafx.h

+ 7 - 0
.gitignore

@@ -7,6 +7,12 @@ build
 *.sln
 *.ncb
 *.vcproj
+*.vcxproj.user
+*.VC.db
+*.VC.db-shm
+*.VC.db-wal
+*.VC.opendb
+*.ipch
 
 # Output
 bin/
@@ -32,6 +38,7 @@ cmake_uninstall.cmake
 *.dir/
 assimp-config.cmake
 assimp-config-version.cmake
+assimpTargets*.cmake
 
 # MakeFile
 Makefile

+ 6 - 6
code/FBXBinaryTokenizer.cpp

@@ -98,7 +98,7 @@ namespace FBX {
 //	return (flags & to_check) != 0;
 //}
 // ------------------------------------------------------------------------------------------------
-Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int offset)
+Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset)
     :
     #ifdef DEBUG
     contents(sbegin, static_cast<size_t>(send-sbegin)),
@@ -122,18 +122,18 @@ namespace {
 
 // ------------------------------------------------------------------------------------------------
 // signal tokenization error, this is always unrecoverable. Throws DeadlyImportError.
-AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset) AI_WONT_RETURN_SUFFIX;
-AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset)
+AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX;
+AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset)
 {
     throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset));
 }
 
 
 // ------------------------------------------------------------------------------------------------
-uint32_t Offset(const char* begin, const char* cursor) {
+size_t Offset(const char* begin, const char* cursor) {
     ai_assert(begin <= cursor);
 
-    return static_cast<unsigned int>(cursor - begin);
+    return cursor - begin;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -424,7 +424,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, unsigned int length)
+void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
 {
     ai_assert(input);
 

+ 55 - 46
code/FBXConverter.cpp

@@ -86,7 +86,6 @@ namespace Assimp {
         , textures_converted()
         , meshes_converted()
         , node_anim_chain_bits()
-        , mNodeNameInstances()
         , mNodeNames()
         , anim_fps()
         , out(out)
@@ -142,12 +141,46 @@ namespace Assimp {
 
         void FBXConverter::ConvertRootNode() {
             out->mRootNode = new aiNode();
-            out->mRootNode->mName.Set("RootNode");
+            std::string unique_name;
+            GetUniqueName("RootNode", unique_name);
+            out->mRootNode->mName.Set(unique_name);
 
             // root has ID 0
             ConvertNodes(0L, *out->mRootNode);
         }
 
+        static std::string getAncestorBaseName(const aiNode* node)
+        {
+            const char* nodeName = nullptr;
+            size_t length = 0;
+            while (node && (!nodeName || length == 0))
+            {
+                nodeName = node->mName.C_Str();
+                length = node->mName.length;
+                node = node->mParent;
+            }
+
+            if (!nodeName || length == 0)
+            {
+                return {};
+            }
+            // could be std::string_view if c++17 available
+            return std::string(nodeName, length);
+        }
+
+        // Make unique name
+        std::string FBXConverter::MakeUniqueNodeName(const Model* const model, const aiNode& parent)
+        {
+            std::string original_name = FixNodeName(model->Name());
+            if (original_name.empty())
+            {
+                original_name = getAncestorBaseName(&parent);
+            }
+            std::string unique_name;
+            GetUniqueName(original_name, unique_name);
+            return unique_name;
+        }
+
         void FBXConverter::ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform) {
             const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
 
@@ -179,35 +212,18 @@ namespace Assimp {
 
                         aiMatrix4x4 new_abs_transform = parent_transform;
 
+                        std::string unique_name = MakeUniqueNodeName(model, parent);
+
                         // even though there is only a single input node, the design of
                         // assimp (or rather: the complicated transformation chain that
                         // is employed by fbx) means that we may need multiple aiNode's
                         // to represent a fbx node's transformation.
-                        GenerateTransformationNodeChain(*model, nodes_chain, post_nodes_chain);
+                        const bool need_additional_node = GenerateTransformationNodeChain(*model, unique_name, nodes_chain, post_nodes_chain);
 
                         ai_assert(nodes_chain.size());
 
-                        std::string original_name = FixNodeName(model->Name());
-
-                        // check if any of the nodes in the chain has the name the fbx node
-                        // is supposed to have. If there is none, add another node to
-                        // preserve the name - people might have scripts etc. that rely
-                        // on specific node names.
-                        aiNode* name_carrier = NULL;
-                        for (aiNode* prenode : nodes_chain) {
-                            if (!strcmp(prenode->mName.C_Str(), original_name.c_str())) {
-                                name_carrier = prenode;
-                                break;
-                            }
-                        }
-
-                        if (!name_carrier) {
-                            std::string old_original_name = original_name;
-                            GetUniqueName(old_original_name, original_name);
-                            nodes_chain.push_back(new aiNode(original_name));
-                        }
-                        else {
-                            original_name = nodes_chain.back()->mName.C_Str();
+                        if (need_additional_node) {
+                            nodes_chain.push_back(new aiNode(unique_name));
                         }
 
                         //setup metadata on newest node
@@ -269,11 +285,11 @@ namespace Assimp {
                         ConvertNodes(model->ID(), *last_parent, new_abs_transform);
 
                         if (doc.Settings().readLights) {
-                            ConvertLights(*model, original_name);
+                            ConvertLights(*model, unique_name);
                         }
 
                         if (doc.Settings().readCameras) {
-                            ConvertCameras(*model, original_name);
+                            ConvertCameras(*model, unique_name);
                         }
 
                         nodes.push_back(nodes_chain.front());
@@ -426,21 +442,16 @@ namespace Assimp {
         void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName)
         {
             uniqueName = name;
-            int i = 0;
-            auto it = mNodeNameInstances.find(name); // duplicate node name instance count
-            if (it != mNodeNameInstances.end())
+            auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
+            unsigned int& i = it_pair.first->second;
+            while (!it_pair.second)
             {
-                i = it->second;
-                while (mNodeNames.find(uniqueName) != mNodeNames.end())
-                {
-                    i++;
-                    std::stringstream ext;
-                    ext << name << std::setfill('0') << std::setw(3) << i;
-                    uniqueName = ext.str();
-                }
+                i++;
+                std::ostringstream ext;
+                ext << name << std::setfill('0') << std::setw(3) << i;
+                uniqueName = ext.str();
+                it_pair = mNodeNames.insert({ uniqueName, 0 });
             }
-            mNodeNameInstances[name] = i;
-            mNodeNames.insert(uniqueName);
         }
 
         const char* FBXConverter::NameTransformationComp(TransformationComp comp) {
@@ -672,7 +683,7 @@ namespace Assimp {
             return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
         }
 
-        void FBXConverter::GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes,
+        bool FBXConverter::GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes,
             std::vector<aiNode*>& post_output_nodes) {
             const PropertyTable& props = model.Props();
             const Model::RotOrder rot = model.RotationOrder();
@@ -787,8 +798,6 @@ namespace Assimp {
             // not be guaranteed.
             ai_assert(NeedsComplexTransformationChain(model) == is_complex);
 
-            std::string name = FixNodeName(model.Name());
-
             // now, if we have more than just Translation, Scaling and Rotation,
             // we need to generate a full node chain to accommodate for assimp's
             // lack to express pivots and offsets.
@@ -830,20 +839,20 @@ namespace Assimp {
                 }
 
                 ai_assert(output_nodes.size());
-                return;
+                return true;
             }
 
             // else, we can just multiply the matrices together
             aiNode* nd = new aiNode();
             output_nodes.push_back(nd);
-            std::string uniqueName;
-            GetUniqueName(name, uniqueName);
 
-            nd->mName.Set(uniqueName);
+            // name passed to the method is already unique
+            nd->mName.Set(name);
 
             for (const auto &transform : chain) {
                 nd->mTransformation = nd->mTransformation * transform;
             }
+            return false;
         }
 
         void FBXConverter::SetupNodeMetadata(const Model& model, aiNode& nd)

+ 7 - 5
code/FBXConverter.h

@@ -154,6 +154,11 @@ private:
     // while these would be allowed, they are a potential trouble spot so better not use them).
     const char* NameTransformationComp(TransformationComp comp);
 
+    // ------------------------------------------------------------------------------------------------
+    // Returns an unique name for a node or traverses up a hierarchy until a non-empty name is found and
+    // then makes this name unique
+    std::string MakeUniqueNodeName(const Model* const model, const aiNode& parent);
+
     // ------------------------------------------------------------------------------------------------
     // note: this returns the REAL fbx property names
     const char* NameTransformationCompProperty(TransformationComp comp);
@@ -177,7 +182,7 @@ private:
     /**
     *  note: memory for output_nodes will be managed by the caller
     */
-    void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
+    bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
 
     // ------------------------------------------------------------------------------------------------
     void SetupNodeMetadata(const Model& model, aiNode& nd);
@@ -457,10 +462,7 @@ private:
     NodeAnimBitMap node_anim_chain_bits;
 
     // number of nodes with the same name
-    using NodeAnimNameMap = std::unordered_map<std::string, unsigned int>;
-    NodeAnimNameMap mNodeNameInstances;
-
-    using NodeNameCache = std::unordered_set<std::string>;
+    using NodeNameCache = std::unordered_map<std::string, unsigned int>;
     NodeNameCache mNodeNames;
 
     double anim_fps;

+ 1 - 1
code/FBXDocument.h

@@ -643,7 +643,7 @@ private:
     std::string fileName;
     std::shared_ptr<const PropertyTable> props;
 
-    uint32_t contentLength;
+    uint64_t contentLength;
     uint8_t* content;
 };
 

+ 1 - 1
code/FBXImporter.cpp

@@ -172,7 +172,7 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
         bool is_binary = false;
         if (!strncmp(begin,"Kaydara FBX Binary",18)) {
             is_binary = true;
-            TokenizeBinary(tokens,begin,static_cast<unsigned int>(contents.size()));
+            TokenizeBinary(tokens,begin,contents.size());
         }
         else {
             Tokenize(tokens,begin);

+ 33 - 9
code/FBXMaterial.cpp

@@ -326,16 +326,40 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std
                     DOMError("embedded content is not surrounded by quotation marks", &element);
                 }
                 else {
-                    const char* encodedData = data + 1;
-                    size_t encodedDataLen = static_cast<size_t>(token.end() - token.begin());
-                    // search for last quotation mark
-                    while (encodedDataLen > 1 && encodedData[encodedDataLen] != '"')
-                        encodedDataLen--;
-                    if (encodedDataLen % 4 != 0) {
-                        DOMError("embedded content is invalid, needs to be in base64", &element);
+                    size_t targetLength = 0;
+                    auto 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);
+                        size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
+                        const char* base64data = dataToken.begin() + 1;
+                        const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength);
+                        if (outLength == 0)
+                        {
+                            DOMError("Corrupted embedded content found", &element);
+                        }
+                        targetLength += outLength;
                     }
-                    else {
-                        contentLength = Util::DecodeBase64(encodedData, encodedDataLen, content);
+                    if (targetLength == 0)
+                    {
+                        DOMError("Corrupted embedded content found", &element);
+                    }
+                    content = new uint8_t[targetLength];
+                    contentLength = static_cast<uint64_t>(targetLength);
+                    size_t dst_offset = 0;
+                    for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx)
+                    {
+                        const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
+                        size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
+                        const char* base64data = dataToken.begin() + 1;
+                        dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset);
+                    }
+                    if (targetLength != dst_offset)
+                    {
+                        delete[] content;
+                        contentLength = 0;
+                        DOMError("Corrupted embedded content found", &element);
                     }
                 }
             }

+ 3 - 3
code/FBXParser.cpp

@@ -643,9 +643,9 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
         if (type == 'd') {
             const double* d = reinterpret_cast<const double*>(&buff[0]);
             for (unsigned int i = 0; i < count3; ++i, d += 3) {
-                out.push_back(aiVector3D(static_cast<float>(d[0]),
-                    static_cast<float>(d[1]),
-                    static_cast<float>(d[2])));
+                out.push_back(aiVector3D(static_cast<ai_real>(d[0]),
+                    static_cast<ai_real>(d[1]),
+                    static_cast<ai_real>(d[2])));
             }
             // for debugging
             /*for ( size_t i = 0; i < out.size(); i++ ) {

+ 6 - 6
code/FBXTokenizer.h

@@ -93,7 +93,7 @@ public:
     Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column);
 
     /** construct a binary token */
-    Token(const char* sbegin, const char* send, TokenType type, unsigned int offset);
+    Token(const char* sbegin, const char* send, TokenType type, size_t offset);
 
     ~Token();
 
@@ -118,14 +118,14 @@ public:
         return type;
     }
 
-    unsigned int Offset() const {
+    size_t Offset() const {
         ai_assert(IsBinary());
         return offset;
     }
 
     unsigned int Line() const {
         ai_assert(!IsBinary());
-        return line;
+        return static_cast<unsigned int>(line);
     }
 
     unsigned int Column() const {
@@ -147,8 +147,8 @@ private:
     const TokenType type;
 
     union {
-        const unsigned int line;
-        unsigned int offset;
+        size_t line;
+        size_t offset;
     };
     const unsigned int column;
 };
@@ -178,7 +178,7 @@ void Tokenize(TokenList& output_tokens, const char* input);
  * @param input_buffer Binary input buffer to be processed.
  * @param length Length of input buffer, in bytes. There is no 0-terminal.
  * @throw DeadlyImportError if something goes wrong */
-void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int length);
+void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length);
 
 
 } // ! FBX

+ 48 - 29
code/FBXUtil.cpp

@@ -86,7 +86,7 @@ const char* TokenTypeString(TokenType t)
 
 
 // ------------------------------------------------------------------------------------------------
-std::string AddOffset(const std::string& prefix, const std::string& text, unsigned int offset)
+std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset)
 {
     return static_cast<std::string>( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) );
 }
@@ -114,47 +114,66 @@ std::string AddTokenText(const std::string& prefix, const std::string& text, con
         text) );
 }
 
+// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
 static const uint8_t base64DecodeTable[128] = {
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0, 63,
-    52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,  0, 64,  0,  0,
-    0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
-    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,
-    0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
-    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,  0,  0,  0,  0,  0
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
+    255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
+    255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
 };
 
 uint8_t DecodeBase64(char ch)
 {
-    return base64DecodeTable[size_t(ch)];
+    const auto idx = static_cast<uint8_t>(ch);
+    if (idx > 127)
+        return 255;
+    return base64DecodeTable[idx];
 }
 
-size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out)
+size_t ComputeDecodedSizeBase64(const char* in, size_t inLength)
 {
-    if (inLength < 4) {
-        out = 0;
+    if (inLength < 2)
+    {
         return 0;
     }
+    const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '=');
+    const size_t full_length = (inLength * 3) >> 2; // div by 4
+    if (full_length < equals)
+    {
+        return 0;
+    }
+    return full_length - equals;
+}
 
-    const size_t outLength = (inLength * 3) / 4;
-    out = new uint8_t[outLength];
-    memset(out, 0, outLength);
-
-    size_t i = 0;
-    size_t j = 0;
-    for (i = 0; i < inLength - 4; i += 4)
+size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength)
+{
+    if (maxOutLength == 0 || inLength < 2) {
+        return 0;
+    }
+    const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
+    size_t dst_offset = 0;
+    int val = 0, valb = -8;
+    for (size_t src_offset = 0; src_offset < realLength; ++src_offset)
     {
-        uint8_t b0 = Util::DecodeBase64(in[i]);
-        uint8_t b1 = Util::DecodeBase64(in[i + 1]);
-        uint8_t b2 = Util::DecodeBase64(in[i + 2]);
-        uint8_t b3 = Util::DecodeBase64(in[i + 3]);
-
-        out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
-        out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
-        out[j++] = (uint8_t)((b2 << 6) | b3);
+        const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
+        if (table_value == 255)
+        {
+            return 0;
+        }
+        val = (val << 6) + table_value;
+        valb += 6;
+        if (valb >= 0)
+        {
+            out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF);
+            valb -= 8;
+            val &= 0xFFF;
+        }
     }
-    return outLength;
+    return dst_offset;
 }
 
 static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

+ 11 - 3
code/FBXUtil.h

@@ -78,7 +78,7 @@ const char* TokenTypeString(TokenType t);
  *  @param line Line index, 1-based
  *  @param column Column index, 1-based
  *  @return A string of the following format: {prefix} (offset 0x{offset}) {text}*/
-std::string AddOffset(const std::string& prefix, const std::string& text, unsigned int offset);
+std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset);
 
 
 /** Format log/error messages using a given line location in the source file.
@@ -105,13 +105,21 @@ std::string AddTokenText(const std::string& prefix, const std::string& text, con
 *  @return decoded byte value*/
 uint8_t DecodeBase64(char ch);
 
+/** Compute decoded size of a Base64-encoded string
+*
+*  @param in Characters to decode.
+*  @param inLength Number of characters to decode.
+*  @return size of the decoded data (number of bytes)*/
+size_t ComputeDecodedSizeBase64(const char* in, size_t inLength);
+
 /** Decode a Base64-encoded string
 *
 *  @param in Characters to decode.
 *  @param inLength Number of characters to decode.
-*  @param out Reference to pointer where we will store the decoded data.
+*  @param out Pointer where we will store the decoded data.
+*  @param maxOutLength Size of output buffer.
 *  @return size of the decoded data (number of bytes)*/
-size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
+size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength);
 
 char EncodeBase64(char byte);
 

+ 1 - 1
code/Importer/IFC/IFCBoolean.cpp

@@ -256,7 +256,7 @@ bool IntersectsBoundaryProfile(const IfcVector3& e0, const IfcVector3& e1, const
     for( size_t i = 0, bcount = boundary.size(); i < bcount; ++i ) {
         IfcVector3 b01 = boundary[(i + 1) % bcount] - boundary[i];
         IfcVector3 b12 = boundary[(i + 2) % bcount] - boundary[(i + 1) % bcount];
-        IfcVector3 b1_side = IfcVector3(b01.y, -b01.x, 0.0); // rotated 90° clockwise in Z plane
+        IfcVector3 b1_side = IfcVector3(b01.y, -b01.x, 0.0); // rotated 90° clockwise in Z plane
         // Warning: rough estimate only. A concave poly with lots of small segments each featuring a small counter rotation
         // could fool the accumulation. Correct implementation would be sum( acos( b01 * b2) * sign( b12 * b1_side))
         windingOrder += (b1_side.x*b12.x + b1_side.y*b12.y);

+ 1 - 0
code/STLLoader.cpp

@@ -278,6 +278,7 @@ void STLImporter::LoadASCIIFile( aiNode *root ) {
             }
             std::string name( szMe, temp );
             node->mName.Set( name.c_str() );
+            pMesh->mName.Set( name.c_str() );
             //pScene->mRootNode->mName.length = temp;
             //memcpy(pScene->mRootNode->mName.data,szMe,temp);
             //pScene->mRootNode->mName.data[temp] = '\0';

+ 2 - 2
code/res/resource.h

@@ -2,8 +2,8 @@
 // Microsoft Visual C++ generated include file.
 // Used by assimp.rc
 
-// Nächste Standardwerte für neue Objekte
-// 
+// Next standard values for new objects
+//
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        101

+ 1 - 1
contrib/irrXML/irrString.h

@@ -19,7 +19,7 @@ so you can assign unicode to string<c8> and ascii to string<wchar_t>
 Note that the conversation between both is not done using an encoding.
 
 Known bugs:
-Special characters like 'Ä', 'Ü' and 'Ö' are ignored in the
+Special characters like 'Ä', 'Ü' and 'Ö' are ignored in the
 methods make_upper, make_lower and equals_ignore_case.
 */
 template <class T>

+ 1 - 1
contrib/poly2tri/AUTHORS

@@ -1,7 +1,7 @@
 Primary Contributors:
 
   Mason Green <[email protected]> (C++, Python)
-  Thomas Åhlén <[email protected]>    (Java)
+  Thomas Ã…hlén <[email protected]>    (Java)
 
 Other Contributors:
 

+ 2 - 2
contrib/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs

@@ -1,5 +1,5 @@
 //
-// © Copyright Henrik Ravn 2004
+// © Copyright Henrik Ravn 2004
 //
 // Use, modification and distribution are subject to the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -199,4 +199,4 @@ namespace DotZLib
     }
     #endregion
 
-}
+}

+ 1 - 1
contrib/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs

@@ -1,5 +1,5 @@
 //
-// © Copyright Henrik Ravn 2004
+// © Copyright Henrik Ravn 2004
 //
 // Use, modification and distribution are subject to the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

+ 1 - 1
contrib/zlib/contrib/dotzlib/DotZLib/CodecBase.cs

@@ -1,5 +1,5 @@
 //
-// © Copyright Henrik Ravn 2004
+// © Copyright Henrik Ravn 2004
 //
 // Use, modification and distribution are subject to the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

+ 1 - 1
contrib/zlib/contrib/dotzlib/DotZLib/Deflater.cs

@@ -1,5 +1,5 @@
 //
-// © Copyright Henrik Ravn 2004
+// © Copyright Henrik Ravn 2004
 //
 // Use, modification and distribution are subject to the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

+ 1 - 1
contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.cs

@@ -1,5 +1,5 @@
 //
-// © Copyright Henrik Ravn 2004
+// © Copyright Henrik Ravn 2004
 //
 // Use, modification and distribution are subject to the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

+ 1 - 1
contrib/zlib/contrib/dotzlib/DotZLib/GZipStream.cs

@@ -1,5 +1,5 @@
 //
-// © Copyright Henrik Ravn 2004
+// © Copyright Henrik Ravn 2004
 //
 // Use, modification and distribution are subject to the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

+ 1 - 1
contrib/zlib/contrib/dotzlib/DotZLib/Inflater.cs

@@ -1,5 +1,5 @@
 //
-// © Copyright Henrik Ravn 2004
+// © Copyright Henrik Ravn 2004
 //
 // Use, modification and distribution are subject to the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

+ 1 - 1
include/assimp/defs.h

@@ -293,7 +293,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef _MSC_VER
 #  define AI_NO_EXCEPT noexcept
 #else
-#  if (_MSC_VER == 1915 )
+#  if (_MSC_VER >= 1915 )
 #    define AI_NO_EXCEPT noexcept
 #  else
 #    define AI_NO_EXCEPT

+ 2 - 1
port/PyAssimp/pyassimp/core.py

@@ -82,7 +82,8 @@ def call_init(obj, caller = None):
         _init(obj,parent=caller)
 
 def _is_init_type(obj):
-    if helper.hasattr_silent(obj,'contents'): #pointer
+
+    if obj and helper.hasattr_silent(obj,'contents'): #pointer
         return _is_init_type(obj[0])
     # null-pointer case that arises when we reach a mesh attribute
     # like mBitangents which use mNumVertices rather than mNumBitangents

+ 3 - 3
port/PyAssimp/pyassimp/helper.py

@@ -192,9 +192,9 @@ def try_load_functions(library_path, dll):
 
     # library found!
     from .structs import Scene, ExportDataBlob
-    load.restype = ctype.POINTER(Scene)
-    load_mem.restype = ctype.POINTER(Scene)
-    export2blob.restype = ctype.POINTER(ExportDataBlob)
+    load.restype = ctypes.POINTER(Scene)
+    load_mem.restype = ctypes.POINTER(Scene)
+    export2blob.restype = ctypes.POINTER(ExportDataBlob)
     return (library_path, load, load_mem, export, export2blob, release, dll)
 
 def search_library():

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 571 - 0
test/models/FBX/cubes_nonames.fbx


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 571 - 0
test/models/FBX/cubes_with_mirroring_and_pivot.fbx


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 571 - 0
test/models/FBX/cubes_with_names.fbx


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 534 - 0
test/models/FBX/embedded_ascii/box_embedded_texture_fragmented.fbx


+ 137 - 0
test/unit/utFBXImporterExporter.cpp

@@ -76,6 +76,119 @@ TEST_F( utFBXImporterExporter, importBareBoxWithoutColorsAndTextureCoords ) {
     EXPECT_EQ(mesh->mNumVertices, 36);
 }
 
+TEST_F(utFBXImporterExporter, importCubesWithNoNames) {
+    Assimp::Importer importer;
+    const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_nonames.fbx", aiProcess_ValidateDataStructure);
+    ASSERT_TRUE(scene);
+
+    ASSERT_TRUE(scene->mRootNode);
+    const auto root = scene->mRootNode;
+    ASSERT_STREQ(root->mName.C_Str(), "RootNode");
+    ASSERT_TRUE(root->mChildren);
+    ASSERT_EQ(root->mNumChildren, 2);
+
+    const auto child0 = root->mChildren[0];
+    ASSERT_TRUE(child0);
+    ASSERT_STREQ(child0->mName.C_Str(), "RootNode001");
+    ASSERT_TRUE(child0->mChildren);
+    ASSERT_EQ(child0->mNumChildren, 1);
+
+    const auto child00 = child0->mChildren[0];
+    ASSERT_TRUE(child00);
+    ASSERT_STREQ(child00->mName.C_Str(), "RootNode001001");
+
+    const auto child1 = root->mChildren[1];
+    ASSERT_TRUE(child1);
+    ASSERT_STREQ(child1->mName.C_Str(), "RootNode002");
+    ASSERT_TRUE(child1->mChildren);
+    ASSERT_EQ(child1->mNumChildren, 1);
+
+    const auto child10 = child1->mChildren[0];
+    ASSERT_TRUE(child10);
+    ASSERT_STREQ(child10->mName.C_Str(), "RootNode002001");
+}
+
+TEST_F(utFBXImporterExporter, importCubesWithUnicodeDuplicatedNames) {
+    Assimp::Importer importer;
+    const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_with_names.fbx", aiProcess_ValidateDataStructure);
+    ASSERT_TRUE(scene);
+
+    ASSERT_TRUE(scene->mRootNode);
+    const auto root = scene->mRootNode;
+    ASSERT_STREQ(root->mName.C_Str(), "RootNode");
+    ASSERT_TRUE(root->mChildren);
+    ASSERT_EQ(root->mNumChildren, 2);
+
+    const auto child0 = root->mChildren[0];
+    ASSERT_TRUE(child0);
+    ASSERT_STREQ(child0->mName.C_Str(), "Cube2");
+    ASSERT_TRUE(child0->mChildren);
+    ASSERT_EQ(child0->mNumChildren, 1);
+
+    const auto child00 = child0->mChildren[0];
+    ASSERT_TRUE(child00);
+    ASSERT_STREQ(child00->mName.C_Str(), "\xd0\x9a\xd1\x83\xd0\xb1\x31");
+
+    const auto child1 = root->mChildren[1];
+    ASSERT_TRUE(child1);
+    ASSERT_STREQ(child1->mName.C_Str(), "Cube3");
+    ASSERT_TRUE(child1->mChildren);
+    ASSERT_EQ(child1->mNumChildren, 1);
+
+    const auto child10 = child1->mChildren[0];
+    ASSERT_TRUE(child10);
+    ASSERT_STREQ(child10->mName.C_Str(), "\xd0\x9a\xd1\x83\xd0\xb1\x31""001");
+}
+
+TEST_F(utFBXImporterExporter, importCubesComplexTransform) {
+    Assimp::Importer importer;
+    const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_with_mirroring_and_pivot.fbx", aiProcess_ValidateDataStructure);
+    ASSERT_TRUE(scene);
+
+    ASSERT_TRUE(scene->mRootNode);
+    const auto root = scene->mRootNode;
+    ASSERT_STREQ(root->mName.C_Str(), "RootNode");
+    ASSERT_TRUE(root->mChildren);
+    ASSERT_EQ(root->mNumChildren, 2);
+
+    const auto child0 = root->mChildren[0];
+    ASSERT_TRUE(child0);
+    ASSERT_STREQ(child0->mName.C_Str(), "Cube2");
+    ASSERT_TRUE(child0->mChildren);
+    ASSERT_EQ(child0->mNumChildren, 1);
+
+    const auto child00 = child0->mChildren[0];
+    ASSERT_TRUE(child00);
+    ASSERT_STREQ(child00->mName.C_Str(), "Cube1");
+
+    const auto child1 = root->mChildren[1];
+    ASSERT_TRUE(child1);
+    ASSERT_STREQ(child1->mName.C_Str(), "Cube3");
+
+    auto parent = child1;
+    const size_t chain_length = 8u;
+    const char* chainStr[chain_length] = {
+        "Cube1001_$AssimpFbx$_Translation",
+        "Cube1001_$AssimpFbx$_RotationPivot",
+        "Cube1001_$AssimpFbx$_RotationPivotInverse",
+        "Cube1001_$AssimpFbx$_ScalingOffset",
+        "Cube1001_$AssimpFbx$_ScalingPivot",
+        "Cube1001_$AssimpFbx$_Scaling",
+        "Cube1001_$AssimpFbx$_ScalingPivotInverse",
+        "Cube1001"
+    };
+    for (size_t i = 0; i < chain_length; ++i)
+    {
+        ASSERT_TRUE(parent->mChildren);
+        ASSERT_EQ(parent->mNumChildren, 1);
+        auto node = parent->mChildren[0];
+        ASSERT_TRUE(node);
+        ASSERT_STREQ(node->mName.C_Str(), chainStr[i]);
+        parent = node;
+    }
+    ASSERT_EQ(0, parent->mNumChildren) << "Leaf node";
+}
+
 TEST_F( utFBXImporterExporter, importPhongMaterial ) {
     Assimp::Importer importer;
     const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/FBX/phong_cube.fbx", aiProcess_ValidateDataStructure );
@@ -128,4 +241,28 @@ TEST_F(utFBXImporterExporter, importEmbeddedAsciiTest) {
     aiString path;
     aiTextureMapMode modes[2];
     EXPECT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes));
+
+    ASSERT_EQ(1, scene->mNumTextures);
+    ASSERT_TRUE(scene->mTextures[0]->pcData);
+    ASSERT_EQ(439176u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture";
+}
+
+TEST_F(utFBXImporterExporter, importEmbeddedFragmentedAsciiTest) {
+    // see https://github.com/assimp/assimp/issues/1957
+    Assimp::Importer importer;
+    const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box_embedded_texture_fragmented.fbx", aiProcess_ValidateDataStructure);
+    EXPECT_NE(nullptr, scene);
+
+    EXPECT_EQ(1, scene->mNumMaterials);
+    aiMaterial *mat = scene->mMaterials[0];
+    ASSERT_NE(nullptr, mat);
+
+    aiString path;
+    aiTextureMapMode modes[2];
+    ASSERT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes));
+    ASSERT_STREQ(path.C_Str(), "paper.png");
+
+    ASSERT_EQ(1, scene->mNumTextures);
+    ASSERT_TRUE(scene->mTextures[0]->pcData);
+    ASSERT_EQ(968029u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture";
 }

+ 7 - 2
tools/assimp_cmd/Info.cpp

@@ -317,10 +317,15 @@ int Assimp_Info (const char* const* params, unsigned int num) {
 		return 1;
 	}
 	
-	// do maximum post-processing unless -r was specified
+	// Parse post-processing flags unless -r was specified
 	ImportData import;
 	if (!raw) {
-		import.ppFlags = aiProcessPreset_TargetRealtime_MaxQuality;
+		// get import flags
+		ProcessStandardArguments(import, params + 1, num - 1);
+
+		//No custom post process flags defined, we set all the post process flags active
+		if(import.ppFlags == 0)
+			import.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality;
 	}
 
 	// import the main model

+ 2 - 2
tools/assimp_view/stdafx.cpp

@@ -1,8 +1,8 @@
 // stdafx.cpp : Quelldatei, die nur die Standard-Includes einbindet.
 // assimp_view.pch ist der vorkompilierte Header.
-// stdafx.obj enthält die vorkompilierten Typinformationen.
+// stdafx.obj enthält die vorkompilierten Typinformationen.
 
 #include "stdafx.h"
 
-// TODO: Auf zusätzliche Header verweisen, die in STDAFX.H
+// TODO: Auf zusätzliche Header verweisen, die in STDAFX.H
 // und nicht in dieser Datei erforderlich sind.

+ 13 - 13
tools/assimp_view/stdafx.h

@@ -1,26 +1,26 @@
-// stdafx.h : Includedatei für Standardsystem-Includedateien
-// oder häufig verwendete projektspezifische Includedateien,
-// die nur in unregelmäßigen Abständen geändert werden.
+// stdafx.h : Includedatei für Standardsystem-Includedateien
+// oder häufig verwendete projektspezifische Includedateien,
+// die nur in unregelmäßigen Abständen geändert werden.
 //
 
 #pragma once
 
-// Ändern Sie folgende Definitionen für Plattformen, die älter als die unten angegebenen sind.
-// In MSDN finden Sie die neuesten Informationen über die entsprechenden Werte für die unterschiedlichen Plattformen.
-#ifndef WINVER              // Lassen Sie die Verwendung spezifischer Features von Windows XP oder später zu.
-#   define WINVER 0x0501        // Ändern Sie dies in den geeigneten Wert für andere Versionen von Windows.
+// Ändern Sie folgende Definitionen für Plattformen, die älter als die unten angegebenen sind.
+// In MSDN finden Sie die neuesten Informationen über die entsprechenden Werte für die unterschiedlichen Plattformen.
+#ifndef WINVER              // Lassen Sie die Verwendung spezifischer Features von Windows XP oder später zu.
+#   define WINVER 0x0501        // Ändern Sie dies in den geeigneten Wert für andere Versionen von Windows.
 #endif
 
-#ifndef _WIN32_WINNT        // Lassen Sie die Verwendung spezifischer Features von Windows XP oder später zu.
-#   define _WIN32_WINNT 0x0501  // Ändern Sie dies in den geeigneten Wert für andere Versionen von Windows.
+#ifndef _WIN32_WINNT        // Lassen Sie die Verwendung spezifischer Features von Windows XP oder später zu.
+#   define _WIN32_WINNT 0x0501  // Ändern Sie dies in den geeigneten Wert für andere Versionen von Windows.
 #endif
 
-#ifndef _WIN32_WINDOWS      // Lassen Sie die Verwendung spezifischer Features von Windows 98 oder später zu.
-#   define _WIN32_WINDOWS 0x0410 // Ändern Sie dies in den geeigneten Wert für Windows Me oder höher.
+#ifndef _WIN32_WINDOWS      // Lassen Sie die Verwendung spezifischer Features von Windows 98 oder später zu.
+#   define _WIN32_WINDOWS 0x0410 // Ändern Sie dies in den geeigneten Wert für Windows Me oder höher.
 #endif
 
-#ifndef _WIN32_IE           // Lassen Sie die Verwendung spezifischer Features von IE 6.0 oder später zu.
-#define _WIN32_IE 0x0600    // Ändern Sie dies in den geeigneten Wert für andere Versionen von IE.
+#ifndef _WIN32_IE           // Lassen Sie die Verwendung spezifischer Features von IE 6.0 oder später zu.
+#define _WIN32_IE 0x0600    // Ändern Sie dies in den geeigneten Wert für andere Versionen von IE.
 #endif
 
 // Windows-Headerdateien:

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно