Fix X-Importer decompress algorithm

pull/4381/head
Kim Kulling 2022-02-08 21:43:14 +01:00
parent 27bcddfb1a
commit 23b43d1825
3 changed files with 43 additions and 64 deletions

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -60,26 +58,11 @@ using namespace Assimp::Formatter;
#ifndef ASSIMP_BUILD_NO_COMPRESSED_X #ifndef ASSIMP_BUILD_NO_COMPRESSED_X
/* #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
#include <zlib.h>
#else
#include "../contrib/zlib/zlib.h"
#endif*/
#include "Common/Compression.h" #include "Common/Compression.h"
// Magic identifier for MSZIP compressed data // Magic identifier for MSZIP compressed data
#define MSZIP_MAGIC 0x4B43 constexpr unsigned int MSZIP_MAGIC = 0x4B43;
#define MSZIP_BLOCK 32786 constexpr size_t MSZIP_BLOCK = 32786l;
// ------------------------------------------------------------------------------------------------
// Dummy memory wrappers for use with zlib
/* static void *dummy_alloc(void * opaque, unsigned int items, unsigned int size) {
return ::operator new(items *size);
}
static void dummy_free(void * opaque, void *address) {
return ::operator delete(address);
}*/
#endif // !! ASSIMP_BUILD_NO_COMPRESSED_X #endif // !! ASSIMP_BUILD_NO_COMPRESSED_X
@ -172,17 +155,6 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
* /////////////////////////////////////////////////////////////////////// * ///////////////////////////////////////////////////////////////////////
*/ */
Compression compression;
// build a zlib stream
/* z_stream stream;
stream.opaque = nullptr;
stream.zalloc = &dummy_alloc;
stream.zfree = &dummy_free;
stream.data_type = (mIsBinaryFormat ? Z_BINARY : Z_ASCII);
// initialize the inflation algorithm
::inflateInit2(&stream, -MAX_WBITS);*/
// skip unknown data (checksum, flags?) // skip unknown data (checksum, flags?)
mP += 6; mP += 6;
@ -211,45 +183,25 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
P1 += ofs; P1 += ofs;
est_out += MSZIP_BLOCK; // one decompressed block is 32786 in size est_out += MSZIP_BLOCK; // one decompressed block is 32786 in size
} }
// Allocate storage and terminating zero and do the actual uncompressing // Allocate storage and terminating zero and do the actual uncompressing
Compression compression;
uncompressed.resize(est_out + 1); uncompressed.resize(est_out + 1);
char *out = &uncompressed.front(); 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.decompress(mP, std::distance(mP, mEnd-3), uncompressed); while (mP + 3 < mEnd) {
uint16_t ofs = *((uint16_t *)mP);
AI_SWAP2(ofs);
mP += 4;
if (mP + ofs > mEnd + 2) {
throw DeadlyImportError("X: Unexpected EOF in compressed chunk");
}
out += compression.decompressBlock(mP, ofs, out, MSZIP_BLOCK);
mP += ofs;
}
compression.close(); compression.close();
} }
/* while (mP + 3 < mEnd) {
uint16_t ofs = *((uint16_t *)mP);
AI_SWAP2(ofs);
mP += 4;
if (mP + ofs > mEnd + 2) {
throw DeadlyImportError("X: Unexpected EOF in compressed chunk");
}
// push data to the stream
stream.next_in = (Bytef *)mP;
stream.avail_in = ofs;
stream.next_out = (Bytef *)out;
stream.avail_out = MSZIP_BLOCK;
// and decompress the data ....
int ret = ::inflate(&stream, Z_SYNC_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END)
throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data");
::inflateReset(&stream);
::inflateSetDictionary(&stream, (const Bytef *)out, MSZIP_BLOCK - stream.avail_out);
// and advance to the next offset
out += MSZIP_BLOCK - stream.avail_out;
mP += ofs;
}
// terminate zlib
::inflateEnd(&stream);*/
// ok, update pointers to point to the uncompressed file data // ok, update pointers to point to the uncompressed file data
mP = &uncompressed[0]; mP = &uncompressed[0];
@ -507,7 +459,7 @@ void XFileParser::ParseDataObjectSkinWeights(Mesh *pMesh) {
bone.mWeights.reserve(numWeights); bone.mWeights.reserve(numWeights);
for (unsigned int a = 0; a < numWeights; a++) { for (unsigned int a = 0; a < numWeights; a++) {
BoneWeight weight; BoneWeight weight = {};
weight.mVertex = ReadInt(); weight.mVertex = ReadInt();
bone.mWeights.push_back(weight); bone.mWeights.push_back(weight);
} }

View File

@ -108,6 +108,7 @@ size_t Compression::decompress(const void *data, size_t in, std::vector<char> &u
do { do {
mImpl->mZSstream.avail_out = MYBLOCK; mImpl->mZSstream.avail_out = MYBLOCK;
mImpl->mZSstream.next_out = block; mImpl->mZSstream.next_out = block;
ret = inflate(&mImpl->mZSstream, Z_NO_FLUSH); ret = inflate(&mImpl->mZSstream, Z_NO_FLUSH);
if (ret != Z_STREAM_END && ret != Z_OK) { if (ret != Z_STREAM_END && ret != Z_OK) {
@ -123,6 +124,30 @@ size_t Compression::decompress(const void *data, size_t in, std::vector<char> &u
return total; return total;
} }
size_t Compression::decompressBlock(const void *data, size_t in, char *out, size_t availableOut) {
// push data to the stream
mImpl->mZSstream.next_in = (Bytef *)data;
mImpl->mZSstream.avail_in = (uInt)in;
mImpl->mZSstream.next_out = (Bytef *)out;
mImpl->mZSstream.avail_out = (uInt)availableOut;
// and decompress the data ....
int ret = ::inflate(&mImpl->mZSstream, Z_SYNC_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END)
throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data");
::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;
}
bool Compression::isOpen() const { bool Compression::isOpen() const {
ai_assert(mImpl != nullptr); ai_assert(mImpl != nullptr);

View File

@ -79,6 +79,8 @@ public:
/// @param[out uncompressed A std::vector containing the decompressed data. /// @param[out uncompressed A std::vector containing the decompressed data.
size_t decompress(const void *data, size_t in, std::vector<char> &uncompressed); size_t decompress(const void *data, size_t in, std::vector<char> &uncompressed);
size_t decompressBlock(const void *data, size_t in, char *out, size_t availableOut);
private: private:
struct impl; struct impl;
impl *mImpl; impl *mImpl;