mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-12-26 14:45:48 +00:00
8f2279e28a
This was caused by the VFS caching file sizes, and not noticing that the file size had changed, which confused zlib because the data stream ended too early.
225 lines
4.4 KiB
C++
225 lines
4.4 KiB
C++
// VFSFile.cpp - basic file interface + classes
|
|
// For conditions of distribution and use, see copyright notice in VFS.h
|
|
|
|
#include "VFSInternal.h"
|
|
#include "VFSFile.h"
|
|
#include "VFSTools.h"
|
|
#include "VFSFileFuncs.h"
|
|
|
|
#include <cstdio>
|
|
|
|
VFS_NAMESPACE_START
|
|
|
|
VFSFile::VFSFile(const char *name)
|
|
: _buf(NULL), _delfunc(NULL)
|
|
{
|
|
_setName(name);
|
|
}
|
|
|
|
VFSFile::~VFSFile()
|
|
{
|
|
close();
|
|
dropBuf(true);
|
|
}
|
|
|
|
void VFSFile::delBuf(void *mem)
|
|
{
|
|
deleteHelper(_delfunc, (char*) mem);
|
|
}
|
|
|
|
const void *VFSFile::getBuf(allocator_func alloc /* = NULL */, delete_func del /* = NULL */)
|
|
{
|
|
assert(!alloc == !del); // either both or none may be defined. Checked extra early to prevent possible errors later.
|
|
|
|
VFS_GUARD_OPT(this);
|
|
if(_buf)
|
|
return _buf;
|
|
|
|
bool op = isopen();
|
|
|
|
if(!op && !open()) // open with default params if not open
|
|
return NULL;
|
|
|
|
unsigned int s = (unsigned int)size();
|
|
_buf = allocHelper(alloc, s + 4); // a bit extra padding
|
|
if(!_buf)
|
|
return NULL;
|
|
|
|
_delfunc = del;
|
|
|
|
vfspos offs;
|
|
if(op)
|
|
{
|
|
vfspos oldpos = getpos();
|
|
seek(0);
|
|
offs = read(_buf, s);
|
|
seek(oldpos);
|
|
}
|
|
else
|
|
{
|
|
offs = read(_buf, s);
|
|
close();
|
|
}
|
|
// Might as well be text mode reading, which means less actual bytes than size() said,
|
|
// so this can't be done earlier.
|
|
memset((char*)_buf + offs, 0, 4);
|
|
|
|
return _buf;
|
|
}
|
|
|
|
void VFSFile::dropBuf(bool del)
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
if(del)
|
|
delBuf(_buf);
|
|
_buf = NULL;
|
|
}
|
|
|
|
VFSFileReal::VFSFileReal(const char *name /* = NULL */)
|
|
: VFSFile(name), _fh(NULL), _buf(NULL)
|
|
{
|
|
}
|
|
|
|
VFSFileReal::~VFSFileReal()
|
|
{
|
|
}
|
|
|
|
bool VFSFileReal::open(const char *mode /* = NULL */)
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
|
|
if(isopen())
|
|
close();
|
|
|
|
dropBuf(true);
|
|
|
|
_fh = real_fopen(fullname(), mode ? mode : "rb");
|
|
|
|
return !!_fh;
|
|
}
|
|
|
|
bool VFSFileReal::isopen(void) const
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
return !!_fh;
|
|
}
|
|
|
|
bool VFSFileReal::iseof(void) const
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
return !_fh || real_feof((FILE*)_fh);
|
|
}
|
|
|
|
bool VFSFileReal::close(void)
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
if(_fh)
|
|
{
|
|
real_fclose((FILE*)_fh);
|
|
_fh = NULL;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool VFSFileReal::seek(vfspos pos)
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
if(!_fh)
|
|
return false;
|
|
return real_fseek((FILE*)_fh, pos, SEEK_SET) == 0;
|
|
}
|
|
|
|
bool VFSFileReal::seekRel(vfspos offs)
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
if(!_fh)
|
|
return false;
|
|
return real_fseek((FILE*)_fh, offs, SEEK_CUR) == 0;
|
|
}
|
|
|
|
bool VFSFileReal::flush(void)
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
if(!_fh)
|
|
return false;
|
|
return real_fflush((FILE*)_fh) == 0;
|
|
}
|
|
|
|
vfspos VFSFileReal::getpos(void) const
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
if(!_fh)
|
|
return npos;
|
|
return real_ftell((FILE*)_fh);
|
|
}
|
|
|
|
unsigned int VFSFileReal::read(void *dst, unsigned int bytes)
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
if(!_fh)
|
|
return npos;
|
|
return real_fread(dst, 1, bytes, (FILE*)_fh);
|
|
}
|
|
|
|
unsigned int VFSFileReal::write(const void *src, unsigned int bytes)
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
if(!_fh)
|
|
return npos;
|
|
return real_fwrite(src, 1, bytes, (FILE*)_fh);
|
|
}
|
|
|
|
vfspos VFSFileReal::size(void)
|
|
{
|
|
return GetFileSize(fullname());
|
|
}
|
|
|
|
// ------------- VFSFileMem -----------------------
|
|
|
|
VFSFileMem::VFSFileMem(const char *name, void *buf, unsigned int size, Mode mode /* = COPY */,
|
|
allocator_func alloc /* = NULL */, delete_func delfunc /* = NULL */)
|
|
: VFSFile(name), _pos(0), _size(size), _mybuf(mode == TAKE_OVER || mode == COPY)
|
|
{
|
|
if(mode == COPY)
|
|
{
|
|
assert(!alloc == !delfunc);
|
|
_buf = alloc ? alloc(size+1) : (void*)(new char[size+1]);
|
|
memcpy(_buf, buf, size);
|
|
((char*)_buf)[size] = 0;
|
|
}
|
|
else
|
|
{
|
|
_buf = buf;
|
|
}
|
|
_delfunc = delfunc;
|
|
}
|
|
|
|
VFSFileMem::~VFSFileMem()
|
|
{
|
|
if(_mybuf)
|
|
VFSFile::dropBuf(true);
|
|
}
|
|
|
|
unsigned int VFSFileMem::read(void *dst, unsigned int bytes)
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
if(iseof())
|
|
return 0;
|
|
unsigned int rem = std::min<unsigned int>((unsigned int)(_size - _pos), bytes);
|
|
|
|
memcpy(dst, (char*)_buf + _pos, rem);
|
|
return rem;
|
|
}
|
|
|
|
unsigned int VFSFileMem::write(const void *src, unsigned int bytes)
|
|
{
|
|
VFS_GUARD_OPT(this);
|
|
if(iseof())
|
|
return 0;
|
|
unsigned int rem = std::min<unsigned int>((unsigned int)(_size - _pos), bytes);
|
|
|
|
memcpy((char*)_buf + _pos, src, rem);
|
|
return rem;
|
|
}
|
|
|
|
VFS_NAMESPACE_END
|