mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-08-11 00:29:53 +00:00
Drop use of tempfiles when loading compressed files.
Also simplified .zga texture and .aqs savegame loading. Dropped support for "crunched" .sav files (those were never used), and the corresponding crunch functions. To be done: Temp files are still used when compressing files, will address this in a later commit.
This commit is contained in:
parent
321a65a9fb
commit
75e7b137d6
11 changed files with 914 additions and 227 deletions
259
BBGE/DeflateCompressor.cpp
Normal file
259
BBGE/DeflateCompressor.cpp
Normal file
|
@ -0,0 +1,259 @@
|
|||
#include "Base.h"
|
||||
|
||||
#include <zutil.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "DeflateCompressor.h"
|
||||
|
||||
// for weird gcc/mingw hackfix below
|
||||
#include <string.h>
|
||||
|
||||
|
||||
DeflateCompressor::DeflateCompressor()
|
||||
: _windowBits(-MAX_WBITS), // negative, because we want a raw deflate stream, and not zlib-wrapped
|
||||
_forceCompress(false),
|
||||
_iscompressed(false),
|
||||
_real_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
ZlibCompressor::ZlibCompressor()
|
||||
: DeflateCompressor()
|
||||
{
|
||||
_windowBits = MAX_WBITS; // positive, means we use a zlib-wrapped deflate stream
|
||||
}
|
||||
|
||||
GzipCompressor::GzipCompressor()
|
||||
: DeflateCompressor()
|
||||
{
|
||||
_windowBits = MAX_WBITS + 16; // this makes zlib wrap a minimal gzip header around the stream
|
||||
_forceCompress = true; // we want this for gzip
|
||||
}
|
||||
|
||||
void DeflateCompressor::compress(void* dst, uint32 *dst_size, const void* src, uint32 src_size,
|
||||
uint8 level, int wbits)
|
||||
{
|
||||
z_stream c_stream;
|
||||
|
||||
c_stream.zalloc = (alloc_func)Z_NULL;
|
||||
c_stream.zfree = (free_func)Z_NULL;
|
||||
c_stream.opaque = (voidpf)Z_NULL;
|
||||
|
||||
if (Z_OK != deflateInit2(&c_stream, level, Z_DEFLATED, wbits, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY))
|
||||
{
|
||||
*dst_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
c_stream.next_out = (Bytef*)dst;
|
||||
c_stream.avail_out = *dst_size;
|
||||
c_stream.next_in = (Bytef*)src;
|
||||
c_stream.avail_in = (uInt)src_size;
|
||||
|
||||
if (Z_OK != deflate(&c_stream, Z_NO_FLUSH))
|
||||
{
|
||||
errorLog("ZLIB: Can't compress (zlib: deflate)");
|
||||
*dst_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (c_stream.avail_in != 0)
|
||||
{
|
||||
errorLog("Can't compress (zlib: deflate not greedy)");
|
||||
*dst_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Z_STREAM_END != deflate(&c_stream, Z_FINISH))
|
||||
{
|
||||
errorLog("Can't compress (zlib: deflate, finish)");
|
||||
*dst_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Z_OK != deflateEnd(&c_stream))
|
||||
{
|
||||
errorLog("Can't compress (zlib: deflateEnd)");
|
||||
*dst_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*dst_size = c_stream.total_out;
|
||||
}
|
||||
|
||||
void DeflateCompressor::decompress(void *dst, uint32 *origsize, const void *src, uint32 size, int wbits)
|
||||
{
|
||||
z_stream stream;
|
||||
int err;
|
||||
|
||||
stream.next_in = (Bytef*)src;
|
||||
stream.avail_in = (uInt)size;
|
||||
stream.next_out = (Bytef*)dst;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
stream.avail_out = *origsize;
|
||||
stream.total_out = 0;
|
||||
|
||||
err = inflateInit2(&stream, wbits);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
*origsize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
err = inflate(&stream, Z_FINISH);
|
||||
if (err != Z_STREAM_END)
|
||||
{
|
||||
inflateEnd(&stream);
|
||||
*origsize = 0;
|
||||
return;
|
||||
}
|
||||
*origsize = (uint32)stream.total_out;
|
||||
|
||||
err = inflateEnd(&stream);
|
||||
if(err != Z_OK)
|
||||
*origsize = 0;
|
||||
}
|
||||
|
||||
|
||||
void DeflateCompressor::Compress(uint8 level)
|
||||
{
|
||||
if(!_forceCompress && (!level || _iscompressed || (!size())))
|
||||
return;
|
||||
|
||||
char *buf;
|
||||
|
||||
|
||||
uint32 oldsize = size();
|
||||
uint32 newsize = compressBound(oldsize) + 30; // for optional gzip header
|
||||
|
||||
buf = new char[newsize];
|
||||
|
||||
compress((void*)buf, &newsize, (void*)contents(), oldsize, level, _windowBits);
|
||||
if(!newsize || (!_forceCompress && newsize > oldsize)) // only allow more data if compression is forced (which is the case for gzip)
|
||||
{
|
||||
delete [] buf;
|
||||
return;
|
||||
}
|
||||
|
||||
resize(newsize);
|
||||
rpos(0);
|
||||
wpos(0);
|
||||
append(buf,newsize);
|
||||
delete [] buf;
|
||||
|
||||
_iscompressed = true;
|
||||
|
||||
_real_size = oldsize;
|
||||
}
|
||||
|
||||
void DeflateCompressor::Decompress(void)
|
||||
{
|
||||
if( (!_iscompressed) || (!size()))
|
||||
return;
|
||||
|
||||
if(!_real_size)
|
||||
{
|
||||
if(decompressBlockwise() == Z_OK)
|
||||
_iscompressed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 rs = (uint32)_real_size;
|
||||
uint32 origsize = rs;
|
||||
uint8 *target = new uint8[rs];
|
||||
wpos(0);
|
||||
rpos(0);
|
||||
decompress((void*)target, &origsize, (const void*)contents(), size(), _windowBits);
|
||||
if(origsize != rs)
|
||||
{
|
||||
char errbuf[256];
|
||||
sprintf(errbuf, "DeflateCompressor: Inflate error! result=%d cursize=%u origsize=%u realsize=%u",size(),origsize,rs);
|
||||
errorLog(errbuf);
|
||||
delete [] target;
|
||||
return;
|
||||
}
|
||||
clear();
|
||||
append(target, origsize);
|
||||
delete [] target;
|
||||
_real_size = 0;
|
||||
_iscompressed = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define CHUNK 16384
|
||||
|
||||
int DeflateCompressor::decompressBlockwise()
|
||||
{
|
||||
int ret;
|
||||
unsigned have;
|
||||
z_stream strm;
|
||||
unsigned char out[CHUNK];
|
||||
|
||||
/* allocate inflate state */
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.avail_in = 0;
|
||||
strm.next_in = Z_NULL;
|
||||
ret = inflateInit2(&strm, _windowBits);
|
||||
if (ret != Z_OK)
|
||||
return ret;
|
||||
|
||||
ByteBuffer bb;
|
||||
|
||||
strm.avail_in = size();
|
||||
strm.next_in = contents();
|
||||
|
||||
/* decompress until deflate stream ends or end of file */
|
||||
do {
|
||||
/* run inflate() on input until output buffer not full */
|
||||
do {
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
ret = inflate(&strm, Z_NO_FLUSH);
|
||||
switch (ret) {
|
||||
case Z_NEED_DICT:
|
||||
case Z_STREAM_ERROR:
|
||||
ret = Z_DATA_ERROR; /* and fall through */
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
(void)inflateEnd(&strm);
|
||||
return ret;
|
||||
}
|
||||
have = CHUNK - strm.avail_out;
|
||||
bb.append(out, have);
|
||||
} while (strm.avail_out == 0);
|
||||
/* done when inflate() says it's done */
|
||||
} while (ret != Z_STREAM_END);
|
||||
|
||||
/* clean up and return */
|
||||
(void)inflateEnd(&strm);
|
||||
|
||||
if (ret != Z_STREAM_END)
|
||||
return Z_DATA_ERROR;
|
||||
|
||||
// exchange pointer
|
||||
clear();
|
||||
init(bb, TAKE_OVER);
|
||||
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
void GzipCompressor::Decompress(void)
|
||||
{
|
||||
uint32 t = 0;
|
||||
rpos(size() - sizeof(uint32)); // according to RFC 1952, input size are the last 4 bytes at the end of the file, in little endian
|
||||
*this >> t;
|
||||
_real_size = t;
|
||||
|
||||
// !! NOTE: this fixes a gcc/mingw bug where _real_size would be set incorrectly
|
||||
#if __GNUC__
|
||||
char xx[20];
|
||||
sprintf(xx, "%u", t);
|
||||
#endif
|
||||
|
||||
DeflateCompressor::Decompress(); // will set rpos back anyway
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue