1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-01-24 17:26:41 +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:
fgenesis 2012-02-10 00:10:50 +01:00
parent 321a65a9fb
commit 75e7b137d6
11 changed files with 913 additions and 226 deletions

View file

@ -2468,6 +2468,9 @@ void Continuity::saveFile(int slot, Vector position, unsigned char *scrShotData,
doc.InsertEndChild(startData);
// FIXME: Patch TinyXML to write out a string and compress in-memory
doc.SaveFile(dsq->getSaveDirectory() + "/poot.tmp");
packFile(dsq->getSaveDirectory() + "/poot.tmp", getSaveFileName(slot, "aqs"), 9);
@ -2483,40 +2486,22 @@ std::string Continuity::getSaveFileName(int slot, const std::string &pfix)
void Continuity::loadFileData(int slot, TiXmlDocument &doc)
{
bool tmp = false;
std::string teh_file = dsq->continuity.getSaveFileName(slot, "aqs");
if (!exists(teh_file, false))
if (exists(teh_file))
{
teh_file = dsq->continuity.getSaveFileName(slot, "sav");
if (!exists(teh_file, false))
{
teh_file = dsq->continuity.getSaveFileName(slot, "xml");
}
else
{
uncrunchFile(teh_file, dsq->getSaveDirectory() + "/poot2.tmp");
unpackFile(dsq->getSaveDirectory() + "/poot2.tmp", dsq->getSaveDirectory() + "/poot.tmp");
remove((dsq->getSaveDirectory() + "/poot2.tmp").c_str());
teh_file = dsq->getSaveDirectory() + "/poot.tmp";
tmp = true;
}
unsigned long size = 0;
char *buf = readCompressedFile(teh_file, &size);
if (!doc.LoadMem(buf, size))
errorLog("Failed to load save data: " + teh_file);
return;
}
else
{
unpackFile(teh_file, dsq->getSaveDirectory() + "/poot.tmp");
teh_file = dsq->getSaveDirectory() + "/poot.tmp";
tmp = true;
teh_file = dsq->continuity.getSaveFileName(slot, "xml");
if (exists(teh_file))
{
if (!doc.LoadFile(teh_file))
errorLog("Failed to load save data: " + teh_file);
}
doc.LoadFile(teh_file);
if (tmp)
remove(teh_file.c_str());
}
void Continuity::loadFile(int slot)

View file

@ -3212,6 +3212,7 @@ void DSQ::doSaveSlotMenu(SaveSlotMode ssm, const Vector &position)
tgaSave(tempfile.c_str(), scrShotWidth, scrShotHeight, 32, scrShotData);
scrShotData = 0; // deleted by tgaSave()
// FIXME: Get rid of tempfile and compress in-memory
packFile(dsq->getSaveDirectory() + "/poot-s.tmp", os.str(),9);
remove((dsq->getSaveDirectory() + "/poot-s.tmp").c_str());
}

View file

@ -1001,86 +1001,6 @@ int unpackFile(const std::string &sourcef, const std::string &destf)
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
int encode[8] = {16, 32, 8, 4, 2, 1, 3, 5 };
void crunchFile(const std::string &file, const std::string &out, bool deleteOriginal)
{
FILE *f = fopen(core->adjustFilenameCase(file).c_str(), "rb"), *o = fopen(core->adjustFilenameCase(out).c_str(), "wb");
if (f && o)
{
char buf=0;
int rot = 0, add = 0;
while (true)
{
if (fread(&buf, sizeof(char), 1, f) != 1)
break;
buf += encode[rot] + add;
if (fwrite(&buf, sizeof(char), 1, o) != 1)
{
errorLog("Failed to write to " + out);
break;
}
rot++;
if (rot>=8)
{ rot=0; add++; }
}
fclose(f);
f=0;
fclose(o);
o=0;
}
if (f) fclose(f);
if (o) fclose(o);
if (deleteOriginal)
remove(file.c_str());
}
void uncrunchFile(const std::string &file, const std::string &out)
{
FILE *f = fopen(core->adjustFilenameCase(file).c_str(), "rb"), *o = fopen(core->adjustFilenameCase(out).c_str(), "wb");
if (f && o)
{
char buf=0;
int rot=0, add=0;
while (true)
{
if (fread(&buf, sizeof(char), 1, f) != 1)
break;
buf -= encode[rot] + add;
if (fwrite(&buf, sizeof(char), 1, o) != 1)
{
errorLog("Failed to write to " + out);
break;
}
rot++;
if (rot>=8)
{ rot=0; add++; }
}
fclose(f);
f=0;
fclose(o);
o=0;
}
if (f) fclose(f);
if (o) fclose(o);
}
void openURL(const std::string &url)
{
#ifdef BBGE_BUILD_WINDOWS
@ -1138,3 +1058,28 @@ std::string spacesToUnderscores(const std::string &str)
if (s[i] == ' ') s[i] = '_';
return s;
}
#include "DeflateCompressor.h"
char *readCompressedFile(std::string path, unsigned long *size_ret)
{
unsigned long size = 0;
char *buf = readFile(path, &size);
ZlibCompressor z; // allocates with new[] by default
z.init(buf, size, ByteBuffer::TAKE_OVER);
z.Compressed(true);
z.Decompress();
if(!z.Compressed())
{
if (size_ret)
*size_ret = z.size();
z.wpos(z.size());
z << '\0'; // be sure the buffer is null-terminated
buf = (char*)z.ptr();
z._setPtr(NULL);
return buf;
}
return NULL;
}

View file

@ -197,6 +197,7 @@ bool exists(const std::string &f, bool makeFatal = false);
void errorLog(const std::string &s);
void debugLog(const std::string &s);
char *readFile(std::string path, unsigned long *size_ret = 0);
char *readCompressedFile(std::string path, unsigned long *size_ret = 0);
void forEachFile(std::string path, std::string type, void callback(const std::string &filename, intptr_t param), intptr_t param);
std::string stripEndlineForUnix(const std::string &in);
std::vector<std::string> getFileList(std::string path, std::string type, int param);
@ -277,10 +278,6 @@ enum LerpType
float lerp(const float &v1, const float &v2, float dt, int lerpType);
void crunchFile(const std::string &file, const std::string &out, bool deleteOriginal=false);
void uncrunchFile(const std::string &file, const std::string &out);
int packFile(const std::string &sourcef, const std::string &destf, int level);
int unpackFile(const std::string &sourcef, const std::string &destf);

476
BBGE/ByteBuffer.h Normal file
View file

@ -0,0 +1,476 @@
#ifndef BYTEBUFFER_H
#define BYTEBUFFER_H
#include <string.h> // for memcpy
// ** compatibility stuff for BBGE .... **
#include "Base.h"
#define BYTEBUFFER_NO_EXCEPTIONS
#if (defined(BBGE_BUILD_SDL) && (SDL_BYTEORDER == SDL_BIG_ENDIAN))
# define BB_IS_BIG_ENDIAN
#endif
// ****
#define BB_MAKE_WRITE_OP(T) inline ByteBuffer& operator<<(T val) { append<T>(val); return *this; }
#define BB_MAKE_READ_OP(T) inline ByteBuffer& operator>>(T &val) { val = read<T>(); return *this; }
class ByteBuffer
{
public:
typedef void (*delete_func)(void*);
typedef void *(*allocator_func)(size_t);
enum Mode // for creation with existing pointers
{
COPY, //- Make a copy of the buffer (default action).
REUSE, //- Use the passed-in buffer as is. Requires the pointer
// to remain valid over the life of this object.
TAKE_OVER, //- Take over the passed-in buffer; it will be deleted on object destruction.
};
#ifdef _MSC_VER
typedef __int64 int64;
typedef long int32;
typedef short int16;
typedef char int8;
typedef unsigned __int64 uint64;
typedef unsigned long uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
#else
typedef long long int64;
typedef int int32;
typedef short int16;
typedef char int8;
typedef unsigned long long uint64;
typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
#endif
class Exception
{
public:
Exception(const ByteBuffer *bb, const char *act, uint32 sp = 0)
{
action = act;
rpos = bb->rpos();
wpos = bb->wpos();
sizeparam = sp;
cursize = bb->size();
}
uint32 rpos, wpos, sizeparam, cursize;
const char *action;
};
#ifdef BYTEBUFFER_NO_EXCEPTIONS
#define BYTEBUFFER_EXCEPT(bb, desc, sz) { Exception __e(bb, desc, sz); char errbuf[256]; \
sprintf(errbuf, "Exception in ByteBuffer: '%s', rpos: %u, wpos: %u, cursize: %u, sizeparam: %u", \
__e.action, __e.rpos, __e.wpos, __e.cursize, __e.sizeparam); errorLog(errbuf); abort(); }
#else
#define BYTEBUFFER_EXCEPT(bb, desc, sz) throw ByteBufferException(bb, desc, sz)
#endif
protected:
uint8 *_buf; // the ptr to the buffer that holds all the bytes
uint32 _rpos, // read position, [0 ... _size]
_wpos, // write position, [0 ... _size]
_res, // reserved buffer size, [0 ... _size ... _res]
_size; // used buffer size
delete_func _delfunc;
allocator_func _allocfunc;
bool _mybuf; // if true, destructor deletes buffer
bool _growable; // default true, if false, buffer will not re-allocate more space
public:
ByteBuffer()
: _rpos(0), _wpos(0), _buf(NULL), _size(0), _growable(true), _res(0), _mybuf(false), _delfunc(NULL),
_allocfunc(NULL)
{
}
ByteBuffer(uint32 res)
: _rpos(0), _wpos(0), _buf(NULL), _size(0), _growable(true), _res(0), _mybuf(false), _delfunc(NULL),
_allocfunc(NULL)
{
_allocate(res);
}
ByteBuffer(ByteBuffer &buf, Mode mode = COPY, uint32 extra = 0)
: _rpos(0), _wpos(0), _buf(NULL), _size(0), _growable(true), _res(0), _mybuf(false), _delfunc(NULL),
_allocfunc(NULL)
{
init(buf, mode, extra);
}
// del param only used with TAKE_OVER, extra only used with COPY
ByteBuffer(void *buf, uint32 size, Mode mode = COPY, delete_func del = NULL, uint32 extra = 0)
: _rpos(0), _wpos(0), _size(size), _buf(NULL), _growable(true), _delfunc(del),
_mybuf(false), _allocfunc(NULL) // for mode == REUSE
{
init(buf, size, mode, del, extra);
}
void init(void *buf, uint32 size, Mode mode = COPY, delete_func del = NULL, uint32 extra = 0)
{
_mybuf = false;
switch(mode)
{
case COPY:
_allocate(size + extra);
append(buf, size);
break;
case TAKE_OVER:
_mybuf = true; // fallthrough
case REUSE:
_buf = (uint8*)buf;
_res = size;
_size = size;
}
}
void init(ByteBuffer& bb, Mode mode = COPY, uint32 extra = 0)
{
_allocfunc = bb._allocfunc;
switch(mode)
{
case COPY:
reserve(bb.size() + extra);
append(bb);
break;
case TAKE_OVER:
case REUSE:
_mybuf = bb._mybuf;
_delfunc = bb._delfunc;
_buf = bb._buf;
_res = bb._res;
_size = bb._size;
_growable = bb._growable;
break;
}
if(mode == TAKE_OVER)
{
bb._buf = NULL;
bb._size = 0;
bb._res = 0;
}
}
virtual ~ByteBuffer()
{
clear();
}
void clear(void)
{
_delete();
reset();
}
inline void reset(void)
{
_rpos = _wpos = _size = 0;
}
void resize(uint32 newsize)
{
reserve(newsize);
_rpos = 0;
_wpos = newsize;
_size = newsize;
}
void reserve(uint32 newsize)
{
if(_res < newsize)
_allocate(newsize);
}
// ---------------------- Write methods -----------------------
BB_MAKE_WRITE_OP(char);
BB_MAKE_WRITE_OP(uint8);
BB_MAKE_WRITE_OP(uint16);
BB_MAKE_WRITE_OP(uint32);
BB_MAKE_WRITE_OP(uint64);
BB_MAKE_WRITE_OP(float);
BB_MAKE_WRITE_OP(double);
BB_MAKE_WRITE_OP(int);
ByteBuffer &operator<<(bool value)
{
append<char>((char)value);
return *this;
}
ByteBuffer &operator<<(const char *str)
{
append((uint8 *)str, str ? strlen(str) : 0);
append((uint8)0);
return *this;
}
ByteBuffer &operator<<(const std::string &value)
{
append((uint8 *)value.c_str(), value.length());
append((uint8)0);
return *this;
}
// -------------------- Read methods --------------------
BB_MAKE_READ_OP(char);
BB_MAKE_READ_OP(uint8);
BB_MAKE_READ_OP(uint16);
BB_MAKE_READ_OP(uint32);
BB_MAKE_READ_OP(uint64);
BB_MAKE_READ_OP(float);
BB_MAKE_READ_OP(double);
BB_MAKE_READ_OP(int);
ByteBuffer &operator>>(bool &value)
{
value = read<char>() > 0 ? true : false;
return *this;
}
uint8 operator[](uint32 pos)
{
return read<uint8>(pos);
}
ByteBuffer &operator>>(std::string& value)
{
value.clear();
char c;
while(readable() && (c = read<char>()))
value += c;
return *this;
}
// --------------------------------------------------
uint32 rpos() const { return _rpos; }
uint32 rpos(uint32 rpos)
{
_rpos = rpos < size() ? rpos : size();
return _rpos;
}
uint32 wpos() const { return _wpos; }
uint32 wpos(uint32 wpos)
{
_wpos = wpos < size() ? wpos : size();
return _wpos;
}
template <typename T> T read()
{
T r = read<T>(_rpos);
_rpos += sizeof(T);
return r;
}
template <typename T> T read(uint32 pos) const
{
if(pos + sizeof(T) > size())
BYTEBUFFER_EXCEPT(this, "read", sizeof(T));
T val = *((T const*)(_buf + pos));
ToLittleEndian<T>(val);
return val;
}
void read(void *dest, uint32 len)
{
if (_rpos + len <= size())
memcpy(dest, &_buf[_rpos], len);
else
BYTEBUFFER_EXCEPT(this, "read-into", len);
_rpos += len;
}
void skipRead(uint32 len)
{
_rpos += len;
}
inline const uint8 *contents() const { return _buf; }
inline uint8 *contents() { return _buf; }
inline const void *ptr() const { return _buf; }
inline void *ptr() { return _buf; }
inline uint32 size() const { return _size; }
inline uint32 bytes() const { return size(); }
inline uint32 bits() const { return bytes() * 8; }
inline uint32 capacity() const { return _res; }
inline uint32 readable(void) const { return size() - rpos(); }
inline uint32 writable(void) const { return size() - wpos(); } // free space left before realloc will occur
template <typename T> void append(T value)
{
ToLittleEndian<T>(value);
_enlargeIfReq(_wpos + sizeof(T));
*((T*)(_buf + _wpos)) = value;
_wpos += sizeof(T);
if(_size < _wpos)
_size = _wpos;
}
void append(const void *src, uint32 bytes)
{
if (!bytes) return;
_enlargeIfReq(_wpos + bytes);
memcpy(_buf + _wpos, src, bytes);
_wpos += bytes;
if(_size < _wpos)
_size = _wpos;
}
void append(const ByteBuffer& buffer)
{
if(buffer.size())
append(buffer.contents(), buffer.size());
}
void put(uint32 pos, const void *src, uint32 bytes)
{
memcpy(_buf + pos, src, bytes);
}
template <typename T> void put(uint32 pos, T value)
{
if(pos >= size())
BYTEBUFFER_EXCEPT(this, "put", sizeof(T));
ToLittleEndian<T>(value);
*((T*)(_buf + pos)) = value;
}
inline bool growable(void) { return _growable; }
inline void growable(bool b) { _growable = b; }
// dangerous functions
void _setPtr(void *p)
{
_buf = (uint8*)p;
}
void _setAllocFunc(allocator_func f)
{
_allocfunc = f;
}
void _setDelFunc(delete_func f)
{
_delfunc = f;
}
void _setSize(uint32 s)
{
_size = s;
}
void _setReserved(uint32 s)
{
_res = s;
}
protected:
void _delete(void)
{
if(_mybuf)
{
if(_delfunc)
_delfunc(_buf);
else
delete [] _buf;
_buf = NULL;
_res = 0;
}
}
// allocate larger buffer and copy contents. if we own the current buffer, delete old, otherwise, leave it as it is.
void _allocate(uint32 s)
{
if(!_growable && _buf) // only throw if we already have a buf
BYTEBUFFER_EXCEPT(this, "_alloc+locked", s);
// dangerous: It's up to the user to be sure that _allocfunc and _delfunc are matching
uint8 *newbuf = (uint8*)(_allocfunc ? _allocfunc(s) : new char[s]);
if(_buf)
{
memcpy(newbuf, _buf, _size);
_delete();
}
_buf = newbuf;
_res = s;
_mybuf = true;
if (!_allocfunc)
_delfunc = NULL;
}
void _enlargeIfReq(uint32 minSize)
{
if(_res < minSize)
{
uint32 a = _res * 2;
if(a < minSize) // fallback if doubling the space was not enough
a += minSize;
_allocate(a);
}
}
template<size_t T> inline static void convert(char *val)
{
std::swap(*val, *(val + T - 1));
convert<T - 2>(val + 1);
}
template<> inline static void convert<0>(char *) {}
template<> inline static void convert<1>(char *) {}
template<typename T> inline static void EndianConvert(T *val)
{
convert<sizeof(T)>((char *)(val));
}
#if BB_IS_BIG_ENDIAN
template<typename T> inline static void ToLittleEndian(T& val) { EndianConvert<T>(&val); }
template<typename T> inline static void ToBigEndian(T&) { }
#else
template<typename T> inline static void ToLittleEndian(T&) { }
template<typename T> inline static void ToBigEndian(T& val) { EndianConvert<T>(&val); }
#endif
template<typename T> static void ToLittleEndian(T*); // will generate link error
template<typename T> static void ToBigEndian(T*); // will generate link error
inline static void ToLittleEndian(uint8&) { }
inline static void ToLittleEndian(int8&) { }
inline static void ToBigEndian(uint8&) { }
inline static void ToBigEndian( int8&) { }
};
#undef BB_MAKE_WRITE_OP
#undef BB_MAKE_READ_OP
#undef BB_IS_BIG_ENDIAN
#endif

259
BBGE/DeflateCompressor.cpp Normal file
View 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
}

59
BBGE/DeflateCompressor.h Normal file
View file

@ -0,0 +1,59 @@
#ifndef DEFLATE_COMPRESSOR_H
#define DEFLATE_COMPRESSOR_H
#include "ByteBuffer.h"
// implements a raw deflate stream, not zlib wrapped, and not checksummed.
class DeflateCompressor : public ByteBuffer
{
public:
DeflateCompressor();
DeflateCompressor(void *buf, uint32 size, Mode mode = COPY, delete_func del = NULL, uint32 extra = 0);
virtual ~DeflateCompressor() {}
virtual void Compress(uint8 level = 1);
virtual void Decompress(void);
bool Compressed(void) const { return _iscompressed; }
void Compressed(bool b) { _iscompressed = b; }
uint32 RealSize(void) const { return _iscompressed ? _real_size : size(); }
void RealSize(uint32 realsize) { _real_size = realsize; }
void clear(void) // not required to be strictly virtual; be careful not to mess up static types!
{
ByteBuffer::clear();
_real_size = 0;
_iscompressed = false;
}
protected:
int _windowBits; // read zlib docs to know what this means
unsigned int _real_size;
bool _forceCompress;
bool _iscompressed;
private:
static void decompress(void *dst, uint32 *origsize, const void *src, uint32 size, int wbits);
static void compress(void* dst, uint32 *dst_size, const void* src, uint32 src_size,
uint8 level, int wbits);
int decompressBlockwise();
};
// implements deflate stream, zlib wrapped
class ZlibCompressor : public DeflateCompressor
{
public:
ZlibCompressor();
virtual ~ZlibCompressor() {}
};
// the output produced by this stream contains a minimal gzip header,
// and can be directly written to a .gz file.
class GzipCompressor : public DeflateCompressor
{
public:
GzipCompressor();
virtual ~GzipCompressor() {}
virtual void Decompress(void);
};
#endif

View file

@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "Texture.h"
#include "Core.h"
#include "../ExternalLibs/glpng.h"
#include "ByteBuffer.h"
#include <assert.h>
@ -69,7 +70,6 @@ Texture::Texture() : Resource()
repeat = false;
pngSetStandardOrientation(0);
imageData = 0;
layer = 0;
ow = oh = -1;
}
@ -388,19 +388,7 @@ void Texture::load(std::string file)
}
else if (post == "zga")
{
if (core->getUserDataFolder().empty())
{
unpackFile(file, "poot.tmp");
loadTGA("poot.tmp");
remove("poot.tmp");
}
else
{
unpackFile(file, core->getUserDataFolder() + "/poot.tmp");
loadTGA(core->getUserDataFolder() + "/poot.tmp");
remove((core->getUserDataFolder() + "/poot.tmp").c_str());
}
loadZGA(file);
}
else if (post == "tga")
{
@ -450,11 +438,6 @@ void Texture::unbind()
{
}
void Texture::setLayer(int layer)
{
this->layer = layer;
}
#ifdef BBGE_BUILD_OPENGL
void Texture::setID(int id)
@ -523,59 +506,43 @@ void Texture::loadPNG(const std::string &file)
// internal load functions
void Texture::loadTGA(const std::string &file)
{
#ifdef BBGE_BUILD_GLFW
GLFWimage image;
glfwReadImage(file.c_str(), &image, 0);
width = image.Width;
height = image.Height;
glfwFreeImage(&image);
loadTGA(TGAload(file.c_str()));
}
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
void Texture::loadZGA(const std::string &file)
{
unsigned long size = 0;
char *buf = readCompressedFile(file, &size);
ImageTGA *tga = TGAloadMem(buf, size);
if (!tga)
{
debugLog("Can't load ZGA File: " + file);
return;
}
loadTGA(tga);
}
glfwLoadTexture2D(file.c_str(), 0);
void Texture::loadTGA(ImageTGA *imageTGA)
{
if (!imageTGA)
return;
glGenTextures(1, &textures[0]);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,filter); // Linear Filtering
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,filter); // Linear Filtering
#endif
if (imageTGA->channels==3)
glTexImage2D(GL_TEXTURE_2D, 0, 3, imageTGA->sizeX, imageTGA->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, imageTGA->data);
else if (imageTGA->channels==4)
glTexImage2D(GL_TEXTURE_2D, 0, 4,imageTGA->sizeX, imageTGA->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageTGA->data);
/*
glfwLoadTexture2D(file.c_str(), 0);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,filter); // Linear Filtering
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,filter); // Linear Filtering
width = imageTGA->sizeX;
height = imageTGA->sizeY;
*/
#ifdef BBGE_BUILD_SDL
ImageTGA *imageTGA;
if ((imageTGA = TGAload(file.c_str())) != 0)
{
glGenTextures(1, &textures[0]);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,filter); // Linear Filtering
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,filter); // Linear Filtering
if (imageTGA->channels==3)
glTexImage2D(GL_TEXTURE_2D, 0, 3, imageTGA->sizeX, imageTGA->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, imageTGA->data);
else if (imageTGA->channels==4)
{
//errorLog("4 channels");
glTexImage2D(GL_TEXTURE_2D, 0, 4,imageTGA->sizeX, imageTGA->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageTGA->data);
}
width = imageTGA->sizeX;
height = imageTGA->sizeY;
}
if (imageTGA)
{
if (imageTGA->data)
delete[] (imageTGA->data);
free (imageTGA);
}
#endif
if (imageTGA->data)
delete[] (imageTGA->data);
free (imageTGA);
}
@ -589,36 +556,37 @@ typedef uint16_t WORD;
#endif
static int fread_int(FILE *file, int size)
{
int buffer;
//input.read((char *)&buffer, 4);
if (fread(&buffer, size, 1, file) != 1)
return 0;
#ifdef BBGE_BUILD_SDL
return SDL_SwapLE32(buffer);
#else
return buffer;
#endif
}
#ifdef BBGE_BUILD_WINDOWS
#define byte char
#endif
ImageTGA *Texture::TGAload(const char *filename)
{
/*
//HACK: function isn't macosx friendly
return 0;
*/
unsigned long size = 0;
char *rawbuf = readFile(filename, &size);
ImageTGA *tga = TGAloadMem(rawbuf, size);
if (rawbuf)
delete [] rawbuf;
if (!tga)
{
debugLog("Can't load TGA File!");
return NULL;
}
return tga;
}
ImageTGA *Texture::TGAloadMem(void *mem, int size)
{
if (!mem || size < 20)
return NULL;
ByteBuffer bb(mem, size, ByteBuffer::REUSE);
ImageTGA *pImageData = NULL; // This stores our important image data
WORD width = 0, height = 0; // The dimensions of the image
byte length = 0; // The length in bytes to the pixels
byte imageType = 0; // The image type (RLE, RGB, Alpha...)
byte bits = 0; // The bits per pixel for the image (16, 24, 32)
FILE *pFile = NULL; // The file pointer
int channels = 0; // The channels of the image (3 = RGA : 4 = RGBA)
int stride = 0; // The stride (channels * width)
int i = 0; // A counter
@ -636,41 +604,25 @@ ImageTGA *Texture::TGAload(const char *filename)
// 32-bit textures are very similar, so there's no need to do anything special.
// We do, however, read in an extra bit for each color.
// Open a file pointer to the targa file and check if it was found and opened
if((pFile = fopen(core->adjustFilenameCase(filename).c_str(), "rb")) == NULL) //, "rb" // openRead(fn)
{
// Display an error message saying the file was not found, then return NULL
debugLog("Unable to load TGA File!");
return NULL;
}
// Allocate the structure that will hold our eventual image data (must free it!)
pImageData = (ImageTGA*)malloc(sizeof(ImageTGA));
// Read in the length in bytes from the header to the pixel data
//fread(&length, sizeof(byte), 1, pFile);
length = fread_int(pFile, sizeof(byte));
bb >> length;
// Jump over one byte
fseek(pFile,1,SEEK_CUR);
bb.skipRead(1);
// Read in the imageType (RLE, RGB, etc...)
//fread(&imageType, sizeof(byte), 1, pFile);
imageType = fread_int(pFile, sizeof(byte));
bb >> imageType;
// Skip past general information we don't care about
fseek(pFile, 9, SEEK_CUR);
bb.skipRead(9);
// Read the width, height and bits per pixel (16, 24 or 32)
/*
fread(&width, sizeof(WORD), 1, pFile);
fread(&height, sizeof(WORD), 1, pFile);
fread(&bits, sizeof(byte), 1, pFile);
*/
width = fread_int(pFile, sizeof(WORD));
height = fread_int(pFile, sizeof(WORD));
bits = fread_int(pFile, sizeof(byte));
bb >> width >> height >> bits;
/*
std::ostringstream os;
@ -679,7 +631,7 @@ ImageTGA *Texture::TGAload(const char *filename)
*/
// Now we move the file pointer to the pixel data
fseek(pFile, length + 1, SEEK_CUR);
bb.skipRead(length + 1);
// Check if the image is RLE compressed or not
if(imageType != TGA_RLE)
@ -700,8 +652,9 @@ ImageTGA *Texture::TGAload(const char *filename)
unsigned char *pLine = &(pImageData->data[stride * y]);
// Read in the current line of pixels
if (fread(pLine, stride, 1, pFile) != 1)
if (bb.readable() < stride)
break;
bb.read(pLine, stride);
// Go through all of the pixels and swap the B and R values since TGA
// files are stored as BGR instead of RGB (or use GL_BGR_EXT verses GL_RGB)
@ -729,8 +682,9 @@ ImageTGA *Texture::TGAload(const char *filename)
for(int i = 0; i < width*height; i++)
{
// Read in the current pixel
if (fread(&pixels, sizeof(unsigned short), 1, pFile) != 1)
if (bb.readable() < sizeof(unsigned char))
break;
bb >> pixels;
// To convert a 16-bit pixel into an R, G, B, we need to
// do some masking and such to isolate each color value.
@ -787,8 +741,7 @@ ImageTGA *Texture::TGAload(const char *filename)
while(i < width*height)
{
// Read in the current color count + 1
if (fread(&rleID, sizeof(byte), 1, pFile) != 1)
break;
bb >> rleID;
// Check if we don't have an encoded string of colors
if(rleID < 128)
@ -800,8 +753,9 @@ ImageTGA *Texture::TGAload(const char *filename)
while(rleID)
{
// Read in the current color
if (fread(pColors, sizeof(byte) * channels, 1, pFile) != 1)
if (bb.readable() < channels)
break;
bb.read(pColors, channels);
// Store the current pixel in our image array
pImageData->data[colorsRead + 0] = pColors[2];
@ -826,8 +780,9 @@ ImageTGA *Texture::TGAload(const char *filename)
rleID -= 127;
// Read in the current color, which is the same for a while
if (fread(pColors, sizeof(byte) * channels, 1, pFile) != 1)
if (bb.readable() < channels)
break;
bb.read(pColors, channels);
// Go and read as many pixels as are the same
while(rleID)
@ -856,9 +811,6 @@ ImageTGA *Texture::TGAload(const char *filename)
delete[] pColors;
}
// Close the file pointer that opened the file
fclose(pFile);
// Fill in our tImageTGA structure to pass back
pImageData->channels = channels;
pImageData->sizeX = width;

View file

@ -59,6 +59,7 @@ public:
int width, height;
static ImageTGA *TGAload(const char* filename);
static ImageTGA *TGAloadMem(void *mem, int size);
static bool useMipMaps;
bool repeat;
@ -84,10 +85,12 @@ public:
void read(int tx, int ty, int w, int h, unsigned char *pixels);
protected:
std::string loadName;
int layer;
// internal load functions
void loadPNG(const std::string &file);
void loadTGA(const std::string &file);
void loadZGA(const std::string &file);
void loadTGA(ImageTGA *tga);
int ow, oh;

View file

@ -993,6 +993,11 @@ bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
return false;
}
return LoadMem(buf, length, encoding);
}
bool TiXmlDocument::LoadMem( char* buf, long length, TiXmlEncoding encoding )
{
// Process the buffer in place to normalize new lines. (See comment above.)
// Copies from the 'p' to 'q' pointer, where p can advance faster if
// a newline-carriage return is hit.

View file

@ -22,6 +22,9 @@ must not be misrepresented as being the original software.
distribution.
*/
// EDIT:
// - added LoadMem() function
#ifndef TINYXML_INCLUDED
#define TINYXML_INCLUDED
@ -1421,6 +1424,8 @@ public:
/// Save a file using the given FILE*. Returns true if successful.
bool SaveFile( FILE* ) const;
bool LoadMem( char *buf, long length, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
#ifdef TIXML_USE_STL
bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version.
{