Explorar el Código

Fix compression for fbx

Kim Kulling hace 3 años
padre
commit
3e09d462fa

+ 1 - 1
code/AssetLib/Blender/BlenderLoader.cpp

@@ -175,7 +175,7 @@ void BlenderImporter::InternReadFile(const std::string &pFile,
 
         size_t total = 0;
         Compression compression;
-        if (compression.open(Compression::Format::Binary)) {
+        if (compression.open(Compression::Format::Binary, Compression::FlushMode::Finish) ) {
             total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), uncompressed);
             compression.close();
         }

+ 16 - 25
code/AssetLib/FBX/FBXParser.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -48,10 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 //#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
 #include "Common/Compression.h"
-/*#   include <zlib.h>
-#else
-#   include "../contrib/zlib/zlib.h"
-#endif*/
+//#   include <zlib.h>
+//#else
+//#   include "../contrib/zlib/zlib.h"
+//#endif
 
 #include "FBXTokenizer.h"
 #include "FBXParser.h"
@@ -116,9 +115,7 @@ namespace Assimp {
 namespace FBX {
 
 // ------------------------------------------------------------------------------------------------
-Element::Element(const Token& key_token, Parser& parser)
-: key_token(key_token)
-{
+Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) {
     TokenPtr n = nullptr;
     do {
         n = parser.AdvanceToNextToken();
@@ -211,8 +208,7 @@ Scope::Scope(Parser& parser,bool topLevel)
 }
 
 // ------------------------------------------------------------------------------------------------
-Scope::~Scope()
-{
+Scope::~Scope() {
     for(ElementMap::value_type& v : elements) {
         delete v.second;
     }
@@ -528,9 +524,7 @@ void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uin
 // ------------------------------------------------------------------------------------------------
 // read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
 void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end,
-    std::vector<char>& buff,
-    const Element& /*el*/)
-{
+        std::vector<char>& buff, const Element& /*el*/) {
     BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end);
     AI_SWAP4(encmode);
     data += 4;
@@ -572,11 +566,12 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha
     else if(encmode == 1) {
         // zlib/deflate, next comes ZIP head (0x78 0x01)
         // see http://www.ietf.org/rfc/rfc1950.txt
-        Compression compress;
-        if (compress.open(Compression::Format::Binary)) {
+         Compression compress;
+        if (compress.open(Compression::Format::Binary, Compression::FlushMode::Finish)) {
             compress.decompress(data, comp_len, buff);
+            compress.close();
         }
-        /* z_stream zstream;
+        /* z_stream zstream = {};
         zstream.opaque = Z_NULL;
         zstream.zalloc = Z_NULL;
         zstream.zfree  = Z_NULL;
@@ -585,9 +580,9 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha
         // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
         if(Z_OK != inflateInit(&zstream)) {
             ParseError("failure initializing zlib");
-        }*/
+        }
 
-        /* zstream.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(data));
+        zstream.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(data));
         zstream.avail_in  = comp_len;
 
         zstream.avail_out = static_cast<uInt>(buff.size());
@@ -705,7 +700,6 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
     }
 }
 
-
 // ------------------------------------------------------------------------------------------------
 // read an array of color4 tuples
 void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
@@ -790,8 +784,7 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
 
 // ------------------------------------------------------------------------------------------------
 // read an array of float2 tuples
-void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
-{
+void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) {
     out.resize( 0 );
     const TokenList& tok = el.Tokens();
     if(tok.empty()) {
@@ -835,8 +828,7 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
                 out.push_back(aiVector2D(static_cast<float>(d[0]),
                     static_cast<float>(d[1])));
             }
-        }
-        else if (type == 'f') {
+        } else if (type == 'f') {
             const float* f = reinterpret_cast<const float*>(&buff[0]);
             for (unsigned int i = 0; i < count2; ++i, f += 2) {
                 out.push_back(aiVector2D(f[0],f[1]));
@@ -869,8 +861,7 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
 
 // ------------------------------------------------------------------------------------------------
 // read an array of ints
-void ParseVectorDataArray(std::vector<int>& out, const Element& el)
-{
+void ParseVectorDataArray(std::vector<int>& out, const Element& el) {
     out.resize( 0 );
     const TokenList& tok = el.Tokens();
     if(tok.empty()) {

+ 3 - 2
code/AssetLib/X/XFileParser.cpp

@@ -188,7 +188,7 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
         Compression compression;
         uncompressed.resize(est_out + 1);
         char *out = &uncompressed.front();
-        if (compression.open(mIsBinaryFormat ? Compression::Format::Binary : Compression::Format::ASCII)) {
+        if (compression.open(mIsBinaryFormat ? Compression::Format::Binary : Compression::Format::ASCII, Compression::FlushMode::SyncFlush)) {
             while (mP + 3 < mEnd) {
                 uint16_t ofs = *((uint16_t *)mP);
                 AI_SWAP2(ofs);
@@ -238,8 +238,9 @@ void XFileParser::ParseFile() {
     while (running) {
         // read name of next object
         std::string objectName = GetNextToken();
-        if (objectName.length() == 0)
+        if (objectName.length() == 0) {
             break;
+        }
 
         // parse specific object
         if (objectName == "template")

+ 4 - 4
code/AssetLib/XGL/XGLLoader.cpp

@@ -130,13 +130,13 @@ void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 #else
 		std::unique_ptr<StreamReaderLE> raw_reader(new StreamReaderLE(stream));
 
-        Compression c;
+        Compression compression;
         size_t total = 0l;
-        if (c.open(Compression::Format::Binary)) {
+        if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush)) {
             // skip two extra bytes, zgl files do carry a crc16 upfront (I think)
             raw_reader->IncPtr(2);
-            total = c.decompress((unsigned char *)raw_reader->GetPtr(), raw_reader->GetRemainingSize(), uncompressed);
-            c.close();
+            total = compression.decompress((unsigned char *)raw_reader->GetPtr(), raw_reader->GetRemainingSize(), uncompressed);
+            compression.close();
         }
 		// replace the input stream with a memory stream
 		stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t *>(uncompressed.data()), total));

+ 52 - 21
code/Common/Compression.cpp

@@ -54,9 +54,12 @@ namespace Assimp {
 struct Compression::impl {
     bool mOpen;
     z_stream mZSstream;
-
+    FlushMode mFlushMode;
     impl() :
-            mOpen(false) {}
+            mOpen(false),
+            mFlushMode(Compression::FlushMode::NoFlush) {
+        // empty
+    }
 };
 
 Compression::Compression() :
@@ -70,7 +73,7 @@ Compression::~Compression() {
     delete mImpl;
 }
 
-bool Compression::open(Format format) {
+bool Compression::open(Format format, FlushMode flush) {
     ai_assert(mImpl != nullptr);
 
     if (mImpl->mOpen) {
@@ -81,6 +84,7 @@ bool Compression::open(Format format) {
     mImpl->mZSstream.opaque = Z_NULL;
     mImpl->mZSstream.zalloc = Z_NULL;
     mImpl->mZSstream.zfree = Z_NULL;
+    mImpl->mFlushMode = flush;
     if (format == Format::Binary) {
         mImpl->mZSstream.data_type = Z_BINARY;
     } else {
@@ -88,7 +92,7 @@ bool Compression::open(Format format) {
     }
 
     // raw decompression without a zlib or gzip header
-    inflateInit2(&mImpl->mZSstream, -MAX_WBITS);
+    inflateInit(&mImpl->mZSstream);
     mImpl->mOpen = true;
 
     return mImpl->mOpen;
@@ -96,30 +100,62 @@ bool Compression::open(Format format) {
 
 constexpr size_t MYBLOCK = 32786;
 
+static int getFlushMode(Compression::FlushMode flush) {
+    int z_flush = 0;
+    switch (flush) {
+        case Compression::FlushMode::NoFlush:
+            z_flush = Z_NO_FLUSH;
+            break;
+        case Compression::FlushMode::SyncFlush:
+            z_flush = Z_SYNC_FLUSH;
+            break;
+        case Compression::FlushMode::Finish:
+            z_flush = Z_FINISH;
+            break;
+        default:
+            ai_assert(false);
+            break;
+    }
+
+    return z_flush;
+}
+
 size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) {
     ai_assert(mImpl != nullptr);
 
     mImpl->mZSstream.next_in = (Bytef*)(data);
     mImpl->mZSstream.avail_in = (uInt)in;
 
-    Bytef block[MYBLOCK] = {};
     int ret = 0;
     size_t total = 0l;
-    do {
-        mImpl->mZSstream.avail_out = MYBLOCK;
-        mImpl->mZSstream.next_out = block;
-        
-        ret = inflate(&mImpl->mZSstream, Z_NO_FLUSH);
+
+    const int flushMode = getFlushMode(mImpl->mFlushMode);
+    if (flushMode == Z_FINISH) {
+        mImpl->mZSstream.avail_out = static_cast<uInt>(uncompressed.size());
+        mImpl->mZSstream.next_out = reinterpret_cast<Bytef *>(&*uncompressed.begin());
+        ret = inflate(&mImpl->mZSstream, Z_FINISH);
 
         if (ret != Z_STREAM_END && ret != Z_OK) {
             throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
-
         }
-        const size_t have = MYBLOCK - mImpl->mZSstream.avail_out;
-        total += have;
-        uncompressed.resize(total);
-        ::memcpy(uncompressed.data() + total - have, block, have);
-    } while (ret != Z_STREAM_END);
+        total = mImpl->mZSstream.avail_out;
+    } else {
+        do {
+            Bytef block[MYBLOCK] = {};
+            mImpl->mZSstream.avail_out = MYBLOCK;
+            mImpl->mZSstream.next_out = block;
+
+            ret = inflate(&mImpl->mZSstream, flushMode);
+
+            if (ret != Z_STREAM_END && ret != Z_OK) {
+                throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
+            }
+            const size_t have = MYBLOCK - mImpl->mZSstream.avail_out;
+            total += have;
+            uncompressed.resize(total);
+            ::memcpy(uncompressed.data() + total - have, block, have);
+        } while (ret != Z_STREAM_END);
+    }
 
     return total;
 }
@@ -140,11 +176,6 @@ size_t Compression::decompressBlock(const void *data, size_t in, char *out, size
     ::inflateReset(&mImpl->mZSstream);
     ::inflateSetDictionary(&mImpl->mZSstream, (const Bytef *)out, (uInt)availableOut - mImpl->mZSstream.avail_out);
 
-
-
-    ::inflateReset(&mImpl->mZSstream);
-    ::inflateSetDictionary(&mImpl->mZSstream, (const Bytef *)out, (uInt)availableOut - mImpl->mZSstream.avail_out);
-
     return availableOut - (size_t)mImpl->mZSstream.avail_out;
 }
 

+ 11 - 1
code/Common/Compression.h

@@ -55,6 +55,16 @@ public:
         NumFormats,
         InvalidFormat
     };
+
+    enum class FlushMode {
+        NoFlush = 0,
+        SyncFlush,
+        Finish,
+
+        NumModes,
+        InvalidMode
+    };
+
     /// @brief  The class constructor.
     Compression();
 
@@ -63,7 +73,7 @@ public:
 
     /// @brief  Will open the access to the compression.
     /// @return true if close was successful, false if not.
-    bool open(Format format);
+    bool open(Format format, FlushMode flush);
 
     /// @brief  Will return the open state.
     /// @return true if the access is opened, false if not.

+ 1 - 1
test/unit/utFBXImporterExporter.cpp

@@ -53,7 +53,7 @@ using namespace Assimp;
 
 class utFBXImporterExporter : public AbstractImportExportBase {
 public:
-    virtual bool importerTest() {
+    bool importerTest() override {
         Assimp::Importer importer;
         const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/spider.fbx", aiProcess_ValidateDataStructure);
         return nullptr != scene;