1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2022, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14 copyright notice, this list of conditions and the
15 following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18 copyright notice, this list of conditions and the
19 following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23 contributors may be used to endorse or promote products
24 derived from this software without specific prior
25 written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42#include "Compression.h"
43#include <assimp/ai_assert.h>
44#include <assimp/Exceptional.h>
45
46namespace Assimp {
47
48struct Compression::impl {
49 bool mOpen;
50 z_stream mZSstream;
51 FlushMode mFlushMode;
52
53 impl() :
54 mOpen(false),
55 mZSstream(),
56 mFlushMode(Compression::FlushMode::NoFlush) {
57 // empty
58 }
59};
60
61Compression::Compression() :
62 mImpl(new impl) {
63 // empty
64}
65
66Compression::~Compression() {
67 ai_assert(mImpl != nullptr);
68
69 delete mImpl;
70}
71
72bool Compression::open(Format format, FlushMode flush, int windowBits) {
73 ai_assert(mImpl != nullptr);
74
75 if (mImpl->mOpen) {
76 return false;
77 }
78
79 // build a zlib stream
80 mImpl->mZSstream.opaque = Z_NULL;
81 mImpl->mZSstream.zalloc = Z_NULL;
82 mImpl->mZSstream.zfree = Z_NULL;
83 mImpl->mFlushMode = flush;
84 if (format == Format::Binary) {
85 mImpl->mZSstream.data_type = Z_BINARY;
86 } else {
87 mImpl->mZSstream.data_type = Z_ASCII;
88 }
89
90 // raw decompression without a zlib or gzip header
91 if (windowBits == 0) {
92 inflateInit(&mImpl->mZSstream);
93 } else {
94 inflateInit2(&mImpl->mZSstream, windowBits);
95 }
96 mImpl->mOpen = true;
97
98 return mImpl->mOpen;
99}
100
101static int getFlushMode(Compression::FlushMode flush) {
102 int z_flush = 0;
103 switch (flush) {
104 case Compression::FlushMode::NoFlush:
105 z_flush = Z_NO_FLUSH;
106 break;
107 case Compression::FlushMode::Block:
108 z_flush = Z_BLOCK;
109 break;
110 case Compression::FlushMode::Tree:
111 z_flush = Z_TREES;
112 break;
113 case Compression::FlushMode::SyncFlush:
114 z_flush = Z_SYNC_FLUSH;
115 break;
116 case Compression::FlushMode::Finish:
117 z_flush = Z_FINISH;
118 break;
119 default:
120 ai_assert(false);
121 break;
122 }
123
124 return z_flush;
125}
126
127constexpr size_t MYBLOCK = 32786;
128
129size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) {
130 ai_assert(mImpl != nullptr);
131 if (data == nullptr || in == 0) {
132 return 0l;
133 }
134
135 mImpl->mZSstream.next_in = (Bytef*)(data);
136 mImpl->mZSstream.avail_in = (uInt)in;
137
138 int ret = 0;
139 size_t total = 0l;
140 const int flushMode = getFlushMode(flush: mImpl->mFlushMode);
141 if (flushMode == Z_FINISH) {
142 mImpl->mZSstream.avail_out = static_cast<uInt>(uncompressed.size());
143 mImpl->mZSstream.next_out = reinterpret_cast<Bytef *>(&*uncompressed.begin());
144 ret = inflate(strm: &mImpl->mZSstream, Z_FINISH);
145
146 if (ret != Z_STREAM_END && ret != Z_OK) {
147 throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
148 }
149 total = mImpl->mZSstream.avail_out;
150 } else {
151 do {
152 Bytef block[MYBLOCK] = {};
153 mImpl->mZSstream.avail_out = MYBLOCK;
154 mImpl->mZSstream.next_out = block;
155
156 ret = inflate(strm: &mImpl->mZSstream, flush: flushMode);
157
158 if (ret != Z_STREAM_END && ret != Z_OK) {
159 throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
160 }
161 const size_t have = MYBLOCK - mImpl->mZSstream.avail_out;
162 total += have;
163 uncompressed.resize(new_size: total);
164 ::memcpy(dest: uncompressed.data() + total - have, src: block, n: have);
165 } while (ret != Z_STREAM_END);
166 }
167
168 return total;
169}
170
171size_t Compression::decompressBlock(const void *data, size_t in, char *out, size_t availableOut) {
172 ai_assert(mImpl != nullptr);
173 if (data == nullptr || in == 0 || out == nullptr || availableOut == 0) {
174 return 0l;
175 }
176
177 // push data to the stream
178 mImpl->mZSstream.next_in = (Bytef *)data;
179 mImpl->mZSstream.avail_in = (uInt)in;
180 mImpl->mZSstream.next_out = (Bytef *)out;
181 mImpl->mZSstream.avail_out = (uInt)availableOut;
182
183 // and decompress the data ....
184 int ret = ::inflate(strm: &mImpl->mZSstream, Z_SYNC_FLUSH);
185 if (ret != Z_OK && ret != Z_STREAM_END) {
186 throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data");
187 }
188
189 ::inflateReset(strm: &mImpl->mZSstream);
190 ::inflateSetDictionary(strm: &mImpl->mZSstream, dictionary: (const Bytef *)out, dictLength: (uInt)availableOut - mImpl->mZSstream.avail_out);
191
192 return availableOut - (size_t)mImpl->mZSstream.avail_out;
193}
194
195bool Compression::isOpen() const {
196 ai_assert(mImpl != nullptr);
197
198 return mImpl->mOpen;
199}
200
201bool Compression::close() {
202 ai_assert(mImpl != nullptr);
203
204 if (!mImpl->mOpen) {
205 return false;
206 }
207
208 inflateEnd(strm: &mImpl->mZSstream);
209 mImpl->mOpen = false;
210
211 return true;
212}
213
214} // namespace Assimp
215

source code of qtquick3d/src/3rdparty/assimp/src/code/Common/Compression.cpp