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