1 /**
2  * Copyright (c) 2006-2016 LOVE Development Team
3  *
4  * This software is provided 'as-is', without any express or implied
5  * warranty.  In no event will the authors be held liable for any damages
6  * arising from the use of this software.
7  *
8  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  *
12  * 1. The origin of this software must not be misrepresented; you must not
13  *    claim that you wrote the original software. If you use this software
14  *    in a product, an acknowledgment in the product documentation would be
15  *    appreciated but is not required.
16  * 2. Altered source versions must be plainly marked as such, and must not be
17  *    misrepresented as being the original software.
18  * 3. This notice may not be removed or altered from any source distribution.
19  **/
20 
21 // LOVE
22 #include "Compressor.h"
23 #include "common/config.h"
24 #include "common/int.h"
25 
26 // LZ4
27 #include "libraries/lz4/lz4.h"
28 #include "libraries/lz4/lz4hc.h"
29 
30 // zlib
31 #include <zlib.h>
32 
33 namespace love
34 {
35 namespace math
36 {
37 
38 class LZ4Compressor : public Compressor
39 {
40 public:
41 
compress(Format format,const char * data,size_t dataSize,int level,size_t & compressedSize)42 	char *compress(Format format, const char *data, size_t dataSize, int level, size_t &compressedSize) override
43 	{
44 		if (format != FORMAT_LZ4)
45 			throw love::Exception("Invalid format (expecting LZ4)");
46 
47 		if (dataSize > LZ4_MAX_INPUT_SIZE)
48 			throw love::Exception("Data is too large for LZ4 compressor.");
49 
50 		// We use a custom header to store some info with the compressed data.
51 		const size_t headersize = sizeof(uint32);
52 
53 		int maxdestsize = LZ4_compressBound((int) dataSize);
54 		size_t maxsize = headersize + (size_t) maxdestsize;
55 		char *compressedbytes = nullptr;
56 
57 		try
58 		{
59 			compressedbytes = new char[maxsize];
60 		}
61 		catch (std::bad_alloc &)
62 		{
63 			throw love::Exception("Out of memory.");
64 		}
65 
66 		// Store the size of the uncompressed data as a header.
67 #ifdef LOVE_BIG_ENDIAN
68 		// Make sure it's little-endian for storage.
69 		*(uint32 *) compressedbytes = swapuint32((uint32) dataSize);
70 #else
71 		*(uint32 *) compressedbytes = (uint32) dataSize;
72 #endif
73 
74 		// Use LZ4-HC for compression level 9 and higher.
75 		int csize = 0;
76 		if (level > 8)
77 			csize = LZ4_compress_HC(data, compressedbytes + headersize, (int) dataSize, maxdestsize, 0);
78 		else
79 			csize = LZ4_compress_default(data, compressedbytes + headersize, (int) dataSize, maxdestsize);
80 
81 		if (csize <= 0)
82 		{
83 			delete[] compressedbytes;
84 			throw love::Exception("Could not LZ4-compress data.");
85 		}
86 
87 		// We allocated space for the maximum possible amount of data, but the
88 		// actual compressed size might be much smaller, so we should shrink the
89 		// data buffer if so.
90 		if ((double) maxsize / (double) (csize + headersize) >= 1.2)
91 		{
92 			char *cbytes = new (std::nothrow) char[csize + headersize];
93 			if (cbytes)
94 			{
95 				memcpy(cbytes, compressedbytes, csize + headersize);
96 				delete[] compressedbytes;
97 				compressedbytes = cbytes;
98 			}
99 		}
100 
101 		compressedSize = (size_t) csize + headersize;
102 		return compressedbytes;
103 	}
104 
decompress(Format format,const char * data,size_t dataSize,size_t & decompressedSize)105 	char *decompress(Format format, const char *data, size_t dataSize, size_t &decompressedSize) override
106 	{
107 		if (format != FORMAT_LZ4)
108 			throw love::Exception("Invalid format (expecting LZ4)");
109 
110 		const size_t headersize = sizeof(uint32);
111 		char *rawbytes = nullptr;
112 
113 		if (dataSize < headersize)
114 			throw love::Exception("Invalid LZ4-compressed data size.");
115 
116 		// Extract the original uncompressed size (stored in our custom header.)
117 #ifdef LOVE_BIG_ENDIAN
118 		// Convert from stored little-endian to big-endian.
119 		uint32 rawsize = swapuint32(*(uint32 *) data);
120 #else
121 		uint32 rawsize = *(uint32 *) data;
122 #endif
123 
124 		try
125 		{
126 			rawbytes = new char[rawsize];
127 		}
128 		catch (std::bad_alloc &)
129 		{
130 			throw love::Exception("Out of memory.");
131 		}
132 
133 		// If the uncompressed size is passed in as an argument (non-zero) and
134 		// it matches the header's stored size, then we assume it's 100% accurate
135 		// and we use a more efficient decompression function.
136 		if (decompressedSize > 0 && decompressedSize == (size_t) rawsize)
137 		{
138 			// We don't use the header here, but we need to account for its size.
139 			if (LZ4_decompress_fast(data + headersize, rawbytes, (int) decompressedSize) < 0)
140 			{
141 				delete[] rawbytes;
142 				throw love::Exception("Could not decompress LZ4-compressed data.");
143 			}
144 		}
145 		else
146 		{
147 			// Account for our custom header's size in the decompress arguments.
148 			int result = LZ4_decompress_safe(data + headersize, rawbytes,
149 			                                 dataSize - headersize, rawsize);
150 
151 			if (result < 0)
152 			{
153 				delete[] rawbytes;
154 				throw love::Exception("Could not decompress LZ4-compressed data.");
155 			}
156 
157 			decompressedSize = (size_t) result;
158 		}
159 
160 		return rawbytes;
161 	}
162 
isSupported(Format format) const163 	bool isSupported(Format format) const override
164 	{
165 		return format == FORMAT_LZ4;
166 	}
167 
168 }; // LZ4Compressor
169 
170 
171 class zlibCompressor : public Compressor
172 {
173 private:
174 
175 	// The following three functions are mostly copied from the zlib source
176 	// (compressBound, compress2, and uncompress), but modified to support both
177 	// zlib and gzip.
178 
zlibCompressBound(Format format,uLong sourceLen)179 	uLong zlibCompressBound(Format format, uLong sourceLen)
180 	{
181 		uLong size = sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13;
182 
183 		// The gzip header is slightly larger than the zlib header.
184 		if (format == FORMAT_GZIP)
185 			size += 18 - 6;
186 
187 		return size;
188 	}
189 
zlibCompress(Format format,Bytef * dest,uLongf * destLen,const Bytef * source,uLong sourceLen,int level)190 	int zlibCompress(Format format, Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)
191 	{
192 		z_stream stream = {};
193 
194 		stream.next_in = (Bytef *) source;
195 		stream.avail_in = (uInt) sourceLen;
196 
197 		stream.next_out = dest;
198 		stream.avail_out = (uInt) (*destLen);
199 
200 		int windowbits = 15;
201 		if (format == FORMAT_GZIP)
202 			windowbits += 16; // This tells zlib to use a gzip header.
203 
204 		int err = deflateInit2(&stream, level, Z_DEFLATED, windowbits, 8, Z_DEFAULT_STRATEGY);
205 
206 		if (err != Z_OK)
207 			return err;
208 
209 		err = deflate(&stream, Z_FINISH);
210 
211 		if (err != Z_STREAM_END)
212 		{
213 			deflateEnd(&stream);
214 			return err == Z_OK ? Z_BUF_ERROR : err;
215 		}
216 
217 		*destLen = stream.total_out;
218 
219 		return deflateEnd(&stream);
220 	}
221 
zlibDecompress(Bytef * dest,uLongf * destLen,const Bytef * source,uLong sourceLen)222 	int zlibDecompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
223 	{
224 		z_stream stream = {};
225 
226 		stream.next_in = (Bytef *) source;
227 		stream.avail_in = (uInt) sourceLen;
228 
229 		stream.next_out = dest;
230 		stream.avail_out = (uInt) (*destLen);
231 
232 		// 15 is the default. Adding 32 makes zlib auto-detect the header type.
233 		int windowbits = 15 + 32;
234 
235 		int err = inflateInit2(&stream, windowbits);
236 
237 		if (err != Z_OK)
238 			return err;
239 
240 		err = inflate(&stream, Z_FINISH);
241 
242 		if (err != Z_STREAM_END)
243 		{
244 			inflateEnd(&stream);
245 			if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
246 				return Z_DATA_ERROR;
247 			return err;
248 		}
249 
250 		*destLen = stream.total_out;
251 
252 		return inflateEnd(&stream);
253 	}
254 
255 public:
256 
compress(Format format,const char * data,size_t dataSize,int level,size_t & compressedSize)257 	char *compress(Format format, const char *data, size_t dataSize, int level, size_t &compressedSize) override
258 	{
259 		if (!isSupported(format))
260 			throw love::Exception("Invalid format (expecting zlib or gzip)");
261 
262 		if (level < 0)
263 			level = Z_DEFAULT_COMPRESSION;
264 		else if (level > 9)
265 			level = 9;
266 
267 		uLong maxsize = zlibCompressBound(format, (uLong) dataSize);
268 		char *compressedbytes = nullptr;
269 
270 		try
271 		{
272 			compressedbytes = new char[maxsize];
273 		}
274 		catch (std::bad_alloc &)
275 		{
276 			throw love::Exception("Out of memory.");
277 		}
278 
279 		uLongf destlen = maxsize;
280 		int status = zlibCompress(format, (Bytef *) compressedbytes, &destlen, (const Bytef *) data, (uLong) dataSize, level);
281 
282 		if (status != Z_OK)
283 		{
284 			delete[] compressedbytes;
285 			throw love::Exception("Could not zlib/gzip-compress data.");
286 		}
287 
288 		// We allocated space for the maximum possible amount of data, but the
289 		// actual compressed size might be much smaller, so we should shrink the
290 		// data buffer if so.
291 		if ((double) maxsize / (double) destlen >= 1.3)
292 		{
293 			char *cbytes = new (std::nothrow) char[destlen];
294 			if (cbytes)
295 			{
296 				memcpy(cbytes, compressedbytes, destlen);
297 				delete[] compressedbytes;
298 				compressedbytes = cbytes;
299 			}
300 		}
301 
302 		compressedSize = (size_t) destlen;
303 		return compressedbytes;
304 	}
305 
decompress(Format format,const char * data,size_t dataSize,size_t & decompressedSize)306 	char *decompress(Format format, const char *data, size_t dataSize, size_t &decompressedSize) override
307 	{
308 		if (!isSupported(format))
309 			throw love::Exception("Invalid format (expecting zlib or gzip)");
310 
311 		char *rawbytes = nullptr;
312 
313 		// We might know the output size before decompression. If not, we guess.
314 		size_t rawsize = decompressedSize > 0 ? decompressedSize : dataSize * 2;
315 
316 		// Repeatedly try to decompress with an increasingly large output buffer.
317 		while (true)
318 		{
319 			try
320 			{
321 				rawbytes = new char[rawsize];
322 			}
323 			catch (std::bad_alloc &)
324 			{
325 				throw love::Exception("Out of memory.");
326 			}
327 
328 			uLongf destLen = (uLongf) rawsize;
329 			int status = zlibDecompress((Bytef *) rawbytes, &destLen, (const Bytef *) data, (uLong) dataSize);
330 
331 			if (status == Z_OK)
332 			{
333 				decompressedSize = (size_t) destLen;
334 				break;
335 			}
336 			else if (status != Z_BUF_ERROR)
337 			{
338 				// For any error other than "not enough room", throw an exception.
339 				delete[] rawbytes;
340 				throw love::Exception("Could not decompress zlib/gzip-compressed data.");
341 			}
342 
343 			// Not enough room in the output buffer: try again with a larger size.
344 			delete[] rawbytes;
345 			rawsize *= 2;
346 		}
347 
348 		return rawbytes;
349 	}
350 
isSupported(Format format) const351 	bool isSupported(Format format) const override
352 	{
353 		return format == FORMAT_ZLIB || format == FORMAT_GZIP;
354 	}
355 
356 }; // zlibCompressor
357 
getCompressor(Format format)358 Compressor *Compressor::getCompressor(Format format)
359 {
360 	static LZ4Compressor lz4compressor;
361 	static zlibCompressor zlibcompressor;
362 
363 	Compressor *compressors[] = {&lz4compressor, &zlibcompressor};
364 
365 	for (Compressor *c : compressors)
366 	{
367 		if (c->isSupported(format))
368 			return c;
369 	}
370 
371 	return nullptr;
372 }
373 
getConstant(const char * in,Format & out)374 bool Compressor::getConstant(const char *in, Format &out)
375 {
376 	return formatNames.find(in, out);
377 }
378 
getConstant(Format in,const char * & out)379 bool Compressor::getConstant(Format in, const char *&out)
380 {
381 	return formatNames.find(in, out);
382 }
383 
384 StringMap<Compressor::Format, Compressor::FORMAT_MAX_ENUM>::Entry Compressor::formatEntries[] =
385 {
386 	{"lz4",  FORMAT_LZ4},
387 	{"zlib", FORMAT_ZLIB},
388 	{"gzip", FORMAT_GZIP},
389 };
390 
391 StringMap<Compressor::Format, Compressor::FORMAT_MAX_ENUM> Compressor::formatNames(Compressor::formatEntries, sizeof(Compressor::formatEntries));
392 
393 } // math
394 } // love
395