mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-07-02 22:14:37 +00:00
Revert "added partial VFS support - enough to read static data from any source"
This reverts commit fa3e9e7329
.
This commit is contained in:
parent
fa3e9e7329
commit
56c6833220
56 changed files with 608 additions and 4023 deletions
|
@ -97,11 +97,9 @@ extern int APIENTRY pngLoadRawF(FILE *file, pngRawInfo *rawinfo);
|
|||
|
||||
extern int APIENTRY pngLoad(const char *filename, int mipmap, int trans, pngInfo *info);
|
||||
extern int APIENTRY pngLoadF(FILE *file, int mipmap, int trans, pngInfo *info);
|
||||
extern int APIENTRY pngLoadMem(const char *mem, int size, int mipmap, int trans, pngInfo *info);
|
||||
|
||||
extern unsigned int APIENTRY pngBind(const char *filename, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter);
|
||||
extern unsigned int APIENTRY pngBindF(FILE *file, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter);
|
||||
extern unsigned int APIENTRY pngBindMem(const char *mem, int size, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter);
|
||||
|
||||
extern void APIENTRY pngSetStencil(unsigned char red, unsigned char green, unsigned char blue);
|
||||
extern void APIENTRY pngSetAlphaCallback(unsigned char (*callback)(unsigned char red, unsigned char green, unsigned char blue));
|
||||
|
|
|
@ -691,14 +691,6 @@ unsigned int APIENTRY pngBindF(FILE *file, int mipmap, int trans, pngInfo *info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned int APIENTRY pngBindMem(const char *mem, int size, int mipmap, int trans, pngInfo *info, int wrapst, int minfilter, int magfilter) {
|
||||
unsigned int id = SetParams(wrapst, magfilter, minfilter);
|
||||
|
||||
if (id != 0 && pngLoadMem(mem, size, mipmap, trans, info))
|
||||
return id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void APIENTRY pngSetStencil(unsigned char red, unsigned char green, unsigned char blue) {
|
||||
StencilRed = red, StencilGreen = green, StencilBlue = blue;
|
||||
}
|
||||
|
@ -725,332 +717,3 @@ void APIENTRY pngSetStandardOrientation(int standardorientation) {
|
|||
StandardOrientation = standardorientation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -- added memory read functions --
|
||||
|
||||
/*pointer to a new input function that takes as its
|
||||
arguments a pointer to a png_struct, a pointer to
|
||||
a location where input data can be stored, and a 32-bit
|
||||
unsigned int that is the number of bytes to be read.
|
||||
To exit and output any fatal error messages the new write
|
||||
function should call png_error(png_ptr, "Error msg"). */
|
||||
|
||||
typedef struct glpng_memread_struct
|
||||
{
|
||||
png_bytep mem;
|
||||
png_size_t rpos;
|
||||
} glpng_memread;
|
||||
|
||||
void glpng_read_mem(png_structp png, png_bytep dst, png_size_t size)
|
||||
{
|
||||
glpng_memread *mr = (glpng_memread*)png->io_ptr;
|
||||
memcpy(dst, mr->mem + mr->rpos, size);
|
||||
mr->rpos += size;
|
||||
}
|
||||
|
||||
int APIENTRY pngLoadMem(const char *mem, int size, int mipmap, int trans, pngInfo *pinfo) {
|
||||
GLint pack, unpack;
|
||||
unsigned char header[8];
|
||||
png_structp png;
|
||||
png_infop info;
|
||||
png_infop endinfo;
|
||||
png_bytep data, data2;
|
||||
png_bytep *row_p;
|
||||
double fileGamma;
|
||||
|
||||
png_uint_32 width, height, rw, rh;
|
||||
int depth, color;
|
||||
|
||||
png_uint_32 i;
|
||||
glpng_memread memread;
|
||||
|
||||
if(size < 8)
|
||||
return 0; // error
|
||||
|
||||
memcpy(header, mem, 8);
|
||||
|
||||
if (!png_check_sig(header, 8))
|
||||
return 0;
|
||||
|
||||
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
info = png_create_info_struct(png);
|
||||
endinfo = png_create_info_struct(png);
|
||||
|
||||
// DH: added following lines
|
||||
if (setjmp(png->jmpbuf))
|
||||
{
|
||||
png_destroy_read_struct(&png, &info, &endinfo);
|
||||
return 0;
|
||||
}
|
||||
// ~DH
|
||||
|
||||
memread.rpos = 0;
|
||||
memread.mem = ((png_bytep)mem) + 8;
|
||||
png_set_read_fn(png, (voidp)&memread, glpng_read_mem);
|
||||
png_set_sig_bytes(png, 8);
|
||||
png_read_info(png, info);
|
||||
png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);
|
||||
|
||||
if (pinfo != NULL) {
|
||||
pinfo->Width = width;
|
||||
pinfo->Height = height;
|
||||
pinfo->Depth = depth;
|
||||
}
|
||||
|
||||
if (MaxTextureSize == 0)
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTextureSize);
|
||||
|
||||
#ifdef SUPPORTS_PALETTE_EXT
|
||||
#ifdef _WIN32
|
||||
if (PalettedTextures == -1)
|
||||
PalettedTextures = ExtSupported("GL_EXT_paletted_texture") && (strstr((const char *) glGetString(GL_VERSION), "1.1.0 3Dfx Beta") == NULL);
|
||||
|
||||
if (PalettedTextures) {
|
||||
if (glColorTableEXT == NULL) {
|
||||
glColorTableEXT = (PFNGLCOLORTABLEEXTPROC) wglGetProcAddress("glColorTableEXT");
|
||||
if (glColorTableEXT == NULL)
|
||||
PalettedTextures = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (PalettedTextures == -1)
|
||||
PalettedTextures = 0;
|
||||
|
||||
if (color == PNG_COLOR_TYPE_GRAY || color == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
png_set_gray_to_rgb(png);
|
||||
|
||||
if (color&PNG_COLOR_MASK_ALPHA && trans != PNG_ALPHA) {
|
||||
png_set_strip_alpha(png);
|
||||
color &= ~PNG_COLOR_MASK_ALPHA;
|
||||
}
|
||||
|
||||
if (!(PalettedTextures && mipmap >= 0 && trans == PNG_SOLID))
|
||||
if (color == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_expand(png);
|
||||
|
||||
/*--GAMMA--*/
|
||||
checkForGammaEnv();
|
||||
if (png_get_gAMA(png, info, &fileGamma))
|
||||
png_set_gamma(png, screenGamma, fileGamma);
|
||||
else
|
||||
png_set_gamma(png, screenGamma, 1.0/2.2);
|
||||
|
||||
png_read_update_info(png, info);
|
||||
|
||||
data = (png_bytep) malloc(png_get_rowbytes(png, info)*height);
|
||||
row_p = (png_bytep *) malloc(sizeof(png_bytep)*height);
|
||||
|
||||
for (i = 0; i < height; i++) {
|
||||
if (StandardOrientation)
|
||||
row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i];
|
||||
else
|
||||
row_p[i] = &data[png_get_rowbytes(png, info)*i];
|
||||
}
|
||||
|
||||
png_read_image(png, row_p);
|
||||
free(row_p);
|
||||
|
||||
rw = SafeSize(width), rh = SafeSize(height);
|
||||
|
||||
if (rw != width || rh != height) {
|
||||
const int channels = png_get_rowbytes(png, info)/width;
|
||||
|
||||
data2 = (png_bytep) malloc(rw*rh*channels);
|
||||
|
||||
/* Doesn't work on certain sizes */
|
||||
/* if (gluScaleImage(glformat, width, height, GL_UNSIGNED_BYTE, data, rw, rh, GL_UNSIGNED_BYTE, data2) != 0)
|
||||
return 0;
|
||||
*/
|
||||
Resize(channels, data, width, height, data2, rw, rh);
|
||||
|
||||
width = rw, height = rh;
|
||||
free(data);
|
||||
data = data2;
|
||||
}
|
||||
|
||||
{ /* OpenGL stuff */
|
||||
glGetIntegerv(GL_PACK_ALIGNMENT, &pack);
|
||||
glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
#ifdef SUPPORTS_PALETTE_EXT
|
||||
if (PalettedTextures && mipmap >= 0 && trans == PNG_SOLID && color == PNG_COLOR_TYPE_PALETTE) {
|
||||
png_colorp pal;
|
||||
int cols;
|
||||
GLint intf;
|
||||
|
||||
if (pinfo != NULL) pinfo->Alpha = 0;
|
||||
png_get_PLTE(png, info, &pal, &cols);
|
||||
|
||||
switch (cols) {
|
||||
case 1<<1: intf = GL_COLOR_INDEX1_EXT; break;
|
||||
case 1<<2: intf = GL_COLOR_INDEX2_EXT; break;
|
||||
case 1<<4: intf = GL_COLOR_INDEX4_EXT; break;
|
||||
case 1<<8: intf = GL_COLOR_INDEX8_EXT; break;
|
||||
case 1<<12: intf = GL_COLOR_INDEX12_EXT; break;
|
||||
case 1<<16: intf = GL_COLOR_INDEX16_EXT; break;
|
||||
default:
|
||||
/*printf("Warning: Colour depth %i not recognised\n", cols);*/
|
||||
return 0;
|
||||
}
|
||||
glColorTableEXT(GL_TEXTURE_2D, GL_RGB8, cols, GL_RGB, GL_UNSIGNED_BYTE, pal);
|
||||
glTexImage2D(GL_TEXTURE_2D, mipmap, intf, width, height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (trans == PNG_SOLID || trans == PNG_ALPHA || trans == PNG_LUMINANCEALPHA || color == PNG_COLOR_TYPE_RGB_ALPHA || color == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||
GLenum glformat;
|
||||
GLint glcomponent;
|
||||
|
||||
switch (color) {
|
||||
case PNG_COLOR_TYPE_GRAY:
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
case PNG_COLOR_TYPE_PALETTE:
|
||||
glformat = GL_RGB;
|
||||
glcomponent = 3;
|
||||
if (pinfo != NULL) pinfo->Alpha = 0;
|
||||
break;
|
||||
|
||||
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
glformat = GL_RGBA;
|
||||
glcomponent = 4;
|
||||
if (pinfo != NULL) pinfo->Alpha = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
/*puts("glformat not set");*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (trans == PNG_LUMINANCEALPHA)
|
||||
glformat = GL_LUMINANCE_ALPHA;
|
||||
|
||||
if (mipmap == PNG_BUILDMIPMAPS)
|
||||
Build2DMipmaps(glcomponent, width, height, glformat, data, 1);
|
||||
else if (mipmap == PNG_SIMPLEMIPMAPS)
|
||||
Build2DMipmaps(glcomponent, width, height, glformat, data, 0);
|
||||
else
|
||||
glTexImage2D(GL_TEXTURE_2D, mipmap, glcomponent, width, height, 0, glformat, GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
else {
|
||||
png_bytep p, endp, q;
|
||||
int r, g, b, a;
|
||||
|
||||
p = data, endp = p+width*height*3;
|
||||
q = data2 = (png_bytep) malloc(sizeof(png_byte)*width*height*4);
|
||||
|
||||
if (pinfo != NULL) pinfo->Alpha = 8;
|
||||
|
||||
#define FORSTART \
|
||||
do { \
|
||||
r = *p++; /*red */ \
|
||||
g = *p++; /*green*/ \
|
||||
b = *p++; /*blue */ \
|
||||
*q++ = r; \
|
||||
*q++ = g; \
|
||||
*q++ = b;
|
||||
|
||||
#define FOREND \
|
||||
q++; \
|
||||
} while (p != endp);
|
||||
|
||||
#define ALPHA *q
|
||||
|
||||
switch (trans) {
|
||||
case PNG_CALLBACK:
|
||||
FORSTART
|
||||
ALPHA = AlphaCallback((unsigned char) r, (unsigned char) g, (unsigned char) b);
|
||||
FOREND
|
||||
break;
|
||||
|
||||
case PNG_STENCIL:
|
||||
FORSTART
|
||||
if (r == StencilRed && g == StencilGreen && b == StencilBlue)
|
||||
ALPHA = 0;
|
||||
else
|
||||
ALPHA = 255;
|
||||
FOREND
|
||||
break;
|
||||
|
||||
case PNG_BLEND1:
|
||||
FORSTART
|
||||
a = r+g+b;
|
||||
if (a > 255) ALPHA = 255; else ALPHA = a;
|
||||
FOREND
|
||||
break;
|
||||
|
||||
case PNG_BLEND2:
|
||||
FORSTART
|
||||
a = r+g+b;
|
||||
if (a > 255*2) ALPHA = 255; else ALPHA = a/2;
|
||||
FOREND
|
||||
break;
|
||||
|
||||
case PNG_BLEND3:
|
||||
FORSTART
|
||||
ALPHA = (r+g+b)/3;
|
||||
FOREND
|
||||
break;
|
||||
|
||||
case PNG_BLEND4:
|
||||
FORSTART
|
||||
a = r*r+g*g+b*b;
|
||||
if (a > 255) ALPHA = 255; else ALPHA = a;
|
||||
FOREND
|
||||
break;
|
||||
|
||||
case PNG_BLEND5:
|
||||
FORSTART
|
||||
a = r*r+g*g+b*b;
|
||||
if (a > 255*2) ALPHA = 255; else ALPHA = a/2;
|
||||
FOREND
|
||||
break;
|
||||
|
||||
case PNG_BLEND6:
|
||||
FORSTART
|
||||
a = r*r+g*g+b*b;
|
||||
if (a > 255*3) ALPHA = 255; else ALPHA = a/3;
|
||||
FOREND
|
||||
break;
|
||||
|
||||
//HACK: disabling this for now
|
||||
/*
|
||||
case PNG_BLEND7:
|
||||
FORSTART
|
||||
a = r*r+g*g+b*b;
|
||||
if (a > 255*255) ALPHA = 255; else ALPHA = (int) (sqrt(float(a)));
|
||||
FOREND
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
#undef FORSTART
|
||||
#undef FOREND
|
||||
#undef ALPHA
|
||||
|
||||
if (mipmap == PNG_BUILDMIPMAPS)
|
||||
Build2DMipmaps(4, width, height, GL_RGBA, data2, 1);
|
||||
else if (mipmap == PNG_SIMPLEMIPMAPS)
|
||||
Build2DMipmaps(4, width, height, GL_RGBA, data2, 0);
|
||||
else
|
||||
glTexImage2D(GL_TEXTURE_2D, mipmap, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
|
||||
|
||||
free(data2);
|
||||
}
|
||||
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, pack);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
|
||||
} /* OpenGL end */
|
||||
|
||||
png_read_end(png, endinfo);
|
||||
png_destroy_read_struct(&png, &info, &endinfo);
|
||||
|
||||
free(data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1,340 +0,0 @@
|
|||
#ifndef BYTEBUFFER_H
|
||||
#define BYTEBUFFER_H
|
||||
|
||||
#include "LVPACommon.h"
|
||||
#include "ByteConverter.h"
|
||||
|
||||
#include <string.h> // for memcpy
|
||||
|
||||
|
||||
LVPA_NAMESPACE_START
|
||||
|
||||
|
||||
#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*);
|
||||
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.
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
delete_func _delfunc;
|
||||
uint32 _rpos, // read position, [0 ... _size]
|
||||
_wpos, // write position, [0 ... _size]
|
||||
_res, // reserved buffer size, [0 ... _size ... _res]
|
||||
_size; // used buffer size
|
||||
|
||||
uint8 *_buf; // the ptr to the buffer that holds all the bytes
|
||||
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)
|
||||
{
|
||||
_allocate(128);
|
||||
}
|
||||
ByteBuffer(uint32 res)
|
||||
: _rpos(0), _wpos(0), _buf(NULL), _size(0), _growable(true)
|
||||
{
|
||||
_allocate(res);
|
||||
}
|
||||
ByteBuffer(const ByteBuffer &buf, uint32 extra = 0)
|
||||
: _rpos(0), _wpos(0), _buf(NULL), _size(0), _growable(true)
|
||||
{
|
||||
_allocate(buf.size() + extra + 64);
|
||||
append(buf);
|
||||
}
|
||||
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) // for mode == REUSE
|
||||
{
|
||||
switch(mode)
|
||||
{
|
||||
case COPY:
|
||||
_allocate(size + extra);
|
||||
append(buf, size);
|
||||
break;
|
||||
|
||||
case TAKE_OVER:
|
||||
_mybuf = true; // fallthrough
|
||||
case REUSE:
|
||||
_buf = (uint8*)buf;
|
||||
_res = size;
|
||||
}
|
||||
}
|
||||
|
||||
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(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(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())
|
||||
throw Exception(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
|
||||
throw Exception(this, "read-into", len);
|
||||
_rpos += len;
|
||||
}
|
||||
|
||||
inline const uint8 *contents() const { return _buf; }
|
||||
inline uint8 *contents() { 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())
|
||||
{
|
||||
throw Exception(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;
|
||||
}
|
||||
|
||||
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
|
||||
throw Exception(this, "_alloc+locked", s);
|
||||
|
||||
uint8 *newbuf = (uint8*)malloc(s);
|
||||
if(_buf)
|
||||
{
|
||||
memcpy(newbuf, _buf, _size);
|
||||
_delete();
|
||||
}
|
||||
_delfunc = free;
|
||||
_buf = newbuf;
|
||||
_res = s;
|
||||
_mybuf = true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#undef BB_MAKE_WRITE_OP
|
||||
#undef BB_MAKE_READ_OP
|
||||
|
||||
|
||||
LVPA_NAMESPACE_END
|
||||
|
||||
|
||||
#endif
|
|
@ -1,46 +0,0 @@
|
|||
#ifndef BYTECONVERTER_H
|
||||
#define BYTECONVERTER_H
|
||||
|
||||
#include <algorithm>
|
||||
#include "LVPAInternal.h" // this is important to fix up any possible ***_ENDIAN misconfigurations
|
||||
|
||||
LVPA_NAMESPACE_START
|
||||
|
||||
namespace ByteConverter
|
||||
{
|
||||
template<size_t T>
|
||||
inline void convert(char *val)
|
||||
{
|
||||
std::swap(*val, *(val + T - 1));
|
||||
convert<T - 2>(val + 1);
|
||||
}
|
||||
|
||||
template<> inline void convert<0>(char *) {}
|
||||
template<> inline void convert<1>(char *) {}
|
||||
|
||||
template<typename T>
|
||||
inline void apply(T *val)
|
||||
{
|
||||
convert<sizeof(T)>((char *)(val));
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_BIG_ENDIAN
|
||||
template<typename T> inline void ToLittleEndian(T& val) { ByteConverter::apply<T>(&val); }
|
||||
template<typename T> inline void ToBigEndian(T&) { }
|
||||
#else
|
||||
template<typename T> inline void ToLittleEndian(T&) { }
|
||||
template<typename T> inline void ToBigEndian(T& val) { ByteConverter::apply<T>(&val); }
|
||||
#endif
|
||||
|
||||
template<typename T> void ToLittleEndian(T*); // will generate link error
|
||||
template<typename T> void ToBigEndian(T*); // will generate link error
|
||||
|
||||
inline void ToLittleEndian(uint8&) { }
|
||||
inline void ToLittleEndian(int8&) { }
|
||||
inline void ToBigEndian(uint8&) { }
|
||||
inline void ToBigEndian( int8&) { }
|
||||
|
||||
LVPA_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1,44 +0,0 @@
|
|||
#ifndef LVPA_COMMON_H
|
||||
#define LVPA_COMMON_H
|
||||
|
||||
#include "LVPACompileConfig.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <cstring>
|
||||
|
||||
LVPA_NAMESPACE_START
|
||||
|
||||
#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
|
||||
|
||||
struct memblock
|
||||
{
|
||||
memblock() : ptr(NULL), size(0) {}
|
||||
memblock(uint8 *p, uint32 s) : size(s), ptr(p) {}
|
||||
uint8 *ptr;
|
||||
uint32 size;
|
||||
};
|
||||
|
||||
|
||||
LVPA_NAMESPACE_END
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef LVPA_COMPILE_CONFIG
|
||||
#define LVPA_COMPILE_CONFIG
|
||||
|
||||
// TODO ADD TEXT
|
||||
#define LVPA_NAMESPACE lvpa
|
||||
|
||||
//#define LVPA_SUPPORT_ZLIB
|
||||
#define LVPA_SUPPORT_LZMA
|
||||
//#define LVPA_SUPPORT_LZO
|
||||
#define LVPA_SUPPORT_LZF
|
||||
|
||||
|
||||
|
||||
// ------ End of config ------
|
||||
|
||||
#ifdef LVPA_NAMESPACE
|
||||
# define LVPA_NAMESPACE_START namespace LVPA_NAMESPACE {
|
||||
# define LVPA_NAMESPACE_END }
|
||||
# define LVPA_NAMESPACE_IMPL LVPA_NAMESPACE::
|
||||
namespace LVPA_NAMESPACE {} // predeclare namespace to make compilers happy
|
||||
#else
|
||||
# define LVPA_NAMESPACE_START
|
||||
# define LVPA_NAMESPACE_END
|
||||
# define LVPA_NAMESPACE_IMPL
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
|
@ -1,201 +0,0 @@
|
|||
#ifndef LVPA_INTERNAL_H
|
||||
#define LVPA_INTERNAL_H
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
# define DBG if(1)
|
||||
# define DEBUG(x) x;
|
||||
# define logdebug(...) { printf(__VA_ARGS__); putchar('\n'); }
|
||||
# define logerror(...) { fputs("ERROR: ",stdout); printf(__VA_ARGS__); putchar('\n'); }
|
||||
#else
|
||||
# define DBG if(0)
|
||||
# define DEBUG(x)
|
||||
# define logdebug(...)
|
||||
# define logerror(...)
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
// Platform defines
|
||||
//////////////////////////////////////
|
||||
|
||||
#define PLATFORM_WIN32 0
|
||||
#define PLATFORM_UNIX 1
|
||||
#define PLATFORM_APPLE 2
|
||||
#define PLATFORM_INTEL 3
|
||||
|
||||
#if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
|
||||
# define PLATFORM PLATFORM_WIN32
|
||||
#elif defined( __APPLE_CC__ )
|
||||
# define PLATFORM PLATFORM_APPLE
|
||||
#elif defined( __INTEL_COMPILER )
|
||||
# define PLATFORM PLATFORM_INTEL
|
||||
#else
|
||||
# define PLATFORM PLATFORM_UNIX
|
||||
#endif
|
||||
|
||||
#define COMPILER_MICROSOFT 0
|
||||
#define COMPILER_GNU 1
|
||||
#define COMPILER_BORLAND 2
|
||||
#define COMPILER_INTEL 3
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define COMPILER COMPILER_MICROSOFT
|
||||
#elif defined( __BORLANDC__ )
|
||||
# define COMPILER COMPILER_BORLAND
|
||||
#elif defined( __INTEL_COMPILER )
|
||||
# define COMPILER COMPILER_INTEL
|
||||
#elif defined( __GNUC__ )
|
||||
# define COMPILER COMPILER_GNU
|
||||
#else
|
||||
# pragma error "FATAL ERROR: Unknown compiler."
|
||||
#endif
|
||||
|
||||
// stupid warnings
|
||||
#if COMPILER == COMPILER_MICROSOFT
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_DEPRECATE
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////
|
||||
// Compiler defines
|
||||
////////////////////////////////////
|
||||
|
||||
#if COMPILER == COMPILER_MICROSOFT
|
||||
#define I64FMT "%016I64X"
|
||||
#define I64FMTD "%I64u"
|
||||
#define I64LIT(x) (x ## i64)
|
||||
#define UI64LIT(x) (x ## ui64)
|
||||
#define snprintf _snprintf
|
||||
#else
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#define I64FMT "%016llX"
|
||||
#define I64FMTD "%llu"
|
||||
#define I64LIT(x) (x ## LL)
|
||||
#define UI64LIT(x) (x ## ULL)
|
||||
#endif
|
||||
|
||||
#ifndef _LP64
|
||||
# if defined (_M_IA64) || defined (__ia64__) || defined (_M_AMD64) || defined (__amd64) || defined(_M_X64)
|
||||
# define _LP64 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _LP64 // to be set for 64 bit compile
|
||||
# define PTRFMT "0x"I64FMT
|
||||
# define SYSTEM_BITS 64
|
||||
#else
|
||||
# define PTRFMT "0x%X"
|
||||
# define SYSTEM_BITS 32
|
||||
#endif
|
||||
|
||||
#ifndef SIGQUIT
|
||||
#define SIGQUIT 3
|
||||
#endif
|
||||
|
||||
#if COMPILER == COMPILER_MICROSOFT
|
||||
# if _MSC_VER >= 1600
|
||||
# define COMPILER_NAME "VC100+"
|
||||
# elif _MSC_VER >= 1500
|
||||
# define COMPILER_NAME "VC90"
|
||||
# elif _MSC_VER >= 1400
|
||||
# define COMPILER_NAME "VC80"
|
||||
# elif _MSC_VER >= 1310
|
||||
# define COMPILER_NAME "VC71"
|
||||
# endif
|
||||
# define COMPILER_VERSION _MSC_VER
|
||||
# define COMPILER_VERSION_OUT "%u"
|
||||
#elif COMPILER == COMPILER_GNU
|
||||
# define COMPILER_NAME "GCC"
|
||||
# ifndef __GNUC_PATCHLEVEL__
|
||||
# define __GNUC_PATCHLEVEL__ 0
|
||||
# endif
|
||||
# define COMPILER_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||
# define COMPILER_VERSION_OUT "%u"
|
||||
// TODO: add more compilers here when necessary
|
||||
#else
|
||||
# define COMPILER_NAME "unknown"
|
||||
# define COMPILER_VERSION "unk"
|
||||
# define COMPILER_VERSION_OUT "%s"
|
||||
#endif
|
||||
|
||||
#if PLATFORM == PLATFORM_UNIX
|
||||
# define PLATFORM_NAME "Unix"
|
||||
#elif PLATFORM == PLATFORM_WIN32
|
||||
# define PLATFORM_NAME "Win32"
|
||||
#elif PLATFORM == PLATFORM_APPLE
|
||||
# define PLATFORM_NAME "Apple"
|
||||
// TODO: add more platforms here when necessary
|
||||
#else
|
||||
# define PLATFORM_NAME "unknown"
|
||||
#endif
|
||||
|
||||
#if COMPILER == COMPILER_GNU
|
||||
# define ATTR_NORETURN __attribute__((noreturn))
|
||||
# define ATTR_PRINTF(F,V) __attribute__ ((format (printf, F, V)))
|
||||
#else //COMPILER != COMPILER_GNU
|
||||
# define ATTR_NORETURN
|
||||
# define ATTR_PRINTF(F,V)
|
||||
#endif //COMPILER == COMPILER_GNU
|
||||
|
||||
|
||||
// taken from ACE
|
||||
// have seen on some systems that both defines exist, so if that is is the case, rely on this detection here
|
||||
#if (!defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)) || (defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN))
|
||||
# if defined (i386) || defined (__i386__) || defined (_M_IX86) || \
|
||||
defined (vax) || defined (__alpha) || defined (__LITTLE_ENDIAN__) || \
|
||||
defined (ARM) || defined (_M_IA64) || defined (__ia64__) || \
|
||||
defined (_M_AMD64) || defined (__amd64)
|
||||
// We know these are little endian.
|
||||
# undef LITTLE_ENDIAN
|
||||
# undef BIG_ENDIAN
|
||||
# define LITTLE_ENDIAN 1
|
||||
# define IS_LITTLE_ENDIAN 1
|
||||
# define IS_BIG_ENDIAN 0
|
||||
# else
|
||||
// Otherwise, we assume big endian.
|
||||
# undef LITTLE_ENDIAN
|
||||
# undef BIG_ENDIAN
|
||||
# define BIG_ENDIAN 1
|
||||
# define IS_LITTLE_ENDIAN 0
|
||||
# define IS_BIG_ENDIAN 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define ASSERT(what) { if (!(what)) { fprintf( stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n", __FILE__, __LINE__,__FUNCTION__, #what); assert( #what &&0 ); } }
|
||||
|
||||
|
||||
|
||||
#include "LVPACommon.h"
|
||||
|
||||
LVPA_NAMESPACE_START
|
||||
|
||||
|
||||
template <typename T> class AutoPtrVector
|
||||
{
|
||||
public:
|
||||
inline AutoPtrVector(uint32 prealloc) :v(prealloc)
|
||||
{
|
||||
for(uint32 i = 0; i < prealloc; ++i)
|
||||
v[i] = NULL;
|
||||
}
|
||||
inline ~AutoPtrVector()
|
||||
{
|
||||
for(uint32 i = 0; i < v.size(); ++i)
|
||||
if(v[i])
|
||||
delete v[i];
|
||||
}
|
||||
std::vector<T*> v;
|
||||
};
|
||||
|
||||
LVPA_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1,64 +0,0 @@
|
|||
|
||||
option(TTVFS_LARGEFILE_SUPPORT "Enable support for files > 4 GB? (experimental!)" FALSE)
|
||||
option(TTVFS_IGNORE_CASE "Enable full case-insensitivity even on case-sensitive OSes like Linux and alike?" FALSE)
|
||||
|
||||
# Be sure to copy this part to your root CMakeLists.txt if you prefer to use CMake for configuring
|
||||
# instead of editing the headers directly!
|
||||
# If you edit the headers, this is not necessary.
|
||||
if(TTVFS_LARGEFILE_SUPPORT)
|
||||
add_definitions("-DVFS_LARGEFILE_SUPPORT")
|
||||
endif()
|
||||
if(TTVFS_IGNORE_CASE)
|
||||
add_definitions("-DVFS_IGNORE_CASE")
|
||||
endif()
|
||||
# --snip--
|
||||
|
||||
|
||||
# compiler specific things
|
||||
if(MSVC)
|
||||
# MSVC builds require installed runtime library by default
|
||||
option(TTVFS_STATIC_LIB "Link as static library without runtime dependencies (Note: To get rid of this setting with MSVC, the cmake cache must be cleared)" FALSE)
|
||||
add_definitions("/GR-") # run-time type info (RTTI) not required
|
||||
|
||||
if(TTVFS_STATIC_LIB)
|
||||
# this is ugly - hackfix compiler flags
|
||||
foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if(${flag_var} MATCHES "/MD")
|
||||
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
||||
endif(${flag_var} MATCHES "/MD")
|
||||
if(${flag_var} MATCHES "/MDd")
|
||||
string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}")
|
||||
endif(${flag_var} MATCHES "/MDd")
|
||||
endforeach()
|
||||
|
||||
# hackfix linker flags - no idea why, but MSVC will produce linker errors otherwise
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /NODEFAULTLIB")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NODEFAULTLIB:msvcrt.lib,msvcrtd.lib") # not sure if this is correct
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:msvcrt.lib,msvcrtd.lib")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
set(ttvfs_SRC
|
||||
VFS.h
|
||||
VFSAtomic.cpp
|
||||
VFSAtomic.h
|
||||
VFSDefines.h
|
||||
VFSDir.cpp
|
||||
VFSDir.h
|
||||
VFSFile.cpp
|
||||
VFSFile.h
|
||||
VFSHelper.cpp
|
||||
VFSHelper.h
|
||||
VFSInternal.h
|
||||
VFSLoader.cpp
|
||||
VFSLoader.h
|
||||
VFSSelfRefCounter.h
|
||||
VFSTools.cpp
|
||||
VFSTools.h
|
||||
)
|
||||
|
||||
set(TTVFS_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} CACHE STRING "ttvfs include directory - for external includers" FORCE)
|
||||
set(TTVFS_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE STRING "ttvfs source directory - for external includers" FORCE)
|
||||
|
||||
add_library(ttvfs ${ttvfs_SRC})
|
|
@ -1,78 +0,0 @@
|
|||
/* ttvfs -- tiny tree virtual file system
|
||||
|
||||
// VFS.h - all the necessary includes to get a basic VFS working
|
||||
// Only include externally, not inside the library.
|
||||
|
||||
See VFSDefines.h for compile configration.
|
||||
|
||||
|
||||
---------[ License ]----------
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TTVFS_VFS_H
|
||||
#define TTVFS_VFS_H
|
||||
|
||||
#include "VFSDefines.h"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
bool _checkCompatInternal(bool large, bool nocase, unsigned int vfspos_size);
|
||||
|
||||
/** It is recommended to call this function early in your code
|
||||
and ensure it returns true - if it does not, compiler settings
|
||||
are inconsistent, which may cause otherwise hard to detect problems. */
|
||||
inline static bool checkCompat(void)
|
||||
{
|
||||
#ifdef VFS_LARGEFILE_SUPPORT
|
||||
bool largefile = true;
|
||||
#else
|
||||
bool largefile = false;
|
||||
#endif
|
||||
|
||||
#ifdef VFS_IGNORE_CASE
|
||||
bool nocase = true;
|
||||
#else
|
||||
bool nocase = false;
|
||||
#endif
|
||||
return _checkCompatInternal(largefile, nocase, sizeof(vfspos));
|
||||
}
|
||||
VFS_NAMESPACE_END
|
||||
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include "VFSHelper.h"
|
||||
#include "VFSFile.h"
|
||||
#include "VFSDir.h"
|
||||
|
||||
|
||||
// Checks to enforce correct including.
|
||||
// At least on windows, <string> includes <cstdio>,
|
||||
// but that must be included after "VFSInternal.h",
|
||||
// and "VFSInternal.h" may only be used inside the library (or by extensions),
|
||||
// because it redefines fseek and ftell, which would
|
||||
// mess up the ABI if included elsewhere.
|
||||
#ifdef VFS_INTERNAL_H
|
||||
#error Oops, VFS_INTERNAL_H is defined, someone messed up and included VFSInternal.h wrongly.
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,103 +0,0 @@
|
|||
// VFSAtomic.cpp - atomic operations and thread locking
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
/** --- Atomic operations and thread safety ---
|
||||
* You may want to add your own implementation if thread safety is needed.
|
||||
* If not, just leave everything like it is.
|
||||
|
||||
* If you are on windows, Interlocked[In/De]crement is faster than
|
||||
explicit mutex locking for integer operations.
|
||||
|
||||
* TODO: The actual locking that is done in the tree when VFS_THREADSAFE is defined
|
||||
is rather crude for the time beeing; a somewhat more efficient ReadWriteLock
|
||||
implementation would be nice to have, someday.
|
||||
|
||||
* If you can, leave VFS_THREADSAFE undefined and do the locking externally,
|
||||
it will probably have much better performance than if each and every operation
|
||||
does a lock and unlock call.
|
||||
(For a rather I/O based library this should not really make a difference, anyway.
|
||||
But don't say you haven't been warned :) )
|
||||
*/
|
||||
|
||||
#include "VFSInternal.h"
|
||||
#include "VFSAtomic.h"
|
||||
|
||||
// for Interlocked[In/De]crement, if required
|
||||
#if defined(_WIN32) && defined(VFS_THREADSAFE)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
#ifdef VFS_THREADSAFE
|
||||
static Mutex mtx;
|
||||
#endif
|
||||
|
||||
int Atomic_Incr(volatile int &i)
|
||||
{
|
||||
#ifdef VFS_THREADSAFE
|
||||
# ifdef _WIN32
|
||||
volatile LONG* dp = (volatile LONG*) &i;
|
||||
return InterlockedIncrement( dp );
|
||||
# else
|
||||
Guard g(mtx);
|
||||
# endif
|
||||
#endif
|
||||
return ++i;
|
||||
}
|
||||
|
||||
int Atomic_Decr(volatile int &i)
|
||||
{
|
||||
#ifdef VFS_THREADSAFE
|
||||
# ifdef _WIN32
|
||||
volatile LONG* dp = (volatile LONG*) &i;
|
||||
return InterlockedDecrement( dp );
|
||||
# else
|
||||
Guard g(mtx);
|
||||
# endif
|
||||
#endif
|
||||
return --i;
|
||||
}
|
||||
|
||||
/* Implement your Mutex class here.
|
||||
Important: The mutex must be re-entrant/recursive,
|
||||
means it must be possible to lock it from the same thread multiple times.
|
||||
*/
|
||||
Mutex::Mutex()
|
||||
{
|
||||
// implement your own if needed. Remove the trap below when you are done.
|
||||
// This is to prevent people from defining VFS_THREADSAFE and expecting everything to work just like that :)
|
||||
#ifdef VFS_THREADSAFE
|
||||
#error VFSAtomic: Hey, you forgot to implement the mutex class, cant guarantee thread safety! Either undef VFS_THREADSAFE or read the docs and get your hands dirty.
|
||||
#endif
|
||||
}
|
||||
|
||||
Mutex::~Mutex()
|
||||
{
|
||||
// implement your own if needed
|
||||
}
|
||||
|
||||
void Mutex::Lock(void)
|
||||
{
|
||||
// implement your own if needed
|
||||
}
|
||||
|
||||
void Mutex::Unlock(void)
|
||||
{
|
||||
// implement your own if needed
|
||||
}
|
||||
|
||||
Guard::Guard(Mutex& m)
|
||||
: _m(m)
|
||||
{
|
||||
_m.Lock();
|
||||
}
|
||||
|
||||
Guard::~Guard()
|
||||
{
|
||||
_m.Unlock();
|
||||
}
|
||||
|
||||
|
||||
VFS_NAMESPACE_END
|
|
@ -1,39 +0,0 @@
|
|||
// VFSAtomic.h - atomic operations and thread locking
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#ifndef VFS_ATOMIC_H
|
||||
#define VFS_ATOMIC_H
|
||||
|
||||
#include "VFSDefines.h"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
int Atomic_Incr(volatile int &i);
|
||||
int Atomic_Decr(volatile int &i);
|
||||
|
||||
// generic Mutex class, needs to be reentrant/recursive.
|
||||
class Mutex
|
||||
{
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
|
||||
protected:
|
||||
// add own stuff if needed
|
||||
};
|
||||
|
||||
class Guard
|
||||
{
|
||||
public:
|
||||
Guard(Mutex& m);
|
||||
~Guard();
|
||||
|
||||
protected:
|
||||
Mutex& _m;
|
||||
};
|
||||
|
||||
VFS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1,79 +0,0 @@
|
|||
// VFSDefines.h - compile config and basic setup
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#ifndef VFS_DEFINES_H
|
||||
#define VFS_DEFINES_H
|
||||
|
||||
/* --- Config section -- modify as needed --- */
|
||||
|
||||
// choose a namespace name, or comment out to disable namespacing completely (not recommended)
|
||||
#define VFS_NAMESPACE ttvfs
|
||||
|
||||
// Define this to allow dealing with files > 4 GB, using non-standard functions.
|
||||
// This may or may not work with your platform/compiler, good luck.
|
||||
//#define VFS_LARGEFILE_SUPPORT
|
||||
|
||||
// Define this to make all operations case insensitive.
|
||||
// Windows systems generally don't care much, but for Linux and Mac this can be used
|
||||
// to get the same behavior as on windows.
|
||||
// Additionally, this achieves full case insensitivity within the library,
|
||||
// if the the same files are accessed multiple times by the program, but with not-uniform case.
|
||||
// (no sane programmer should do this, anyway).
|
||||
// However, on non-windows systems this will decrease performance when checking for files
|
||||
// on disk (see VFSLoader.cpp).
|
||||
#define VFS_IGNORE_CASE
|
||||
|
||||
// Define this to make all VFSFile, VFSDir, VFSHelper operations thread-safe.
|
||||
// If you do, do not forget to add your own implementation to VFSAtomic.cpp/.h !
|
||||
// If this is not defined, you can still do manual locking if you know what you're doing,
|
||||
// performance matters, and you implemented actual locking into the Mutex class.
|
||||
// If no Mutex implementation is provided, its operations are no-ops, beware!
|
||||
//#define VFS_THREADSAFE
|
||||
|
||||
|
||||
/* --- End of config section --- */
|
||||
|
||||
|
||||
#ifdef VFS_NAMESPACE
|
||||
# define VFS_NAMESPACE_START namespace VFS_NAMESPACE {
|
||||
# define VFS_NAMESPACE_END }
|
||||
# define VFS_NAMESPACE_IMPL VFS_NAMESPACE::
|
||||
#else
|
||||
# define VFS_NAMESPACE_START
|
||||
# define VFS_NAMESPACE_END
|
||||
# define VFS_NAMESPACE_IMPL
|
||||
#endif
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
#ifdef VFS_LARGEFILE_SUPPORT
|
||||
# if defined(_MSC_VER)
|
||||
typedef __int64 vfspos;
|
||||
# else
|
||||
typedef long long vfspos;
|
||||
# endif
|
||||
#else
|
||||
typedef unsigned int vfspos;
|
||||
#endif
|
||||
|
||||
// simple guard wrapper, works also if VFS_THREADSAFE is not defined
|
||||
#define VFS_GUARD(obj) VFS_NAMESPACE_IMPL Guard __vfs_stack_guard((obj)->mutex())
|
||||
|
||||
// defines for optional auto-locking; only if VFS_THREADSAFE is defined
|
||||
#ifdef VFS_THREADSAFE
|
||||
# define VFS_GUARD_OPT(obj) VFS_GUARD(obj)
|
||||
#else
|
||||
# define VFS_GUARD_OPT(obj)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define VFS_STRICMP stricmp
|
||||
#else
|
||||
# define VFS_STRICMP strcasecmp
|
||||
#endif
|
||||
|
||||
static const vfspos npos = vfspos(-1);
|
||||
|
||||
VFS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1,255 +0,0 @@
|
|||
// VFSDir.cpp - basic directory interface + classes
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#include "VFSInternal.h"
|
||||
#include "VFSTools.h"
|
||||
#include "VFSFile.h"
|
||||
#include "VFSDir.h"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
VFSDir::VFSDir()
|
||||
: ref(this), _name(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
VFSDir::VFSDir(const char *fullpath)
|
||||
: ref(this)
|
||||
{
|
||||
_setFullName(fullpath);
|
||||
}
|
||||
|
||||
VFSDir::~VFSDir()
|
||||
{
|
||||
for(Files::iterator it = _files.begin(); it != _files.end(); it++)
|
||||
it->second->ref--;
|
||||
for(Dirs::iterator it = _subdirs.begin(); it != _subdirs.end(); it++)
|
||||
it->second->ref--;
|
||||
}
|
||||
|
||||
void VFSDir::_setFullName(const char *fullname)
|
||||
{
|
||||
_fullname = FixPath(fullname);
|
||||
_name = PathToFileName(_fullname.c_str());
|
||||
}
|
||||
|
||||
VFSDir *VFSDir::createNew(void) const
|
||||
{
|
||||
return new VFSDir;
|
||||
}
|
||||
|
||||
unsigned int VFSDir::load(const char *dir /* = NULL */)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool VFSDir::add(VFSFile *f, bool overwrite /* = true */)
|
||||
{
|
||||
if(!f)
|
||||
return false;
|
||||
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
Files::iterator it = _files.find(f->name());
|
||||
|
||||
if(it != _files.end())
|
||||
{
|
||||
if(overwrite)
|
||||
{
|
||||
VFSFile *oldf = it->second;
|
||||
if(oldf == f)
|
||||
return false;
|
||||
|
||||
oldf->ref--;
|
||||
_files.erase(it);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
f->ref++;
|
||||
_files[f->name()] = f;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VFSDir::addRecursive(VFSFile *f, bool overwrite /* = true */)
|
||||
{
|
||||
if(!f)
|
||||
return false;
|
||||
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
// figure out directory from full file name
|
||||
std::string dirname(f->fullname());
|
||||
size_t pathend = dirname.find_last_of("/\\");
|
||||
VFSDir *vdir;
|
||||
if(pathend != std::string::npos)
|
||||
{
|
||||
dirname = dirname.substr(0, pathend);
|
||||
vdir = getDir(dirname.c_str(), true);
|
||||
}
|
||||
else
|
||||
vdir = this;
|
||||
|
||||
return vdir->add(f, true);
|
||||
}
|
||||
|
||||
bool VFSDir::merge(VFSDir *dir, bool overwrite /* = true */)
|
||||
{
|
||||
if(!dir)
|
||||
return false;
|
||||
|
||||
bool result = false;
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
for(Files::iterator it = dir->_files.begin(); it != dir->_files.end(); it++)
|
||||
result = add(it->second, overwrite) || result;
|
||||
|
||||
for(Dirs::iterator it = dir->_subdirs.begin(); it != dir->_subdirs.end(); it++)
|
||||
result = insert(it->second, overwrite) || result;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VFSDir::insert(VFSDir *subdir, bool overwrite /* = true */)
|
||||
{
|
||||
if(!subdir)
|
||||
return false;
|
||||
|
||||
VFS_GUARD_OPT(this);
|
||||
Dirs::iterator it = _subdirs.find(subdir->name());
|
||||
VFSDir *mydir;
|
||||
if(it != _subdirs.end())
|
||||
{
|
||||
mydir = it->second;
|
||||
//return it->second->merge(subdir, overwrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a new subtree, not to pollute the original one with data that may be added later
|
||||
mydir = subdir->createNew(); // create subdir of same type
|
||||
mydir->_setFullName(subdir->fullname());
|
||||
_subdirs[mydir->name()] = mydir;
|
||||
}
|
||||
|
||||
return mydir->merge(subdir, overwrite);
|
||||
}
|
||||
|
||||
VFSFile *VFSDir::getFile(const char *fn)
|
||||
{
|
||||
char *slashpos = (char *)strchr(fn, '/');
|
||||
|
||||
// if there is a '/' in the string, descend into subdir and continue there
|
||||
if(slashpos)
|
||||
{
|
||||
const char *sub = slashpos + 1;
|
||||
std::string t(fn, slashpos - fn);
|
||||
VFS_GUARD_OPT(this);
|
||||
VFSDir *subdir = getDir(t.c_str()); // fn is null-terminated early here
|
||||
return subdir ? subdir->getFile(sub) : NULL;
|
||||
}
|
||||
|
||||
// no subdir? file must be in this dir now.
|
||||
VFS_GUARD_OPT(this);
|
||||
Files::iterator it = _files.find(fn);
|
||||
return it != _files.end() ? it->second : NULL;
|
||||
}
|
||||
|
||||
VFSDir *VFSDir::getDir(const char *subdir, bool forceCreate /* = false */)
|
||||
{
|
||||
if(!subdir[0] || (subdir[0] == '.' && (!subdir[1] || subdir[1] == '/'))) // empty string or "." or "./" ? use this.
|
||||
return this;
|
||||
|
||||
VFSDir *ret = NULL;
|
||||
char *slashpos = (char *)strchr(subdir, '/');
|
||||
|
||||
// if there is a '/' in the string, descend into subdir and continue there
|
||||
if(slashpos)
|
||||
{
|
||||
const char *sub = slashpos + 1;
|
||||
std::string t(subdir, slashpos - subdir);
|
||||
VFS_GUARD_OPT(this);
|
||||
Dirs::iterator it = _subdirs.find(t);
|
||||
if(it != _subdirs.end())
|
||||
{
|
||||
ret = it->second->getDir(sub, forceCreate); // descend into subdirs
|
||||
}
|
||||
else if(forceCreate)
|
||||
{
|
||||
VFSDir *ins = createNew();
|
||||
std::string newname(fullname());
|
||||
newname += '/';
|
||||
newname += t;
|
||||
ins->_setFullName(newname.c_str());
|
||||
_subdirs[ins->name()] = ins;
|
||||
ret = ins->getDir(sub, true); // create remaining structure
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
Dirs::iterator it = _subdirs.find(subdir);
|
||||
if(it != _subdirs.end())
|
||||
ret = it->second;
|
||||
else if(forceCreate)
|
||||
{
|
||||
ret = createNew();
|
||||
std::string newname(fullname());
|
||||
newname += '/';
|
||||
newname += subdir;
|
||||
ret->_setFullName(newname.c_str());
|
||||
_subdirs[ret->name()] = ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----- VFSDirReal start here -----
|
||||
|
||||
|
||||
VFSDirReal::VFSDirReal() : VFSDir()
|
||||
{
|
||||
}
|
||||
|
||||
VFSDir *VFSDirReal::createNew(void) const
|
||||
{
|
||||
return new VFSDirReal;
|
||||
}
|
||||
|
||||
unsigned int VFSDirReal::load(const char *dir /* = NULL */)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(dir)
|
||||
_setFullName(dir);
|
||||
|
||||
StringList li;
|
||||
GetFileList(_fullname.c_str(), li);
|
||||
for(StringList::iterator it = li.begin(); it != li.end(); it++)
|
||||
{
|
||||
if(VFSFile *oldf = getFile(it->c_str()))
|
||||
oldf->ref--;
|
||||
VFSFileReal *f = new VFSFileReal((_fullname + '/' + *it).c_str());
|
||||
_files[f->name()] = f;
|
||||
}
|
||||
unsigned int sum = li.size();
|
||||
|
||||
li.clear();
|
||||
GetDirList(_fullname.c_str(), li, false);
|
||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); it++)
|
||||
{
|
||||
if(VFSDir *oldd = getDir(it->c_str()))
|
||||
oldd->ref--;
|
||||
VFSDir *d = createNew();
|
||||
std::string full(_fullname);
|
||||
full += '/';
|
||||
full += *it;
|
||||
sum += d->load(full.c_str()); // GetDirList() always returns relative paths
|
||||
_subdirs[d->name()] = d;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
VFS_NAMESPACE_END
|
|
@ -1,118 +0,0 @@
|
|||
// VFSDir.h - basic directory interface + classes
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#ifndef VFSDIR_H
|
||||
#define VFSDIR_H
|
||||
|
||||
#include "VFSDefines.h"
|
||||
#include <map>
|
||||
#include "VFSSelfRefCounter.h"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
#ifdef VFS_IGNORE_CASE
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
# endif
|
||||
|
||||
struct ci_less
|
||||
{
|
||||
inline bool operator() (const std::string& a, const std::string& b) const
|
||||
{
|
||||
return VFS_STRICMP(a.c_str(), b.c_str()) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
class VFSDir;
|
||||
class VFSFile;
|
||||
|
||||
class VFSDir
|
||||
{
|
||||
public:
|
||||
|
||||
#ifdef VFS_IGNORE_CASE
|
||||
typedef std::map<std::string, VFSDir*, ci_less> Dirs;
|
||||
typedef std::map<std::string, VFSFile*, ci_less> Files;
|
||||
#else
|
||||
typedef std::map<std::string, VFSDir*> Dirs;
|
||||
typedef std::map<std::string, VFSFile*> Files;
|
||||
#endif
|
||||
|
||||
VFSDir();
|
||||
VFSDir(const char *fullpath);
|
||||
virtual ~VFSDir();
|
||||
|
||||
/* Load directory with given path. If dir is NULL, reload previously loaded directory.
|
||||
If there is no previously loaded directory, load root. */
|
||||
virtual unsigned int load(const char *dir = NULL);
|
||||
virtual VFSFile *getFile(const char *fn);
|
||||
virtual VFSDir *getDir(const char *subdir, bool forceCreate = false);
|
||||
virtual VFSDir *createNew(void) const;
|
||||
virtual const char *getType(void) const { return "VFSDir"; }
|
||||
|
||||
bool insert(VFSDir *subdir, bool overwrite = true);
|
||||
bool merge(VFSDir *dir, bool overwrite = true);
|
||||
bool add(VFSFile *f, bool overwrite = true); // add file directly in this dir
|
||||
bool addRecursive(VFSFile *f, bool overwrite = true); // traverse subdir tree to find correct subdir; create if not existing
|
||||
|
||||
|
||||
inline const char *name() const { VFS_GUARD_OPT(this); return _name; }
|
||||
inline const char *fullname() const { VFS_GUARD_OPT(this); return _fullname.c_str(); }
|
||||
|
||||
// iterators are NOT thread-safe! If you need to iterate over things in a multithreaded environment,
|
||||
// do the locking yourself! (see below)
|
||||
inline Files::iterator fileIter() { return _files.begin(); }
|
||||
inline Files::iterator fileIterEnd() { return _files.end(); }
|
||||
inline Dirs::iterator dirIter() { return _subdirs.begin(); }
|
||||
inline Dirs::iterator dirIterEnd() { return _subdirs.end(); }
|
||||
inline Files::const_iterator fileIter() const { return _files.begin(); }
|
||||
inline Files::const_iterator fileIterEnd() const { return _files.end(); }
|
||||
inline Dirs::const_iterator dirIter() const { return _subdirs.begin(); }
|
||||
inline Dirs::const_iterator dirIterEnd() const { return _subdirs.end(); }
|
||||
|
||||
// std::map<std::string,*> stores for files and subdirs
|
||||
Files _files;
|
||||
Dirs _subdirs;
|
||||
|
||||
// reference counter, does auto-delete holder when it reaches 0. initially 1.
|
||||
SelfRefCounter<VFSDir> ref;
|
||||
|
||||
// the following functions should be used before and after an iteration finishes
|
||||
// alternatively, VFS_GUARD(dir) can be used to create a locking guard on the stack.
|
||||
inline void lock() { _mtx.Lock(); }
|
||||
inline void unlock() { _mtx.Unlock(); }
|
||||
inline Mutex& mutex() const { return _mtx; }
|
||||
|
||||
protected:
|
||||
void _setFullName(const char *fullname);
|
||||
std::string _fullname;
|
||||
const char *_name; // must point to an address constant during object lifetime (like _fullname.c_str() + N)
|
||||
// (not necessary to have an additional string copy here, just wastes memory)
|
||||
mutable Mutex _mtx;
|
||||
};
|
||||
|
||||
typedef VFSDir::Files::iterator FileIter;
|
||||
typedef VFSDir::Dirs::iterator DirIter;
|
||||
typedef VFSDir::Files::const_iterator ConstFileIter;
|
||||
typedef VFSDir::Dirs::const_iterator ConstDirIter;
|
||||
|
||||
class VFSDirReal : public VFSDir
|
||||
{
|
||||
public:
|
||||
VFSDirReal();
|
||||
virtual ~VFSDirReal() {};
|
||||
virtual unsigned int load(const char *dir = NULL);
|
||||
virtual VFSDir *createNew(void) const;
|
||||
virtual const char *getType(void) const { return "VFSDirReal"; }
|
||||
};
|
||||
|
||||
VFS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1,258 +0,0 @@
|
|||
// 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"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
VFSFile::VFSFile()
|
||||
: ref(this)
|
||||
{
|
||||
}
|
||||
|
||||
VFSFileReal::VFSFileReal(const char *name /* = NULL */)
|
||||
: VFSFile()
|
||||
{
|
||||
_buf = NULL;
|
||||
_setName(name);
|
||||
_fh = NULL;
|
||||
_size = npos;
|
||||
}
|
||||
|
||||
VFSFileReal::~VFSFileReal()
|
||||
{
|
||||
close();
|
||||
dropBuf(true);
|
||||
}
|
||||
|
||||
// call this only with a lock held!
|
||||
void VFSFileReal::_setName(const char *n)
|
||||
{
|
||||
if(n && *n)
|
||||
{
|
||||
_fullname = FixPath(n);
|
||||
_name = PathToFileName(_fullname.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool VFSFileReal::open(const char *fn /* = NULL */, const char *mode /* = NULL */)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
if(isopen())
|
||||
close();
|
||||
|
||||
dropBuf(true);
|
||||
|
||||
_setName(fn);
|
||||
|
||||
_fh = fopen(_fullname.c_str(), mode ? mode : "rb");
|
||||
if(!_fh)
|
||||
return false;
|
||||
|
||||
fseek((FILE*)_fh, 0, SEEK_END);
|
||||
_size = getpos();
|
||||
fseek((FILE*)_fh, 0, SEEK_SET);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VFSFileReal::isopen(void) const
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
return !!_fh;
|
||||
}
|
||||
|
||||
bool VFSFileReal::iseof(void) const
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
return !_fh || feof((FILE*)_fh);
|
||||
}
|
||||
|
||||
const char *VFSFileReal::name(void) const
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
return _name;
|
||||
}
|
||||
|
||||
const char *VFSFileReal::fullname(void) const
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
return _fullname.c_str();
|
||||
}
|
||||
|
||||
bool VFSFileReal::close(void)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(_fh)
|
||||
{
|
||||
fclose((FILE*)_fh);
|
||||
_fh = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VFSFileReal::seek(vfspos pos)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(!_fh)
|
||||
return false;
|
||||
fseek((FILE*)_fh, pos, SEEK_SET);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VFSFileReal::seekRel(vfspos offs)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(!_fh)
|
||||
return false;
|
||||
fseek((FILE*)_fh, offs, SEEK_CUR);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VFSFileReal::flush(void)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(_fh)
|
||||
return false;
|
||||
fflush((FILE*)_fh);
|
||||
return true;
|
||||
}
|
||||
|
||||
vfspos VFSFileReal::getpos(void) const
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(!_fh)
|
||||
return npos;
|
||||
return ftell((FILE*)_fh);
|
||||
}
|
||||
|
||||
unsigned int VFSFileReal::read(void *dst, unsigned int bytes)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(!_fh)
|
||||
return npos;
|
||||
return 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 fwrite(src, 1, bytes, (FILE*)_fh);
|
||||
}
|
||||
|
||||
vfspos VFSFileReal::size(void)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(_size != npos)
|
||||
return _size;
|
||||
open();
|
||||
close();
|
||||
// now size is known.
|
||||
return _size;
|
||||
}
|
||||
|
||||
const void *VFSFileReal::getBuf(void)
|
||||
{
|
||||
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 = malloc(s + 4); // a bit extra padding
|
||||
if(!_buf)
|
||||
return NULL;
|
||||
|
||||
if(op)
|
||||
{
|
||||
vfspos oldpos = getpos();
|
||||
seek(0);
|
||||
unsigned int offs = read(_buf, s);
|
||||
memset((char*)_buf + offs, 0, 4);
|
||||
seek(oldpos);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int offs = read(_buf, s);
|
||||
memset((char*)_buf + offs, 0, 4);
|
||||
close();
|
||||
}
|
||||
return _buf;
|
||||
}
|
||||
|
||||
void VFSFileReal::dropBuf(bool del)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(del && _buf)
|
||||
free(_buf);
|
||||
_buf = NULL;
|
||||
}
|
||||
|
||||
// ------------- VFSFileMem -----------------------
|
||||
|
||||
VFSFileMem::VFSFileMem(const char *name, void *buf, unsigned int size, Mode mode /* = COPY */, delete_func delfunc /* = NULL */)
|
||||
: VFSFile(), _pos(0), _size(size), _buf(buf), _delfunc(delfunc), _mybuf(mode == TAKE_OVER || mode == COPY)
|
||||
{
|
||||
_setName(name);
|
||||
if(mode == COPY)
|
||||
{
|
||||
_buf = malloc(size+1);
|
||||
_delfunc = free;
|
||||
memcpy(_buf, buf, size);
|
||||
((char*)_buf)[size] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VFSFileMem::~VFSFileMem()
|
||||
{
|
||||
if(_mybuf)
|
||||
{
|
||||
if(_delfunc)
|
||||
_delfunc(_buf);
|
||||
else
|
||||
delete [] (char*)_buf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VFSFileMem::_setName(const char *n)
|
||||
{
|
||||
if(n && *n)
|
||||
{
|
||||
_fullname = FixPath(n);
|
||||
_name = PathToFileName(_fullname.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
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
|
|
@ -1,183 +0,0 @@
|
|||
// VFSFile.h - basic file interface + classes
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#ifndef VFSFILE_H
|
||||
#define VFSFILE_H
|
||||
|
||||
#include "VFSDefines.h"
|
||||
#include "VFSSelfRefCounter.h"
|
||||
#include <string>
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
|
||||
/** -- VFSFile basic interface --
|
||||
* All functions that return bool should return true on success and false on failure.
|
||||
* If an operation is not necessary or irrelevant (for example, files in memory can't be closed),
|
||||
* it is useful to return true anyways, because this operation did not fail, technically.
|
||||
* (Common sense here!)
|
||||
* An int/vfspos value of 0 indicates failure, except the size/seek/getpos functions, where npos means failure.
|
||||
* Only the functions required or applicable need to be implemented, for unsupported operations
|
||||
* the default implementation should be sufficient.
|
||||
**/
|
||||
class VFSFile
|
||||
{
|
||||
public:
|
||||
|
||||
/** The ctor is expected to set both name() and fullname(). */
|
||||
VFSFile();
|
||||
|
||||
virtual ~VFSFile() {};
|
||||
|
||||
/** Open a file. If fn is NULL (the default), open fullname().
|
||||
Mode can be "r", "w", "rb", "rb", and possibly other things that fopen supports.
|
||||
It is the subclass's choice to support other modes. Default is "rb". */
|
||||
virtual bool open(const char *fn = NULL, const char *mode = NULL) { return false; }
|
||||
virtual bool isopen(void) const { return false; }
|
||||
virtual bool iseof(void) const { return true; }
|
||||
|
||||
/** Returns the plain file name. Never NULL. */
|
||||
virtual const char *name(void) const { return ""; }
|
||||
|
||||
/** Returns the file name with full path. Never NULL. */
|
||||
virtual const char *fullname(void) const { return ""; }
|
||||
|
||||
virtual bool close(void) { return true; }
|
||||
virtual bool seek(vfspos pos) { return false; }
|
||||
|
||||
/** Seek relative to current position. Negative numbers will seek backwards.
|
||||
(In most cases, the default implementation does not have to be changed) */
|
||||
virtual bool seekRel(vfspos offs) { VFS_GUARD_OPT(this); return seek(getpos() + offs); }
|
||||
|
||||
virtual bool flush(void) { return true; }
|
||||
|
||||
/** Current offset in file. Return npos if NA. */
|
||||
virtual vfspos getpos(void) const { return npos; }
|
||||
|
||||
virtual unsigned int read(void *dst, unsigned int bytes) { return 0; }
|
||||
virtual unsigned int write(const void *src, unsigned int bytes) { return 0; }
|
||||
|
||||
/** Return file size. If NA, return npos. If size is not yet known,
|
||||
open() and close() may be called (with default args) to find out the size.
|
||||
The file is supposed to be in its old state when the function returns,
|
||||
that is in the same open state and seek position.
|
||||
The pointer returned by getBuf() must not change. */
|
||||
virtual vfspos size(void) { return npos; }
|
||||
|
||||
/** Attempt to increase file size. Returns new size after completion.
|
||||
May return any size. Failure is indicated by a size() that didn't change. */
|
||||
virtual vfspos size(vfspos newsize) { return size(); }
|
||||
|
||||
/** Return full file content in memory. Like size(), this may do other operations on the file,
|
||||
but after the function returns the file is expected to be in the same state it was before.
|
||||
If the file is not open before the call, it will be opened with default parameters (that is, "rb").
|
||||
Addition EOL mangling my happen if the file is opened in text mode before (= not binary).
|
||||
Calls to open() should delete this memory if the file was previously opened in a different mode.
|
||||
The returned memory is not guaranteed to be writable without problems, so don't do it.
|
||||
Don't cast the const away. You have been warned.
|
||||
This memory can be freed with free(), after calling dropBuf(false). */
|
||||
virtual const void *getBuf(void) { return NULL; }
|
||||
|
||||
/** If del is true, delete internal buffer. If false, unregister internal buffer from the file,
|
||||
but do not delete. Use free() later. */
|
||||
virtual void dropBuf(bool del) {}
|
||||
|
||||
/** Basic RTTI, for debugging purposes */
|
||||
virtual const char *getType(void) const { return "<BASE>"; }
|
||||
|
||||
|
||||
/** Reference count, if the pointer to this file is stored somewhere it is advisable to increase
|
||||
(ref++) it. If it reaches 0, this file is deleted automatically. */
|
||||
SelfRefCounter<VFSFile> ref;
|
||||
|
||||
|
||||
inline void lock() { _mtx.Lock(); }
|
||||
inline void unlock() { _mtx.Unlock(); }
|
||||
inline Mutex& mutex() const { return _mtx; }
|
||||
|
||||
protected:
|
||||
|
||||
mutable Mutex _mtx;
|
||||
};
|
||||
|
||||
class VFSFileReal : public VFSFile
|
||||
{
|
||||
public:
|
||||
VFSFileReal(const char *name = NULL);
|
||||
virtual ~VFSFileReal();
|
||||
virtual bool open(const char *fn = NULL, const char *mode = NULL);
|
||||
virtual bool isopen(void) const;
|
||||
virtual bool iseof(void) const;
|
||||
virtual const char *name(void) const;
|
||||
virtual const char *fullname(void) const;
|
||||
virtual bool close(void);
|
||||
virtual bool seek(vfspos pos);
|
||||
virtual bool seekRel(vfspos offs);
|
||||
virtual bool flush(void);
|
||||
virtual vfspos getpos(void) const;
|
||||
virtual unsigned int read(void *dst, unsigned int bytes);
|
||||
virtual unsigned int write(const void *src, unsigned int bytes);
|
||||
virtual vfspos size(void);
|
||||
virtual const void *getBuf(void);
|
||||
virtual void dropBuf(bool del);
|
||||
virtual const char *getType(void) const { return "disk"; }
|
||||
|
||||
inline void *getFP() { return _fh; }
|
||||
|
||||
protected:
|
||||
void _setName(const char *n);
|
||||
std::string _fullname;
|
||||
const char *_name;
|
||||
void *_fh; // FILE*
|
||||
vfspos _size;
|
||||
void *_buf;
|
||||
};
|
||||
|
||||
class VFSFileMem : public VFSFile
|
||||
{
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
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.
|
||||
};
|
||||
typedef void (*delete_func)(void*);
|
||||
|
||||
/* Creates a virtual file from a memory buffer. By default, the memory is copied.
|
||||
A deletor function can be passed optionally, if its NULL (the default),
|
||||
delete[] (char*)buf will be used. For malloc()'d memory, pass free. (Only used if mode is TAKE_OVER) */
|
||||
VFSFileMem(const char *name, void *buf, unsigned int size, Mode m = COPY, delete_func delfunc = NULL);
|
||||
virtual ~VFSFileMem();
|
||||
virtual bool open(const char *fn = NULL, const char *mode = NULL) { return true; }
|
||||
virtual bool isopen(void) const { return true; } // always open
|
||||
virtual bool iseof(void) const { VFS_GUARD_OPT(this); return _pos >= _size; }
|
||||
virtual const char *name(void) const { VFS_GUARD_OPT(this); return _name; }
|
||||
virtual const char *fullname(void) const { VFS_GUARD_OPT(this); return _fullname.c_str(); }
|
||||
virtual bool close(void) { return true; } // cant close, but not a problem
|
||||
virtual bool seek(vfspos pos) { VFS_GUARD_OPT(this); _pos = pos; return true; }
|
||||
virtual bool seekRel(vfspos offs) { VFS_GUARD_OPT(this); _pos += offs; return true; }
|
||||
virtual bool flush(void) { return false; } // can't flush, if a successful file write is expected, this IS a problem.
|
||||
virtual vfspos getpos(void) const { VFS_GUARD_OPT(this); return _pos; }
|
||||
virtual unsigned int read(void *dst, unsigned int bytes);
|
||||
virtual unsigned int write(const void *src, unsigned int bytes);
|
||||
virtual vfspos size(void) { VFS_GUARD_OPT(this); return _size; }
|
||||
virtual const void *getBuf(void) { VFS_GUARD_OPT(this); return _buf; }
|
||||
virtual void dropBuf(bool) {} // we can't simply drop the internal buffer, as the file is entirely memory based
|
||||
virtual const char *getSource(void) const { return "mem"; }
|
||||
|
||||
protected:
|
||||
void _setName(const char *n);
|
||||
std::string _fullname;
|
||||
const char *_name;
|
||||
vfspos _pos;
|
||||
vfspos _size;
|
||||
void *_buf;
|
||||
delete_func _delfunc;
|
||||
bool _mybuf;
|
||||
};
|
||||
|
||||
VFS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1,350 +0,0 @@
|
|||
// VFSHelper.cpp - glues it all together and makes use simple
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#include <iostream> // for debug only, see EOF
|
||||
|
||||
#include "VFSInternal.h"
|
||||
#include "VFSHelper.h"
|
||||
#include "VFSAtomic.h"
|
||||
#include "VFSTools.h"
|
||||
|
||||
#include "VFSDir.h"
|
||||
#include "VFSFile.h"
|
||||
#include "VFSLoader.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
# include <cassert>
|
||||
# define DEBUG_ASSERT(x) assert(x)
|
||||
#else
|
||||
# define DEBUG_ASSERT(x)
|
||||
#endif
|
||||
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
// predecl is in VFS.h
|
||||
bool _checkCompatInternal(bool large, bool nocase, unsigned int vfspos_size)
|
||||
{
|
||||
#ifdef VFS_LARGEFILE_SUPPORT
|
||||
bool largefile_i = true;
|
||||
#else
|
||||
bool largefile_i = false;
|
||||
#endif
|
||||
|
||||
#ifdef VFS_IGNORE_CASE
|
||||
bool nocase_i = true;
|
||||
#else
|
||||
bool nocase_i = false;
|
||||
#endif
|
||||
|
||||
return (large == largefile_i)
|
||||
&& (nocase == nocase_i)
|
||||
&& (sizeof(vfspos) == vfspos_size);
|
||||
}
|
||||
|
||||
VFSHelper::VFSHelper()
|
||||
: filesysRoot(NULL), merged(NULL)
|
||||
{
|
||||
_ldrDiskId = _AddFixedLoader(); // NULL intentionally. created by LoadFileSysRoot()
|
||||
}
|
||||
|
||||
VFSHelper::~VFSHelper()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void VFSHelper::Clear(void)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
_cleanup();
|
||||
|
||||
if(filesysRoot)
|
||||
{
|
||||
filesysRoot->ref--; // this should always delete it...
|
||||
filesysRoot = NULL; // ...but it may be referenced elsewhere, just in case
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < preRoot.size(); ++i)
|
||||
preRoot[i]->ref--;
|
||||
preRoot.clear();
|
||||
|
||||
for(unsigned int i = 0; i < postRoot.size(); ++i)
|
||||
postRoot[i]->ref--;
|
||||
postRoot.clear();
|
||||
|
||||
for(unsigned int i = 0; i < FixedLoadersCount(); ++i)
|
||||
if(fixedLdrs[i])
|
||||
{
|
||||
delete fixedLdrs[i];
|
||||
fixedLdrs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int VFSHelper::_AddFixedLoader(VFSLoader *ldr /* = NULL */)
|
||||
{
|
||||
fixedLdrs.push_back(ldr);
|
||||
return FixedLoadersCount() - 1;
|
||||
}
|
||||
|
||||
void VFSHelper::_cleanup(void)
|
||||
{
|
||||
VFS_GUARD_OPT(this); // be extra safe and ensure this is locked
|
||||
if(merged)
|
||||
{
|
||||
merged->ref--;
|
||||
merged = NULL;
|
||||
}
|
||||
for(VFSMountList::iterator it = vlist.begin(); it != vlist.end(); ++it)
|
||||
it->vdir->ref--;
|
||||
vlist.clear();
|
||||
for(LoaderList::iterator it = dynLdrs.begin(); it != dynLdrs.end(); ++it)
|
||||
delete *it;
|
||||
dynLdrs.clear();
|
||||
}
|
||||
|
||||
bool VFSHelper::LoadFileSysRoot(void)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
VFSDirReal *oldroot = filesysRoot;
|
||||
|
||||
filesysRoot = new VFSDirReal;
|
||||
if(!filesysRoot->load("."))
|
||||
{
|
||||
filesysRoot->ref--;
|
||||
filesysRoot = oldroot;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!fixedLdrs[_ldrDiskId])
|
||||
fixedLdrs[_ldrDiskId] = new VFSLoaderDisk;
|
||||
|
||||
if(oldroot)
|
||||
oldroot->ref--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VFSHelper::Prepare(bool clear /* = true */)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(clear)
|
||||
_cleanup();
|
||||
if(!merged)
|
||||
{
|
||||
merged = new VFSDir("");
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < preRoot.size(); ++i)
|
||||
merged->merge(preRoot[i]);
|
||||
if(filesysRoot)
|
||||
merged->merge(filesysRoot);
|
||||
for(size_t i = 0; i < postRoot.size(); ++i)
|
||||
merged->merge(postRoot[i]);
|
||||
}
|
||||
|
||||
void VFSHelper::Reload(bool fromDisk /* = false */)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(fromDisk)
|
||||
LoadFileSysRoot();
|
||||
Prepare(false);
|
||||
for(VFSMountList::iterator it = vlist.begin(); it != vlist.end(); it++)
|
||||
GetDir(it->mountPoint.c_str(), true)->merge(it->vdir, it->overwrite);
|
||||
}
|
||||
|
||||
bool VFSHelper::Mount(const char *src, const char *dest, bool overwrite /* = true*/)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
return AddVFSDir(GetDir(src, false), dest, overwrite);
|
||||
}
|
||||
|
||||
bool VFSHelper::AddVFSDir(VFSDir *dir, const char *subdir /* = NULL */, bool overwrite /* = true */)
|
||||
{
|
||||
if(!dir)
|
||||
return false;
|
||||
VFS_GUARD_OPT(this);
|
||||
if(!subdir)
|
||||
subdir = dir->fullname();
|
||||
VFSDir *sd = GetDir(subdir, true);
|
||||
if(!sd) // may be NULL if Prepare() was not called before
|
||||
return false;
|
||||
dir->ref++; // because this is to be added to vlist
|
||||
VDirEntry ve(dir, subdir, overwrite);
|
||||
_StoreMountPoint(ve);
|
||||
sd->merge(dir, overwrite); // merge into specified subdir. will be (virtually) created if not existing
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VFSHelper::Unmount(const char *src, const char *dest)
|
||||
{
|
||||
VFSDir *vd = GetDir(src, false);
|
||||
if(!vd)
|
||||
return false;
|
||||
|
||||
VDirEntry ve(vd, dest, true); // last is dummy
|
||||
if(!_RemoveMountPoint(ve))
|
||||
return false;
|
||||
|
||||
Reload(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VFSHelper::_StoreMountPoint(const VDirEntry& ve)
|
||||
{
|
||||
// scan through and ensure only one mount point with the same data is present.
|
||||
// if present, remove and re-add, this ensures the mount point is at the end of the list
|
||||
for(VFSMountList::iterator it = vlist.begin(); it != vlist.end(); )
|
||||
{
|
||||
const VDirEntry& oe = *it;
|
||||
if(ve.mountPoint == oe.mountPoint && ve.vdir == oe.vdir
|
||||
&& (ve.overwrite || !oe.overwrite) ) // overwrite definitely, or if other does not overwrite
|
||||
{
|
||||
it = vlist.erase(it); // do not break; just in case there are more (fixme?)
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
vlist.push_back(ve);
|
||||
}
|
||||
|
||||
bool VFSHelper::_RemoveMountPoint(const VDirEntry& ve)
|
||||
{
|
||||
for(VFSMountList::iterator it = vlist.begin(); it != vlist.end(); ++it)
|
||||
{
|
||||
const VDirEntry& oe = *it;
|
||||
if(ve.mountPoint == oe.mountPoint && ve.vdir == oe.vdir)
|
||||
{
|
||||
vlist.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VFSHelper::MountExternalPath(const char *path, const char *where /* = "" */)
|
||||
{
|
||||
// no guard required here, AddVFSDir has one, and the reference count is locked as well.
|
||||
VFSDirReal *vfs = new VFSDirReal;
|
||||
if(vfs->load(path))
|
||||
AddVFSDir(vfs, where);
|
||||
return !!--(vfs->ref); // 0 if deleted
|
||||
}
|
||||
|
||||
void VFSHelper::AddLoader(VFSLoader *ldr)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
dynLdrs.push_back(ldr);
|
||||
}
|
||||
|
||||
inline static VFSFile *VFSHelper_GetFileByLoader(VFSLoader *ldr, const char *fn, VFSDir *root)
|
||||
{
|
||||
if(!ldr)
|
||||
return NULL;
|
||||
VFSFile *vf = ldr->Load(fn);
|
||||
if(vf)
|
||||
{
|
||||
root->addRecursive(vf, true);
|
||||
--(vf->ref);
|
||||
}
|
||||
return vf;
|
||||
}
|
||||
|
||||
VFSFile *VFSHelper::GetFile(const char *fn)
|
||||
{
|
||||
while(fn[0] == '.' && fn[1] == '/')
|
||||
fn += 2;
|
||||
|
||||
VFSFile *vf = NULL;
|
||||
|
||||
// guarded block
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
if(!merged) // Prepare() called?
|
||||
return NULL;
|
||||
|
||||
vf = merged->getFile(fn);
|
||||
}
|
||||
|
||||
// nothing found? maybe a loader has something.
|
||||
// if so, add the newly created VFSFile to the tree.
|
||||
// constant, no locking required here - also a bad idea in case a loader does heavy I/O
|
||||
if(!vf)
|
||||
for(unsigned int i = 0; i < fixedLdrs.size(); ++i)
|
||||
if((vf = VFSHelper_GetFileByLoader(fixedLdrs[i], fn, GetDirRoot())))
|
||||
break;
|
||||
|
||||
if(!vf)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
for(LoaderList::iterator it = dynLdrs.begin(); it != dynLdrs.end(); ++it)
|
||||
if((vf = VFSHelper_GetFileByLoader(*it, fn, GetDirRoot())))
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("VFS: GetFile '%s' -> '%s' (%p)\n", fn, vf ? vf->fullname() : "NULL", vf);
|
||||
|
||||
return vf;
|
||||
}
|
||||
|
||||
VFSDir *VFSHelper::GetDir(const char* dn, bool create /* = false */)
|
||||
{
|
||||
while(dn[0] == '.' && dn[1] == '/')
|
||||
dn += 2;
|
||||
|
||||
VFS_GUARD_OPT(this);
|
||||
return (merged && *dn) ? merged->getDir(dn, create) : merged;
|
||||
}
|
||||
|
||||
VFSDir *VFSHelper::GetDirRoot(void)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
return merged;
|
||||
}
|
||||
|
||||
|
||||
// DEBUG STUFF
|
||||
|
||||
static void _DumpTreeRecursive(std::ostream& os, VFSDir *vd, const std::string& sp, VFSDir *parent)
|
||||
{
|
||||
std::string sub = sp + " ";
|
||||
|
||||
os << sp << "d|" << vd->name() << " [" << vd->getType() << ", ref " << vd->ref.count() << ", 0x" << vd << "]";
|
||||
|
||||
if(parent && strncmp(parent->fullname(), vd->fullname(), strlen(parent->fullname())))
|
||||
os << " <-- {" << vd->fullname() << "} ***********";
|
||||
os << std::endl;
|
||||
|
||||
for(DirIter it = vd->_subdirs.begin(); it != vd->_subdirs.end(); ++it)
|
||||
_DumpTreeRecursive(os, it->second, sub, vd);
|
||||
|
||||
for(FileIter it = vd->_files.begin(); it != vd->_files.end(); ++it)
|
||||
{
|
||||
VFSFile *vf = it->second;
|
||||
// only if refcount and/or mount point differs
|
||||
bool p = false;
|
||||
if(vf->ref.count() != vd->ref.count())
|
||||
{
|
||||
doprint:
|
||||
os << sub << "f|" << vf->name() << " [" << vf->getType() << ", ref " << vf->ref.count() << ", 0x" << vf << "]";
|
||||
p = true;
|
||||
}
|
||||
if(strncmp(vd->fullname(), vf->fullname(), strlen(vd->fullname())))
|
||||
{
|
||||
if(!p)
|
||||
goto doprint;
|
||||
os << " <-- {" << vf->fullname() << "} ***********";
|
||||
}
|
||||
if(p)
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void VFSHelper::debugDumpTree(std::ostream& os, VFSDir *start /* = NULL */)
|
||||
{
|
||||
_DumpTreeRecursive(os, start ? start : GetDirRoot(), "", NULL);
|
||||
}
|
||||
|
||||
|
||||
VFS_NAMESPACE_END
|
|
@ -1,192 +0,0 @@
|
|||
// VFSHelper.h - glues it all together and makes use simple
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#ifndef VFSHELPER_H
|
||||
#define VFSHELPER_H
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
|
||||
#include "VFSAtomic.h"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
class VFSDir;
|
||||
class VFSDirReal;
|
||||
class VFSFile;
|
||||
class VFSLoader;
|
||||
|
||||
|
||||
/** VFSHelper - extensible class to simplify working with the VFS tree
|
||||
* Contains a set of useful functions that should be useful for anyone.
|
||||
* This class may be overridden to support adding any source in a comfortable way.
|
||||
*
|
||||
* Note: This class uses VFS_LAST_HELPER_CLASS, which should always store the last
|
||||
* class derived from VFSHelper. This is supposed to make it easy to make extensions like this:
|
||||
|
||||
#include "VFSHelperExtra.h" // defines a VFSHelperExtra class that is somehow derived from VFSHelper
|
||||
// and follows the same rules as explained below.
|
||||
|
||||
class VFSHelperArchive : public VFS_LAST_HELPER_CLASS
|
||||
{
|
||||
private:
|
||||
typedef VFS_LAST_HELPER_CLASS super;
|
||||
public:
|
||||
// .... class members ....
|
||||
};
|
||||
|
||||
#undef VFS_LAST_HELPER_CLASS
|
||||
#define VFS_LAST_HELPER_CLASS VFSHelperArchive
|
||||
|
||||
|
||||
* Used this way, only the order in which VFSHelper extension classes are included matters.
|
||||
* No code changes are required to get a nice inheritance and priority chain working.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef VFS_LAST_HELPER_CLASS
|
||||
# error VFS_LAST_HELPER_CLASS defined before VFSHelper class decl, check your include order!
|
||||
#endif
|
||||
|
||||
class VFSHelper
|
||||
{
|
||||
public:
|
||||
VFSHelper();
|
||||
virtual ~VFSHelper();
|
||||
|
||||
/** Creates the working tree. Required before any files or directories can be accessed.
|
||||
Internally, it merges all individual VFS trees into one. If clear is true (default),
|
||||
an existing merged tree is dropped, and old and previously added files and loaders removed.
|
||||
(This is the recommended setting.) */
|
||||
virtual void Prepare(bool clear = true);
|
||||
|
||||
/** Re-merges any files in the tree, and optionally reloads files on disk.
|
||||
This is useful if files on disk were created or removed, and the tree needs to reflect these changes. */
|
||||
virtual void Reload(bool fromDisk = false);
|
||||
|
||||
/** Reset an instance to its initial state */
|
||||
virtual void Clear(void);
|
||||
|
||||
/** Load all files from working directory (into an internal tree) */
|
||||
bool LoadFileSysRoot(void);
|
||||
|
||||
/** Mount a directory in the tree to a different location. Requires a previous call to Prepare().
|
||||
This can be imagined like a symlink pointing to a different location.
|
||||
Be careful not to create circles, this might technically work,
|
||||
but confuses the reference counting, causing memory leaks. */
|
||||
bool Mount(const char *src, const char *dest, bool overwrite = true);
|
||||
|
||||
/** Drops a directory from the tree. Internally, this calls Reload(false),
|
||||
which is a heavy operation compared to Mount(). Be warned. */
|
||||
bool Unmount(const char *src, const char *dest);
|
||||
|
||||
/** Merges a path into the tree. Requires a previous call to Prepare().
|
||||
By default the directory is added into the root directory of the merged tree.
|
||||
Pass NULL to add the directory to its original location,
|
||||
or any other path to add it to that explicit location.
|
||||
It is advised not to use this to re-add parts already in the tree; use Mount() instead.
|
||||
Rule of thumb: If you called LoadFileSysRoot(), do not use this for subdirs. */
|
||||
bool MountExternalPath(const char *path, const char *where = "");
|
||||
|
||||
/** Adds a VFSDir object into the merged tree. If subdir is NULL (the default),
|
||||
add into the subdir stored in the VFSDir object. The tree will be extended if target dir does not exist.
|
||||
If overwrite is true (the default), files in the tree will be replaced if already existing.
|
||||
Requires a previous call to Prepare().
|
||||
Like with Mount(); be careful not to create cycles. */
|
||||
bool AddVFSDir(VFSDir *dir, const char *subdir = NULL, bool overwrite = true);
|
||||
|
||||
/** Add a loader that can look for files on demand.
|
||||
It will be deleted if Prepare(true) is called.
|
||||
It is possible (but not a good idea) to add a loader multiple times. */
|
||||
inline void AddLoader(VFSLoader *ldr);
|
||||
|
||||
/** Get a file from the merged tree. Requires a previous call to Prepare().
|
||||
Asks loaders if the file is not in the tree. If found by a loader, the file will be added to the tree.
|
||||
The returned pointer is reference counted. In case the file pointer is stored elsewhere,
|
||||
do ptr->ref++, and later ptr->ref--. This is to prevent the VFS tree from deleting the file when cleaning up.
|
||||
Not necessary if the pointer is just retrieved and used, or temp. stored while the VFS tree is not modified. */
|
||||
VFSFile *GetFile(const char *fn);
|
||||
|
||||
/** Get a directory from the merged tree. If create is true and the directory does not exist,
|
||||
build the tree structure and return the newly created dir. NULL otherwise.
|
||||
Requires a previous call to Prepare().
|
||||
Reference counted, same as GetFile(), look there for more info. */
|
||||
VFSDir *GetDir(const char* dn, bool create = false);
|
||||
|
||||
/** Returns the tree root, which is usually the working directory. */
|
||||
VFSDir *GetDirRoot(void);
|
||||
|
||||
/** Remove a file or directory from the tree */
|
||||
//bool Remove(VFSFile *vf);
|
||||
//bool Remove(VFSDir *dir);
|
||||
//bool Remove(const char *name); // TODO: CODE ME
|
||||
|
||||
/** This depends on the class type and stays constant. */
|
||||
inline unsigned int FixedLoadersCount(void) const { return (unsigned int)fixedLdrs.size(); }
|
||||
|
||||
inline void lock() { _mtx.Lock(); }
|
||||
inline void unlock() { _mtx.Unlock(); }
|
||||
inline Mutex& mutex() const { return _mtx; }
|
||||
|
||||
// DEBUG STUFF
|
||||
void debugDumpTree(std::ostream& os, VFSDir *start = NULL);
|
||||
|
||||
protected:
|
||||
|
||||
/** Drops the merged tree and additional mount points and dynamic loaders.
|
||||
Overload to do additional cleanup if required. Invoked by Clear() and Prepare(true). */
|
||||
virtual void _cleanup(void);
|
||||
|
||||
/** Add a fixed VFSLoader. Returns its array index in fixedLdrs. */
|
||||
unsigned int _AddFixedLoader(VFSLoader *ldr = NULL);
|
||||
|
||||
struct VDirEntry
|
||||
{
|
||||
VDirEntry() : vdir(NULL), overwrite(false) {}
|
||||
VDirEntry(VFSDir *v, std::string mp, bool ow) : vdir(v), mountPoint(mp), overwrite(ow) {}
|
||||
VFSDir *vdir;
|
||||
std::string mountPoint;
|
||||
bool overwrite;
|
||||
};
|
||||
|
||||
typedef std::list<VDirEntry> VFSMountList;
|
||||
typedef std::vector<VFSLoader*> LoaderArray;
|
||||
typedef std::deque<VFSLoader*> LoaderList;
|
||||
typedef std::vector<VFSDir*> DirArray;
|
||||
|
||||
|
||||
void _StoreMountPoint(const VDirEntry& ve);
|
||||
|
||||
bool _RemoveMountPoint(const VDirEntry& ve);
|
||||
|
||||
// the VFSDirs are merged in their declaration order.
|
||||
// when merging, files already contained can be overwritten by files merged in later.
|
||||
VFSDirReal *filesysRoot; // local files on disk (root dir)
|
||||
|
||||
// Additional tree stores, to be filled by subclasses if needed.
|
||||
DirArray preRoot; // VFSDirs in here will be merged in, before the actual disk files.
|
||||
// Means files on disk will overwrite existing entries.
|
||||
DirArray postRoot; // Will be merged after the disk files, and overwrite prev. merged files.
|
||||
// Both may contain NULLs.
|
||||
|
||||
// if files are not in the tree, maybe one of these is able to find it. May contain NULLs.
|
||||
LoaderArray fixedLdrs; // defined by class type, stays constant during object lifetime
|
||||
LoaderList dynLdrs; // dynamically added on demand, deleted on _cleanup()
|
||||
|
||||
VFSDir *merged; // contains the merged virtual/actual file system tree
|
||||
|
||||
mutable Mutex _mtx;
|
||||
|
||||
private:
|
||||
unsigned int _ldrDiskId;
|
||||
VFSMountList vlist; // all other dirs added later, together with path to mount to
|
||||
};
|
||||
|
||||
#undef VFS_LAST_HELPER_CLASS
|
||||
#define VFS_LAST_HELPER_CLASS VFSHelper
|
||||
|
||||
VFS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1,43 +0,0 @@
|
|||
// VFSInternal.h - misc things that are not required to be visible outside of the library.
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
// !! this file is supposed to be included ONLY from VFS*.cpp files.
|
||||
|
||||
#ifndef VFS_INTERNAL_H
|
||||
#define VFS_INTERNAL_H
|
||||
|
||||
// checks to enforcecorrect including
|
||||
#ifdef TTVFS_VFS_H
|
||||
#error Oops, TTVFS_VFS_H is defined, someone messed up and included VFS.h wrongly.
|
||||
#endif
|
||||
|
||||
#include "VFSDefines.h"
|
||||
|
||||
#if _MSC_VER
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_DEPRECATE
|
||||
# pragma warning(disable: 4355) // 'this' : used in base member initializer list
|
||||
#endif
|
||||
|
||||
// this is for POSIX - define before including any stdio headers
|
||||
#ifdef VFS_LARGEFILE_SUPPORT
|
||||
# ifndef _MSC_VER
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
// this is for MSVC - re-define functions
|
||||
#ifdef VFS_LARGEFILE_SUPPORT
|
||||
# ifdef _MSC_VER
|
||||
# define fseek _fseeki64
|
||||
# define ftell _ftelli64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,102 +0,0 @@
|
|||
// VFSLoader.cpp - late loading of files not in the tree
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#include "VFSInternal.h"
|
||||
#include "VFSTools.h"
|
||||
#include "VFSFile.h"
|
||||
#include "VFSLoader.h"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
#if !defined(_WIN32) && defined(VFS_IGNORE_CASE)
|
||||
|
||||
#include <sys/dir.h>
|
||||
|
||||
// based on code in PhysicsFS: http://icculus.org/physfs/
|
||||
static bool locateOneElement(char *buf)
|
||||
{
|
||||
char *ptr;
|
||||
DIR *dirp;
|
||||
|
||||
ptr = strrchr(buf, '/'); // find entry at end of path.
|
||||
if (ptr == NULL)
|
||||
{
|
||||
dirp = opendir(".");
|
||||
ptr = buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr = '\0';
|
||||
dirp = opendir(buf);
|
||||
*ptr = '/';
|
||||
ptr++; // point past dirsep to entry itself.
|
||||
}
|
||||
|
||||
struct dirent *dent;
|
||||
while ((dent = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (strcasecmp(dent->d_name, ptr) == 0)
|
||||
{
|
||||
strcpy(ptr, dent->d_name); // found a match. Overwrite with this case.
|
||||
closedir(dirp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// no match at all...
|
||||
closedir(dirp);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool findFileHarder(char *fn)
|
||||
{
|
||||
char *ptr = fn;
|
||||
bool found = true;
|
||||
while ((ptr = strchr(ptr + 1, '/')) != 0)
|
||||
{
|
||||
*ptr = '\0';
|
||||
found = locateOneElement(fn);
|
||||
*ptr = '/'; // restore path separator
|
||||
if (!found)
|
||||
return false;
|
||||
}
|
||||
|
||||
// check final element...
|
||||
found = found && locateOneElement(fn);
|
||||
|
||||
printf("tt: Fixed case '%s' [%s]\n", fn, found ? "found" : "NOT FOUND"); // TEMP
|
||||
return found;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
VFSFile *VFSLoaderDisk::Load(const char *fn)
|
||||
{
|
||||
if(FileExists(fn))
|
||||
return new VFSFileReal(fn); // must contain full file name
|
||||
|
||||
#if !defined(_WIN32) && defined(VFS_IGNORE_CASE)
|
||||
size_t s = strlen(fn);
|
||||
if(s < 511) // avoid using malloc() and alloca() for short strings
|
||||
{
|
||||
char t[512];
|
||||
memcpy(&t[0], fn, s+1); // copy terminating '\0' as well
|
||||
if(findFileHarder(&t[0])) // fixes the filename on the way
|
||||
return new VFSFileReal(&t[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *t = (char*)malloc(s+1);
|
||||
VFSFileReal *vf = NULL;
|
||||
memcpy(t, fn, s+1);
|
||||
if(findFileHarder(&t[0]))
|
||||
vf = new VFSFileReal(&t[0]);
|
||||
free(t);
|
||||
return vf;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VFS_NAMESPACE_END
|
|
@ -1,31 +0,0 @@
|
|||
// VFSLoader.h - late loading of files not in the tree
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#ifndef VFSLOADER_H
|
||||
#define VFSLOADER_H
|
||||
|
||||
#include "VFSDefines.h"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
class VFSFile;
|
||||
|
||||
// VFSLoader - to be called if a file is not in the tree.
|
||||
class VFSLoader
|
||||
{
|
||||
public:
|
||||
virtual ~VFSLoader() {}
|
||||
virtual VFSFile *Load(const char *fn) = 0;
|
||||
};
|
||||
|
||||
class VFSLoaderDisk : public VFSLoader
|
||||
{
|
||||
public:
|
||||
virtual ~VFSLoaderDisk() {}
|
||||
virtual VFSFile *Load(const char *fn);
|
||||
};
|
||||
|
||||
VFS_NAMESPACE_END
|
||||
|
||||
|
||||
#endif
|
|
@ -1,44 +0,0 @@
|
|||
#ifndef SELFREFCOUNTER_H
|
||||
#define SELFREFCOUNTER_H
|
||||
|
||||
#include "VFSDefines.h"
|
||||
#include "VFSAtomic.h"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
// self must point to the object that holds the counter.
|
||||
template <class T, bool DELSELF = true> class SelfRefCounter
|
||||
{
|
||||
private:
|
||||
T *self;
|
||||
volatile int c;
|
||||
SelfRefCounter(SelfRefCounter& r); // forbid copy constructor
|
||||
inline unsigned int _deref(void)
|
||||
{
|
||||
unsigned int cc = (unsigned int)Atomic_Decr(c); // copy c, in case we get deleted
|
||||
if(DELSELF && !cc)
|
||||
{
|
||||
delete self;
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
public:
|
||||
SelfRefCounter(T *p): self(p), c(1) {}
|
||||
~SelfRefCounter() { /* DEBUG(ASSERT(c <= 1)); */ } // its ok if the last reference calls delete instead of _deref()
|
||||
inline unsigned int count(void) { return c; }
|
||||
|
||||
// post-increment (dummy int)
|
||||
inline unsigned int operator++(int) { unsigned int cc = c; Atomic_Incr(c); return cc; }
|
||||
inline unsigned int operator--(int) { unsigned int cc = c; _deref(); return cc; }
|
||||
|
||||
// pre-increment
|
||||
inline unsigned int operator++(void) { return (unsigned int)Atomic_Incr(c); }
|
||||
inline unsigned int operator--(void) { return _deref(); }
|
||||
};
|
||||
|
||||
VFS_NAMESPACE_END
|
||||
|
||||
|
||||
#endif
|
|
@ -1,427 +0,0 @@
|
|||
// VFSTools.cpp - useful functions and misc stuff
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#include "VFSInternal.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <stack>
|
||||
#include "VFSTools.h"
|
||||
|
||||
|
||||
#if _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <sys/dir.h>
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
std::string stringToLower(std::string s)
|
||||
{
|
||||
std::transform(s.begin(), s.end(), s.begin(), tolower);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string stringToUpper(std::string s)
|
||||
{
|
||||
std::transform(s.begin(), s.end(), s.begin(), toupper);
|
||||
return s;
|
||||
}
|
||||
|
||||
void makeLowercase(std::string& s)
|
||||
{
|
||||
std::transform(s.begin(), s.end(), s.begin(), tolower);
|
||||
}
|
||||
|
||||
void makeUppercase(std::string& s)
|
||||
{
|
||||
std::transform(s.begin(), s.end(), s.begin(), toupper);
|
||||
}
|
||||
|
||||
// returns list of *plain* file names in given directory,
|
||||
// without paths, and without anything else
|
||||
void GetFileList(const char *path, StringList& files)
|
||||
{
|
||||
#if !_WIN32
|
||||
DIR * dirp;
|
||||
struct dirent * dp;
|
||||
dirp = opendir(path);
|
||||
if(dirp)
|
||||
{
|
||||
while((dp=readdir(dirp)) != NULL)
|
||||
{
|
||||
if (dp->d_type != DT_DIR) // only add if it is not a directory
|
||||
{
|
||||
std::string s(dp->d_name);
|
||||
files.push_back(s);
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
WIN32_FIND_DATA fil;
|
||||
std::string search(path);
|
||||
MakeSlashTerminated(search);
|
||||
search += "*";
|
||||
HANDLE hFil = FindFirstFile(search.c_str(),&fil);
|
||||
if(hFil != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
if(!(fil.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
std::string s(fil.cFileName);
|
||||
files.push_back(s);
|
||||
}
|
||||
}
|
||||
while(FindNextFile(hFil, &fil));
|
||||
|
||||
FindClose(hFil);
|
||||
}
|
||||
|
||||
# endif
|
||||
}
|
||||
|
||||
// returns a list of directory names in the given directory, *without* the source dir.
|
||||
// if getting the dir list recursively, all paths are added, except *again* the top source dir beeing queried.
|
||||
void GetDirList(const char *path, StringList &dirs, bool recursive /* = false */)
|
||||
{
|
||||
#if !_WIN32
|
||||
DIR * dirp;
|
||||
struct dirent * dp;
|
||||
dirp = opendir(path);
|
||||
if(dirp)
|
||||
{
|
||||
while((dp = readdir(dirp))) // assignment is intentional
|
||||
{
|
||||
if (dp->d_type == DT_DIR) // only add if it is a directory
|
||||
{
|
||||
if(strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
|
||||
{
|
||||
dirs.push_back(dp->d_name);
|
||||
if (recursive) // needing a better way to do that
|
||||
{
|
||||
std::deque<std::string> newdirs;
|
||||
GetDirList(dp->d_name, newdirs, true);
|
||||
std::string d(dp->d_name);
|
||||
for(std::deque<std::string>::iterator it = newdirs.begin(); it != newdirs.end(); ++it)
|
||||
dirs.push_back(d + *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
std::string search(path);
|
||||
MakeSlashTerminated(search);
|
||||
search += "*";
|
||||
WIN32_FIND_DATA fil;
|
||||
HANDLE hFil = FindFirstFile(search.c_str(),&fil);
|
||||
if(hFil != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
if( fil.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
|
||||
{
|
||||
if (!strcmp(fil.cFileName, ".") || !strcmp(fil.cFileName, ".."))
|
||||
continue;
|
||||
|
||||
std::string d(fil.cFileName);
|
||||
dirs.push_back(d);
|
||||
|
||||
if (recursive) // need a better way to do that
|
||||
{
|
||||
StringList newdirs;
|
||||
GetDirList(d.c_str(), newdirs, true);
|
||||
|
||||
for(std::deque<std::string>::iterator it = newdirs.begin(); it != newdirs.end(); ++it)
|
||||
dirs.push_back(d + *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
while(FindNextFile(hFil, &fil));
|
||||
|
||||
FindClose(hFil);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FileExists(const char *fn)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(fp)
|
||||
{
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return access(fn, F_OK) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// must return true if creating the directory was successful, or already exists
|
||||
bool CreateDir(const char *dir)
|
||||
{
|
||||
if(IsDirectory(dir)) // do not try to create if it already exists
|
||||
return true;
|
||||
bool result;
|
||||
# if _WIN32
|
||||
result = !!::CreateDirectory(dir, NULL);
|
||||
# else
|
||||
result = !mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CreateDirRec(const char *dir)
|
||||
{
|
||||
if(IsDirectory(dir))
|
||||
return true;
|
||||
bool result = true;
|
||||
StringList li;
|
||||
StrSplit(dir, "/\\", li, false);
|
||||
std::string d;
|
||||
d.reserve(strlen(dir));
|
||||
bool last;
|
||||
for(StringList::iterator it = li.begin(); it != li.end(); it++)
|
||||
{
|
||||
d += *it;
|
||||
last = CreateDir(d.c_str());
|
||||
result = last && result;
|
||||
d += '/';
|
||||
}
|
||||
return result || last;
|
||||
}
|
||||
|
||||
vfspos GetFileSize(const char* fn)
|
||||
{
|
||||
if(!fn || !*fn)
|
||||
return 0;
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp)
|
||||
return 0;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
vfspos s = (vfspos)ftell(fp);
|
||||
fclose(fp);
|
||||
|
||||
return s == npos ? 0 : s;
|
||||
}
|
||||
|
||||
std::string FixSlashes(const std::string& s)
|
||||
{
|
||||
std::string r;
|
||||
r.reserve(s.length() + 1);
|
||||
char last = 0, cur;
|
||||
for(size_t i = 0; i < s.length(); ++i)
|
||||
{
|
||||
cur = s[i];
|
||||
if(cur == '\\')
|
||||
cur = '/';
|
||||
if(last == '/' && cur == '/')
|
||||
continue;
|
||||
r += cur;
|
||||
last = cur;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string FixPath(const std::string& s)
|
||||
{
|
||||
const char *p = s.c_str();
|
||||
while(p[0] == '.' && p[1] == '/')
|
||||
p += 2;
|
||||
return FixSlashes(p == s.c_str() ? s : p); // avoid hidden re-allocation when pointer was not moved
|
||||
}
|
||||
|
||||
bool IsDirectory(const char *s)
|
||||
{
|
||||
#if _WIN32
|
||||
DWORD dwFileAttr = GetFileAttributes(s);
|
||||
if(dwFileAttr == INVALID_FILE_ATTRIBUTES)
|
||||
return false;
|
||||
return !!(dwFileAttr & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
if ( access( s, 0 ) == 0 )
|
||||
{
|
||||
struct stat status;
|
||||
stat( s, &status );
|
||||
return status.st_mode & S_IFDIR;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MakeSlashTerminated(std::string& s)
|
||||
{
|
||||
if(s.length() && s[s.length() - 1] != '/')
|
||||
s += '/';
|
||||
}
|
||||
|
||||
// extracts the file name from a given path
|
||||
const char *PathToFileName(const char *str)
|
||||
{
|
||||
const char *p = strrchr(str, '/');
|
||||
return p ? p+1 : str;
|
||||
}
|
||||
|
||||
std::string StripFileExtension(const std::string& s)
|
||||
{
|
||||
size_t pos = s.find_last_of('.');
|
||||
size_t pos2 = s.find_last_of('/');
|
||||
if(pos != std::string::npos && (pos2 < pos || pos2 == std::string::npos))
|
||||
return s.substr(0, pos);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string StripLastPath(const std::string& s)
|
||||
{
|
||||
if(s[s.length() - 1] == '/')
|
||||
return StripLastPath(s.substr(0, s.length() - 1));
|
||||
|
||||
size_t pos = s.find_last_of('/');
|
||||
if(pos == std::string::npos)
|
||||
return ""; // nothing remains
|
||||
|
||||
return s.substr(0, pos);
|
||||
}
|
||||
|
||||
void GetFileListRecursive(std::string dir, StringList& files, bool withQueriedDir /* = false */)
|
||||
{
|
||||
std::stack<std::string> stk;
|
||||
|
||||
if(withQueriedDir)
|
||||
{
|
||||
stk.push(dir);
|
||||
while(stk.size())
|
||||
{
|
||||
dir = stk.top();
|
||||
stk.pop();
|
||||
MakeSlashTerminated(dir);
|
||||
|
||||
StringList li;
|
||||
GetFileList(dir.c_str(), li);
|
||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); ++it)
|
||||
files.push_back(dir + *it);
|
||||
|
||||
li.clear();
|
||||
GetDirList(dir.c_str(), li, true);
|
||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); ++it)
|
||||
stk.push(dir + *it);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string topdir = dir;
|
||||
MakeSlashTerminated(topdir);
|
||||
stk.push("");
|
||||
while(stk.size())
|
||||
{
|
||||
dir = stk.top();
|
||||
stk.pop();
|
||||
MakeSlashTerminated(dir);
|
||||
|
||||
StringList li;
|
||||
dir = topdir + dir;
|
||||
GetFileList(dir.c_str(), li);
|
||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); ++it)
|
||||
files.push_back(dir + *it);
|
||||
|
||||
li.clear();
|
||||
GetDirList(dir.c_str(), li, true);
|
||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); ++it)
|
||||
stk.push(dir + *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from http://board.byuu.org/viewtopic.php?f=10&t=1089&start=15
|
||||
bool WildcardMatch(const char *str, const char *pattern)
|
||||
{
|
||||
const char *cp = 0, *mp = 0;
|
||||
while(*str && *pattern != '*')
|
||||
{
|
||||
if(*pattern != *str && *pattern != '?')
|
||||
return false;
|
||||
pattern++, str++;
|
||||
}
|
||||
|
||||
while(*str)
|
||||
{
|
||||
if(*pattern == '*')
|
||||
{
|
||||
if(!*++pattern)
|
||||
return 1;
|
||||
mp = pattern;
|
||||
cp = str + 1;
|
||||
}
|
||||
else if(*pattern == *str || *pattern == '?')
|
||||
{
|
||||
++pattern;
|
||||
++str;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = mp;
|
||||
str = cp++;
|
||||
}
|
||||
}
|
||||
|
||||
while(*pattern++ == '*');
|
||||
|
||||
return !*pattern;
|
||||
}
|
||||
|
||||
// copy strings, mangling newlines to system standard
|
||||
// windows has 13+10
|
||||
// *nix has 10
|
||||
// exotic systems may have 10+13
|
||||
size_t strnNLcpy(char *dst, const char *src, unsigned int n /* = -1 */)
|
||||
{
|
||||
char *olddst = dst;
|
||||
bool had10 = false, had13 = false;
|
||||
|
||||
--n; // reserve 1 for \0 at end
|
||||
|
||||
while(*src && n)
|
||||
{
|
||||
if((had13 && *src == 10) || (had10 && *src == 13))
|
||||
{
|
||||
++src; // last was already mangled
|
||||
had13 = had10 = false; // processed one CRLF pair
|
||||
continue;
|
||||
}
|
||||
had10 = *src == 10;
|
||||
had13 = *src == 13;
|
||||
|
||||
if(had10 || had13)
|
||||
{
|
||||
*dst++ = '\n';
|
||||
++src;
|
||||
}
|
||||
else
|
||||
*dst++ = *src++;
|
||||
|
||||
--n;
|
||||
}
|
||||
|
||||
*dst++ = 0;
|
||||
|
||||
return dst - olddst;
|
||||
}
|
||||
|
||||
VFS_NAMESPACE_END
|
|
@ -1,59 +0,0 @@
|
|||
// VFSTools.h - useful functions and misc stuff
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#ifndef VFS_TOOLS_H
|
||||
#define VFS_TOOLS_H
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
#include "VFSDefines.h"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
typedef std::deque<std::string> StringList;
|
||||
|
||||
std::string stringToUpper(const std::string& s);
|
||||
std::string stringToLower(const std::string& s);
|
||||
void makeUppercase(std::string& s);
|
||||
void makeLowercase(std::string& s);
|
||||
void GetFileList(const char *, StringList& files);
|
||||
void GetDirList(const char *, StringList& dirs, bool recursive = false);
|
||||
bool FileExists(const char *);
|
||||
bool IsDirectory(const char *);
|
||||
bool CreateDir(const char*);
|
||||
bool CreateDirRec(const char*);
|
||||
vfspos GetFileSize(const char*);
|
||||
std::string FixSlashes(const std::string& s);
|
||||
std::string FixPath(const std::string& s);
|
||||
const char *PathToFileName(const char *str);
|
||||
void MakeSlashTerminated(std::string& s);
|
||||
std::string StripFileExtension(const std::string& s);
|
||||
std::string StripLastPath(const std::string& s);
|
||||
void GetFileListRecursive(std::string dir, StringList& files, bool withQueriedDir = false);
|
||||
bool WildcardMatch(const char *str, const char *pattern);
|
||||
size_t strnNLcpy(char *dst, const char *src, unsigned int n = -1);
|
||||
|
||||
template <class T> void StrSplit(const std::string &src, const std::string &sep, T& container, bool keepEmpty = false)
|
||||
{
|
||||
std::string s;
|
||||
for (std::string::const_iterator i = src.begin(); i != src.end(); i++)
|
||||
{
|
||||
if (sep.find(*i) != std::string::npos)
|
||||
{
|
||||
if (keepEmpty || s.length())
|
||||
container.push_back(s);
|
||||
s = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
s += *i;
|
||||
}
|
||||
}
|
||||
if (keepEmpty || s.length())
|
||||
container.push_back(s);
|
||||
}
|
||||
|
||||
VFS_NAMESPACE_END
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue