no message
This was SVN commit r53.
This commit is contained in:
parent
d963d9c046
commit
40ca60014c
@ -57,6 +57,8 @@ void get_cur_resolution(int& xres, int& yres)
|
||||
size_t tot_mem = 0;
|
||||
size_t avl_mem = 0;
|
||||
|
||||
size_t page_size = 0;
|
||||
|
||||
void get_mem_status()
|
||||
{
|
||||
// Win32
|
||||
@ -68,10 +70,19 @@ void get_mem_status()
|
||||
// fixes results for my machine - off by 528 KB. why?!
|
||||
avl_mem = ms.dwAvailPhys;
|
||||
|
||||
// Sys V derived (GNU/Linux, Solaris)
|
||||
#elif defined(_SC_PAGESIZE) && defined(_SC_AVPHYS_PAGES)
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
page_size = si.dwPageSize;
|
||||
|
||||
#else // !_WIN32
|
||||
|
||||
#ifdef _SC_PAGESIZE
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
|
||||
// Sys V derived (GNU/Linux, Solaris)
|
||||
#ifdef _SC_AVPHYS_PAGES
|
||||
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
tot_mem = sysconf(_SC_PHYS_PAGES ) * page_size;
|
||||
avl_mem = sysconf(_SC_AVPHYS_PAGES) * page_size;
|
||||
|
||||
@ -85,6 +96,8 @@ void get_mem_status()
|
||||
sysctl(mib, 2, &avl_mem, &len, 0, 0);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "font.h"
|
||||
#include "res.h"
|
||||
#include "vfs.h"
|
||||
#include "tex.h"
|
||||
#include "ogl.h"
|
||||
#include "posix.h"
|
||||
@ -126,13 +127,21 @@ static void font_dtor(void* p)
|
||||
}
|
||||
|
||||
|
||||
u32 font_load(const char* fn)
|
||||
Handle font_load(const char* fn)
|
||||
{
|
||||
const u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
|
||||
FONT* font;
|
||||
Handle h = h_alloc(fn_hash, H_FONT, font_dtor, (void**)&font);
|
||||
if(!h)
|
||||
return 0;
|
||||
if(font->tex)
|
||||
return h;
|
||||
|
||||
void* p;
|
||||
size_t size;
|
||||
HDATA* hd;
|
||||
Handle h = res_load(fn, H_FONT, font_dtor, p, size, hd);
|
||||
if(!h)
|
||||
Handle hm = vfs_load(fn, p, size);
|
||||
if(!hm)
|
||||
return 0;
|
||||
|
||||
int pos; // current position in the file
|
||||
@ -159,6 +168,8 @@ u32 font_load(const char* fn)
|
||||
}
|
||||
}
|
||||
|
||||
h_free(hm, H_MEM);
|
||||
|
||||
// load glyph texture
|
||||
const Handle tex = tex_load(tex_filename);
|
||||
if(!tex)
|
||||
@ -191,7 +202,6 @@ u32 font_load(const char* fn)
|
||||
u = 0.f, v += th;
|
||||
}
|
||||
|
||||
FONT* font = (FONT*)hd->user;
|
||||
font->tex = tex;
|
||||
font->list_base = list_base;
|
||||
|
||||
@ -201,10 +211,9 @@ u32 font_load(const char* fn)
|
||||
|
||||
int font_bind(const Handle h)
|
||||
{
|
||||
HDATA* hd = h_data(h, H_FONT);
|
||||
if(!hd)
|
||||
FONT* font = (FONT*)h_user_data(h, H_FONT);
|
||||
if(!font)
|
||||
return -1;
|
||||
FONT* font = (FONT*)hd->user;
|
||||
|
||||
tex_bind(font->tex);
|
||||
glListBase(font->list_base);
|
||||
|
@ -1,6 +1,7 @@
|
||||
// malloc layer for less fragmentation, alignment, and automatic release
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#include <map>
|
||||
|
||||
@ -11,58 +12,43 @@
|
||||
#include "posix.h"
|
||||
|
||||
|
||||
struct MEM
|
||||
static void heap_free(MEM* m)
|
||||
{
|
||||
uint type;
|
||||
|
||||
// MEM_HEAP only
|
||||
void* org_p;
|
||||
|
||||
// MEM_POOL only
|
||||
size_t ofs;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void heap_dtor(void* p)
|
||||
{
|
||||
MEM* mem = (MEM*)p;
|
||||
free(mem->org_p);
|
||||
free(m->org_p);
|
||||
}
|
||||
|
||||
|
||||
static void* heap_alloc(const size_t size, const int align, MEM& mem)
|
||||
static void* heap_alloc(const size_t size, const int align, MEM* mem)
|
||||
{
|
||||
u8* org_p = (u8*)malloc(size+align-1);
|
||||
u8* p = (u8*)round_up((long)org_p, align);
|
||||
|
||||
mem.org_p = org_p;
|
||||
mem->org_p = org_p;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static u8* pool;
|
||||
static size_t pool_pos;
|
||||
static const size_t POOL_CAP = 64*MB; // TODO: user editable
|
||||
|
||||
|
||||
static void pool_dtor(void* p)
|
||||
static void pool_free(MEM* m)
|
||||
{
|
||||
MEM* mem = (MEM*)p;
|
||||
|
||||
// at end of pool? if so, 'free' it
|
||||
if(mem->ofs + mem->size == pool_pos)
|
||||
pool_pos -= mem->size;
|
||||
if(m->ofs + m->size == pool_pos)
|
||||
pool_pos -= m->size;
|
||||
}
|
||||
|
||||
|
||||
static void* pool_alloc(const size_t size, const uint align, MEM& mem)
|
||||
static void* pool_alloc(const size_t size, const uint align, MEM* mem)
|
||||
{
|
||||
if(!pool)
|
||||
{
|
||||
pool = (u8*)mem_alloc(size, MEM_HEAP, align);
|
||||
pool = (u8*)mem_alloc(size, align, MEM_HEAP);
|
||||
if(!pool)
|
||||
return 0;
|
||||
}
|
||||
@ -73,52 +59,47 @@ static void* pool_alloc(const size_t size, const uint align, MEM& mem)
|
||||
|
||||
void* p = (u8*)pool + ofs;
|
||||
|
||||
mem.size = size;
|
||||
mem.ofs = ofs;
|
||||
mem->size = size;
|
||||
mem->ofs = ofs;
|
||||
|
||||
pool_pos = ofs+size;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void mem_dtor(void* p)
|
||||
|
||||
static void mmap_free(MEM* m)
|
||||
{
|
||||
MEM* mem = (MEM*)p;
|
||||
if(mem->type == MEM_HEAP)
|
||||
heap_dtor(p);
|
||||
else if(mem->type == MEM_POOL)
|
||||
pool_dtor(p);
|
||||
munmap(m->p, m->size);
|
||||
}
|
||||
|
||||
|
||||
void* mem_alloc(size_t size, const MemType type, const uint align, Handle* ph)
|
||||
static void* mmap_alloc(const size_t size, const int fd, MEM* mem)
|
||||
{
|
||||
if(size == 0)
|
||||
size = 1;
|
||||
mem->p = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
mem->size = size;
|
||||
mem->fd = fd;
|
||||
|
||||
HDATA* hd;
|
||||
Handle h = h_alloc(0, H_MEM, mem_dtor, &hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
return mem->p;
|
||||
}
|
||||
|
||||
MEM& mem = (MEM&)hd->user;
|
||||
|
||||
void* p;
|
||||
if(type == MEM_HEAP)
|
||||
p = heap_alloc(size, align, mem);
|
||||
else if(type == MEM_POOL)
|
||||
p = pool_alloc(size, align, mem);
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static void mem_dtor(void* p)
|
||||
{
|
||||
MEM* m = (MEM*)p;
|
||||
if(m->type == MEM_HEAP)
|
||||
heap_free(m);
|
||||
else if(m->type == MEM_POOL)
|
||||
pool_free(m);
|
||||
else if(m->type == MEM_MAPPED)
|
||||
mmap_free(m);
|
||||
else
|
||||
{
|
||||
h_free(h, H_MEM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(ph)
|
||||
*ph = h;
|
||||
|
||||
return p;
|
||||
assert(0 && "mem_dtor: MEM.type invalid!");
|
||||
}
|
||||
|
||||
|
||||
@ -127,9 +108,60 @@ int mem_free(void* p)
|
||||
if(!p)
|
||||
return 1;
|
||||
|
||||
HDATA* hd;
|
||||
Handle h = h_find(p, H_MEM, &hd);
|
||||
Handle h = h_find((u32)p, H_MEM, 0);
|
||||
if(h)
|
||||
return h_free(h, H_MEM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int mem_free(Handle hm)
|
||||
{
|
||||
return h_free(hm, H_MEM);
|
||||
}
|
||||
|
||||
|
||||
void* mem_alloc(size_t size, const uint align, const MemType type, const int fd, Handle* ph)
|
||||
{
|
||||
assert(size != 0 && "mem_alloc: why is size = 0?");
|
||||
|
||||
// bit of a hack: the allocators require space for bookkeeping,
|
||||
// but we can't allocate a handle until we know the key
|
||||
// (the pointer address), which is used to find the corresponding
|
||||
// handle when freeing memory.
|
||||
// we fill a temp MEM, and then copy it into the handle's user data space
|
||||
MEM mem;
|
||||
|
||||
void* p;
|
||||
if(type == MEM_HEAP)
|
||||
p = heap_alloc(size, align, &mem);
|
||||
else if(type == MEM_POOL)
|
||||
p = pool_alloc(size, align, &mem);
|
||||
else if(type == MEM_MAPPED)
|
||||
p = mmap_alloc(size, fd, &mem);
|
||||
else
|
||||
{
|
||||
assert(0 && "mem_alloc: invalid type parameter");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!p)
|
||||
return 0;
|
||||
|
||||
MEM* pmem;
|
||||
Handle h = h_alloc((u32)p, H_MEM, mem_dtor, (void**)&pmem);
|
||||
if(!h) // failed to allocate a handle
|
||||
{
|
||||
mem_dtor(&mem);
|
||||
return 0;
|
||||
}
|
||||
*pmem = mem; // copy our memory info into the handle's user data space
|
||||
|
||||
// caller is asking for the handle
|
||||
// (freeing the memory via handle is faster than mem_free, because
|
||||
// we wouldn't have to scan all handles looking for the pointer)
|
||||
if(ph)
|
||||
*ph = h;
|
||||
|
||||
return p;
|
||||
}
|
@ -3,13 +3,36 @@
|
||||
|
||||
#include "res.h"
|
||||
|
||||
// include memory mappings because the VFS may return either a chunk of
|
||||
// memory, or the mapped file, and a client doesn't know the difference.
|
||||
|
||||
enum MemType
|
||||
{
|
||||
MEM_POOL,
|
||||
MEM_HEAP
|
||||
MEM_HEAP,
|
||||
MEM_MAPPED
|
||||
};
|
||||
|
||||
extern void* mem_alloc(size_t size, MemType type = MEM_HEAP, uint align = 1, Handle* ph = 0);
|
||||
|
||||
struct MEM
|
||||
{
|
||||
void* p;
|
||||
size_t size;
|
||||
|
||||
MemType type;
|
||||
|
||||
union
|
||||
{
|
||||
size_t ofs; // MEM_POOL only
|
||||
void* org_p; // MEM_HEAP only
|
||||
int fd; // MEM_MAPPED only
|
||||
};
|
||||
};
|
||||
|
||||
extern void* mem_alloc(size_t size, uint align = 1, MemType type = MEM_HEAP, int fd = -1, Handle* ph = 0);
|
||||
extern int mem_free(void* p);
|
||||
|
||||
// faster than mem_free(void*) - no scan of open handles for the pointer
|
||||
extern int mem_free(Handle hm);
|
||||
|
||||
#endif // #ifndef __MEM_H__
|
||||
|
@ -477,7 +477,6 @@ int uname(struct utsname* un)
|
||||
// hardware type
|
||||
static SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
|
||||
if(si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
|
||||
strcpy(un->machine, "AMD64");
|
||||
else
|
||||
|
@ -22,13 +22,39 @@
|
||||
#include <cstdio>
|
||||
|
||||
#include "types.h"
|
||||
#include "unzip.h"
|
||||
#include "zip.h"
|
||||
#include "posix.h"
|
||||
#include "misc.h"
|
||||
#include "res.h"
|
||||
#include "mem.h"
|
||||
#include "vfs.h"
|
||||
|
||||
|
||||
// handle (32 bits)
|
||||
// .. make sure this is the same handle we opened
|
||||
const uint HTAG_BITS = 16;
|
||||
// .. index into array => = log2(max open handles)
|
||||
const uint HIDX_BITS = 12;
|
||||
|
||||
// together, <= 32-TAG_BITS bits
|
||||
const uint HTYPE_BITS = 4;
|
||||
const uint HREF_BITS = 8;
|
||||
|
||||
const int HDATA_USER_SIZE = 20;
|
||||
|
||||
// 32 bytes
|
||||
struct HDATA
|
||||
{
|
||||
u32 key;
|
||||
u32 tag : HTAG_BITS;
|
||||
u32 type : HTYPE_BITS; // handle's type (e.g. texture, sound)
|
||||
u32 refs : HREF_BITS;
|
||||
|
||||
u32 unused; // TODO: type pointer?
|
||||
|
||||
u8 user[HDATA_USER_SIZE];
|
||||
};
|
||||
|
||||
static const ulong hdata_cap = 1ul << HIDX_BITS;
|
||||
static const uint type_cap = 1ul << HTYPE_BITS;
|
||||
|
||||
@ -70,7 +96,7 @@ static int h_idx(const Handle h, const uint type)
|
||||
return -1;
|
||||
|
||||
const HDATA* hd = h_data(idx);
|
||||
// cannot fail - it was successfully allocated
|
||||
// cannot fail - all HDATA up to last_in_use are valid
|
||||
|
||||
const u32 tag = h >> HIDX_BITS;
|
||||
// note: tag = 0 marks unused entries => is invalid
|
||||
@ -101,17 +127,7 @@ static int h_free(const int idx)
|
||||
if(--hd->refs)
|
||||
return 0;
|
||||
|
||||
// free its pointer
|
||||
switch(hd->ptype)
|
||||
{
|
||||
case PT_MEM:
|
||||
mem_free(hd->p);
|
||||
break;
|
||||
|
||||
case PT_MAP:
|
||||
munmap(hd->p, hd->size);
|
||||
break;
|
||||
}
|
||||
// TODO: keep this handle open (cache)
|
||||
|
||||
// call its type's destructor
|
||||
if(dtors[hd->type])
|
||||
@ -143,25 +159,7 @@ static void cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
Handle h_find(const void* p, uint type, HDATA** puser)
|
||||
{
|
||||
for(int idx = 0; idx <= last_in_use; idx++)
|
||||
{
|
||||
HDATA* hd = h_data(idx); // guaranteed valid
|
||||
|
||||
if(hd->p == p && hd->type == type)
|
||||
{
|
||||
if(puser)
|
||||
*puser = hd/*->user*/;
|
||||
return handle(idx);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Handle h_find(const u32 key, uint type, HDATA** puser)
|
||||
Handle h_find(const u32 key, uint type, void** puser)
|
||||
{
|
||||
int idx;
|
||||
HDATA* hd;
|
||||
@ -195,32 +193,12 @@ Handle h_find(const u32 key, uint type, HDATA** puser)
|
||||
found:
|
||||
Handle h = handle(idx);
|
||||
if(puser)
|
||||
*puser = hd/*->user*/;
|
||||
*puser = hd->user;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
int h_assign(Handle h, u8* p, size_t size, bool mem)
|
||||
{
|
||||
HDATA* hd = h_data(h);
|
||||
if(!hd)
|
||||
return -1;
|
||||
|
||||
if(hd->p || hd->size || hd->ptype != PT_NONE)
|
||||
{
|
||||
assert(!"h_assign: field(s) already assigned");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hd->p = p;
|
||||
hd->size = size;
|
||||
hd->ptype = mem? PT_MEM : PT_MAP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Handle h_alloc(const u32 key, const uint type, /*const size_t user_size,*/ DTOR dtor, HDATA** puser)
|
||||
Handle h_alloc(const u32 key, const uint type, /*const size_t user_size,*/ H_DTOR dtor, void** puser)
|
||||
{
|
||||
ONCE(atexit(cleanup))
|
||||
/*
|
||||
@ -253,11 +231,10 @@ Handle h_alloc(const u32 key, const uint type, /*const size_t user_size,*/ DTOR
|
||||
if(key)
|
||||
{
|
||||
// object already loaded?
|
||||
Handle h = h_find(key, type, &hd);
|
||||
Handle h = h_find(key, type, 0);
|
||||
if(h)
|
||||
{
|
||||
// only way to decide whether this handle is new, or a reference
|
||||
assert(hd->size != 0);
|
||||
hd = h_data(h_idx(h, type));
|
||||
|
||||
if(hd->refs == (1ul << HREF_BITS))
|
||||
{
|
||||
@ -320,14 +297,15 @@ Handle h_alloc(const u32 key, const uint type, /*const size_t user_size,*/ DTOR
|
||||
hd->type = type;
|
||||
|
||||
if(puser)
|
||||
*puser = hd/*->user*/;
|
||||
*puser = hd->user;
|
||||
return handle(idx);
|
||||
}
|
||||
|
||||
|
||||
int h_free(const Handle h, const uint type)
|
||||
int h_free(Handle& h, const uint type)
|
||||
{
|
||||
int idx = h_idx(h, type);
|
||||
h = 0;
|
||||
if(idx >= 0)
|
||||
return h_free(idx);
|
||||
return -1;
|
||||
@ -335,52 +313,14 @@ int h_free(const Handle h, const uint type)
|
||||
|
||||
|
||||
|
||||
HDATA* h_data(const Handle h, const uint type)
|
||||
void* h_user_data(const Handle h, const uint type)
|
||||
{
|
||||
int idx = h_idx(h, type);
|
||||
if(idx >= 0)
|
||||
return h_data(idx);
|
||||
return h_data(idx)->user; // pointer is always valid if index is in range
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& user)
|
||||
{
|
||||
p = 0;
|
||||
size = 0;
|
||||
user = 0;
|
||||
|
||||
u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
// TODO: fn is usually a constant; pass fn len if too slow
|
||||
|
||||
HDATA* hd;
|
||||
Handle h = h_alloc(fn_hash, type, dtor, &hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
|
||||
// already open - return a reference
|
||||
if(hd->size)
|
||||
return h;
|
||||
|
||||
Handle hf = vfs_open(fn);
|
||||
int err = vfs_read(hf, p, size, 0);
|
||||
vfs_close(hf);
|
||||
if(err < 0)
|
||||
return 0;
|
||||
|
||||
if(!p)
|
||||
{
|
||||
h_free(h, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hd->p = p;
|
||||
hd->size = size;
|
||||
user=hd;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -21,16 +21,10 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// the following are internal to the resource manager,
|
||||
// but are required for the HDATA definition
|
||||
// (which is passed around to modules that create handles).
|
||||
// we don't want to waste memory or fragment the handle data
|
||||
// by splitting into internal/external
|
||||
|
||||
|
||||
// handle type (for 'type safety' - can't use a texture handle as a sound)
|
||||
//
|
||||
// rationale: we could use the destructor passed to res_load to identify
|
||||
// rationale: we could use the destructor passed to h_alloc to identify
|
||||
// the handle, but it's good to have a list of all types, and we avoid having
|
||||
// to create empty destructors for handle types that wouldn't need them.
|
||||
// finally, we save memory - this fits in a few bits, vs. needing a pointer.
|
||||
@ -47,41 +41,7 @@ enum HType
|
||||
NUM_HANDLE_TYPES
|
||||
};
|
||||
|
||||
// handle's pointer type
|
||||
enum PType
|
||||
{
|
||||
PT_NONE,
|
||||
PT_MEM, // allocated by mem_alloc
|
||||
PT_MAP // mapped by mmap
|
||||
};
|
||||
|
||||
// handle (32 bits)
|
||||
// .. make sure this is the same handle we opened
|
||||
const uint HTAG_BITS = 16;
|
||||
// .. index into array => = log2(max open handles)
|
||||
const uint HIDX_BITS = 12;
|
||||
|
||||
// <= 32-TAG_BITS bits
|
||||
const uint HTYPE_BITS = 4;
|
||||
const uint PTYPE_BITS = 4;
|
||||
const uint HREF_BITS = 8;
|
||||
|
||||
const int HDATA_USER_SIZE = 16;
|
||||
|
||||
// 32 bytes
|
||||
struct HDATA
|
||||
{
|
||||
u32 key;
|
||||
u32 tag : HTAG_BITS;
|
||||
u32 type : HTYPE_BITS; // handle's type (e.g. texture, sound)
|
||||
u32 ptype : PTYPE_BITS; // what does p point to?
|
||||
u32 refs : HREF_BITS;
|
||||
|
||||
void* p;
|
||||
size_t size;
|
||||
|
||||
u8 user[HDATA_USER_SIZE];
|
||||
};
|
||||
|
||||
|
||||
// 0 = invalid handle value.
|
||||
@ -90,7 +50,7 @@ typedef u32 Handle;
|
||||
|
||||
// destructor, registered by h_alloc for a given handle type.
|
||||
// receives the user data associated with the handle.
|
||||
typedef void(*DTOR)(void*);
|
||||
typedef void(*H_DTOR)(void*);
|
||||
|
||||
|
||||
// all functions check the passed tag (part of the handle) and type against
|
||||
@ -105,20 +65,15 @@ typedef void(*DTOR)(void*);
|
||||
//// user_size is checked to make sure the user data fits in the handle data space.
|
||||
// dtor is associated with type and called when the object is freed.
|
||||
// handle data is initialized to 0; optionally, a pointer to it is returned.
|
||||
extern Handle h_alloc(u32 key, uint type,/* size_t user_size,*/ DTOR dtor = 0, HDATA** puser = 0);
|
||||
extern int h_free(Handle h, uint type);
|
||||
extern Handle h_alloc(u32 key, uint type,/* size_t user_size,*/ H_DTOR dtor = 0, void** puser = 0);
|
||||
extern int h_free(Handle& h, uint type);
|
||||
|
||||
// find and return a handle by type and key (typically filename hash)
|
||||
// currently O(n).
|
||||
extern Handle h_find(u32 key, uint type, HDATA** puser = 0);
|
||||
|
||||
// same as above, but search for the handle's associated pointer
|
||||
extern Handle h_find(const void* p, uint type, HDATA** puser = 0);
|
||||
extern Handle h_find(u32 key, uint type, void** puser = 0);
|
||||
|
||||
// return a pointer to handle data
|
||||
extern HDATA* h_data(Handle h, uint type);
|
||||
|
||||
extern Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& user);
|
||||
extern void* h_user_data(Handle h, uint type);
|
||||
|
||||
|
||||
#endif // #ifndef __RES_H__
|
||||
|
@ -21,8 +21,11 @@
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "vfs.h"
|
||||
#include "tex.h"
|
||||
#include "mem.h"
|
||||
#include "ogl.h"
|
||||
#include "res.h"
|
||||
#include "misc.h"
|
||||
@ -134,8 +137,6 @@ static int dds_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
const u32 img_size = read_le32(&surf->dwLinearSize);
|
||||
const u32 mipmaps = read_le32(&surf->dwMipMapCount);
|
||||
|
||||
const u8* img = ptr + hdr_size;
|
||||
|
||||
uint fmt = 0;
|
||||
switch(surf->ddpfPixelFormat.dwFourCC) // endian-independent
|
||||
{
|
||||
@ -154,7 +155,7 @@ static int dds_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
tex->height = h;
|
||||
tex->fmt = fmt;
|
||||
tex->bpp = img_size / (w * h);
|
||||
tex->ptr = img;
|
||||
tex->ofs = hdr_size;
|
||||
|
||||
if(sizeof(DDSURFACEDESC2) != ddsd_size)
|
||||
err = "DDSURFACEDESC2 size mismatch";
|
||||
@ -214,7 +215,6 @@ static int tga_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
|
||||
const u8 alpha_bits = desc & 0x0f;
|
||||
|
||||
const u8* img = ptr + hdr_size;
|
||||
const ulong img_size = (ulong)w * h * bpp / 8;
|
||||
|
||||
// determine format
|
||||
@ -240,7 +240,7 @@ static int tga_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
tex->height = h;
|
||||
tex->fmt = fmt;
|
||||
tex->bpp = bpp;
|
||||
tex->ptr = img;
|
||||
tex->ofs = hdr_size;
|
||||
|
||||
if(fmt == -1)
|
||||
err = "invalid format or bpp";
|
||||
@ -323,14 +323,13 @@ static int bmp_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
const u32 compress = read_le32(&bch->biCompression);
|
||||
const u32 ofs = read_le32(&bfh->bfOffBits);
|
||||
|
||||
const u8* img = ptr + ofs;
|
||||
const u32 img_size = w * h * bpp/8;
|
||||
|
||||
tex->width = w;
|
||||
tex->height = h;
|
||||
tex->fmt = (bpp == 24)? GL_BGR : GL_BGRA;
|
||||
tex->bpp = bpp;
|
||||
tex->ptr = img;
|
||||
tex->ofs = ofs;
|
||||
|
||||
if(h < 0)
|
||||
err = "top-down";
|
||||
@ -386,7 +385,7 @@ static int raw_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
tex->height = dim;
|
||||
tex->fmt = fmts[i];
|
||||
tex->bpp = i * 8;
|
||||
tex->ptr = ptr;
|
||||
tex->ofs = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -591,28 +590,38 @@ static int jp2_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
static void tex_dtor(void* p)
|
||||
{
|
||||
TEX* tex = (TEX*)p;
|
||||
|
||||
mem_free(tex->hm);
|
||||
|
||||
glDeleteTextures(1, &tex->id);
|
||||
}
|
||||
|
||||
|
||||
// TEX output param is invalid if function fails
|
||||
Handle tex_load(const char* fn, TEX* ptex)
|
||||
{
|
||||
const u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
|
||||
TEX* tex;
|
||||
Handle ht = h_alloc(fn_hash, H_TEX, tex_dtor, (void**)&tex);
|
||||
if(!ht)
|
||||
return 0;
|
||||
if(tex->id != 0)
|
||||
goto already_loaded;
|
||||
|
||||
{
|
||||
// load file
|
||||
const u8* p;
|
||||
size_t size;
|
||||
HDATA* hd;
|
||||
Handle h = res_load(fn, H_TEX, tex_dtor, (void*&)p, size, hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
|
||||
TEX* tex = (TEX*)hd->user;
|
||||
if(!p)
|
||||
goto already_loaded;
|
||||
if(size < 4) // guarantee xxx_valid routines 4 bytes
|
||||
return 0;
|
||||
|
||||
Handle hm = vfs_load(fn, (void*&)p, size);
|
||||
// .. note: xxx_valid routines assume 4 header bytes are available
|
||||
if(!hm || !p || size < 4)
|
||||
{
|
||||
h_free(ht, H_TEX);
|
||||
return 0;
|
||||
}
|
||||
tex->hm = hm;
|
||||
|
||||
int err = -1;
|
||||
|
||||
#ifndef NO_DDS
|
||||
@ -643,7 +652,6 @@ Handle tex_load(const char* fn, TEX* ptex)
|
||||
|
||||
if(err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
// loaders weren't able to determine type
|
||||
if(tex->fmt == 0)
|
||||
@ -653,43 +661,45 @@ Handle tex_load(const char* fn, TEX* ptex)
|
||||
// TODO: check file name, go to 32 bit if wrong
|
||||
}
|
||||
|
||||
{
|
||||
uint id;
|
||||
glGenTextures(1, &id);
|
||||
tex->id = id;
|
||||
}
|
||||
// this can't realistically fail, just note that the already_loaded
|
||||
// check above assumes (id > 0) <==> texture is loaded and valid
|
||||
}
|
||||
|
||||
already_loaded:
|
||||
if(ptex)
|
||||
*ptex = *tex;
|
||||
|
||||
return h;
|
||||
return ht;
|
||||
}
|
||||
|
||||
|
||||
int tex_bind(const Handle h)
|
||||
{
|
||||
HDATA* hd = h_data(h, H_TEX);
|
||||
if(!hd)
|
||||
TEX* tex = (TEX*)h_user_data(h, H_TEX);
|
||||
if(!tex)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return -1;
|
||||
}
|
||||
TEX* tex = (TEX*)hd->user;
|
||||
glBindTexture(GL_TEXTURE_2D, tex->id);
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, tex->id);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int tex_filter = GL_LINEAR;
|
||||
uint tex_bpp = 32; // 16 or 32
|
||||
|
||||
int tex_upload(const Handle h, int filter, int int_fmt)
|
||||
int tex_upload(const Handle ht, int filter, int int_fmt)
|
||||
{
|
||||
HDATA* hd = h_data(h, H_TEX);
|
||||
if(!hd)
|
||||
TEX* tex = (TEX*)h_user_data(ht, H_TEX);
|
||||
if(!tex)
|
||||
return -1;
|
||||
TEX* tex = (TEX*)hd->user;
|
||||
|
||||
// greater than max supported tex dimension?
|
||||
// no-op if oglInit not yet called
|
||||
@ -708,7 +718,18 @@ int tex_upload(const Handle h, int filter, int int_fmt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
tex_bind(h);
|
||||
tex_bind(ht);
|
||||
|
||||
// get pointer to image data
|
||||
MEM* mem = (MEM*)h_user_data(tex->hm, H_MEM);
|
||||
if(!mem)
|
||||
return 0;
|
||||
void* p = mem->p;
|
||||
if(!p)
|
||||
{
|
||||
assert(0 && "tex_upload: mem object is a NULL pointer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set filter
|
||||
if(!filter)
|
||||
@ -726,8 +747,9 @@ int tex_upload(const Handle h, int filter, int int_fmt)
|
||||
if(tex->fmt >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
|
||||
tex->fmt <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
|
||||
{
|
||||
int img_size = tex->width * tex->height * tex->bpp;
|
||||
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, tex->fmt, tex->width, tex->height, 0, img_size, tex->ptr);
|
||||
const int img_size = tex->width * tex->height * tex->bpp;
|
||||
assert(4+sizeof(DDSURFACEDESC2)+img_size == mem->size && "tex_upload: dds file size mismatch");
|
||||
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, tex->fmt, tex->width, tex->height, 0, img_size, p);
|
||||
}
|
||||
// normal
|
||||
else
|
||||
@ -756,16 +778,18 @@ int tex_upload(const Handle h, int filter, int int_fmt)
|
||||
|
||||
// manual mipmap gen via GLU (box filter)
|
||||
if(mipmap && !sgm_avl)
|
||||
gluBuild2DMipmaps(GL_TEXTURE_2D, int_fmt, tex->width, tex->height, tex->fmt, GL_UNSIGNED_BYTE, tex->ptr);
|
||||
gluBuild2DMipmaps(GL_TEXTURE_2D, int_fmt, tex->width, tex->height, tex->fmt, GL_UNSIGNED_BYTE, p);
|
||||
// auto mipmap gen, or no mipmap
|
||||
else
|
||||
{
|
||||
if(mipmap)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, tex->width, tex->height, 0, tex->fmt, GL_UNSIGNED_BYTE, tex->ptr);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, tex->width, tex->height, 0, tex->fmt, GL_UNSIGNED_BYTE, p);
|
||||
}
|
||||
}
|
||||
|
||||
mem_free(tex->hm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,7 +29,8 @@ struct TEX
|
||||
u32 height : 16;
|
||||
u32 fmt : 16;
|
||||
u32 bpp : 16;
|
||||
const u8* ptr;
|
||||
Handle hm; // H_MEM handle to loaded file
|
||||
size_t ofs; // WRT image data in file
|
||||
uint id;
|
||||
};
|
||||
|
||||
|
@ -1,351 +0,0 @@
|
||||
// ZIP archiving (on top of ZLib)
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "unzip.h"
|
||||
#include "posix.h"
|
||||
#include "misc.h"
|
||||
#include "res.h"
|
||||
#include "mem.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "zlib.lib")
|
||||
#endif
|
||||
|
||||
|
||||
static const char ecdr_id[] = "PK\5\6"; // End of Central Directory Header identifier
|
||||
static const char cdfh_id[] = "PK\1\2"; // Central File Header identifier
|
||||
static const char lfh_id[] = "PK\3\4"; // Local File Header identifier
|
||||
|
||||
|
||||
// H_ZFILE handle
|
||||
// location and size of an archived file
|
||||
// no destructor
|
||||
struct ZFILE
|
||||
{
|
||||
u32 ofs;
|
||||
u32 csize; // bit 31 = compression method (1: deflate; 0: stored)
|
||||
u32 ucsize;
|
||||
};
|
||||
|
||||
|
||||
// H_ZARCHIVE handle
|
||||
// information about a ZIP archive
|
||||
struct ZARCHIVE
|
||||
{
|
||||
Handle hf; // actual ZIP file (H_VFILE)
|
||||
|
||||
// file lookup
|
||||
u32 num_files;
|
||||
u32* fn_hashs; // split for more efficient search
|
||||
ZFILE* files;
|
||||
u32 last_file; // index of last file we found (speed up lookups of sequential files)
|
||||
};
|
||||
|
||||
|
||||
static void zarchive_dtor(void* p)
|
||||
{
|
||||
ZARCHIVE* za = (ZARCHIVE*)p;
|
||||
|
||||
vfs_close(za->hf);
|
||||
za->hf = 0;
|
||||
}
|
||||
|
||||
|
||||
// open and return a handle to the zip archive indicated by <fn>
|
||||
Handle zopen(const char* const fn)
|
||||
{
|
||||
const u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
|
||||
// already loaded?
|
||||
HDATA* hd;
|
||||
Handle h = h_find(fn_hash, H_ZFILE, &hd);
|
||||
if(h)
|
||||
return h;
|
||||
|
||||
// map the ZIP file
|
||||
Handle hf = vfs_map(fn);
|
||||
hd = h_data(hf, 0);
|
||||
if(!hd)
|
||||
return 0;
|
||||
const size_t size = hd->size;
|
||||
const u8* zfile = (const u8*)hd->p;
|
||||
|
||||
// find end of central dir record
|
||||
// by scanning last 66000 bytes of file for ecdr_id magic
|
||||
// (zip comment <= 65535 bytes, sizeof(ECDR) = 22, add some for safety)
|
||||
// if the zip file is < 66000 bytes, scan the whole file
|
||||
|
||||
size_t bytes_left = min(size, 66000);
|
||||
const u8* ecdr = zfile + size - bytes_left;
|
||||
|
||||
while(bytes_left-3 > 0)
|
||||
{
|
||||
if(*(u32*)ecdr == *(u32*)&ecdr_id)
|
||||
goto found_ecdr;
|
||||
|
||||
// check next 4 bytes (non aligned!!)
|
||||
ecdr++;
|
||||
bytes_left--;
|
||||
}
|
||||
|
||||
// reached EOF and still haven't found the ECDR identifier
|
||||
|
||||
fail:
|
||||
vfs_close(hf);
|
||||
return 0;
|
||||
|
||||
{
|
||||
found_ecdr:
|
||||
// read ECDR
|
||||
const u16 num_files = read_le16(ecdr+10);
|
||||
const u32 cd_ofs = read_le32(ecdr+16);
|
||||
|
||||
// memory for fn_hash and File arrays
|
||||
void* mem = mem_alloc(num_files * (4 + sizeof(ZFILE)), MEM_HEAP, 4*KB);
|
||||
if(!mem)
|
||||
goto fail;
|
||||
|
||||
h = h_alloc(fn_hash, H_ZFILE, zarchive_dtor, &hd);
|
||||
if(!h)
|
||||
goto fail;
|
||||
|
||||
ZARCHIVE* const za = (ZARCHIVE*)hd->user;
|
||||
za->hf = hf;
|
||||
za->fn_hashs = (u32*)mem;
|
||||
za->files = (ZFILE*)((u8*)mem + 4*num_files);
|
||||
za->last_file = 0;
|
||||
|
||||
// cache file list for faster lookups
|
||||
// currently linear search, comparing filename hash.
|
||||
// TODO: if too slow, use hash table.
|
||||
const u8* cdfh = zfile+cd_ofs;
|
||||
u32* hs = za->fn_hashs;
|
||||
ZFILE* f = za->files;
|
||||
uint i;
|
||||
for(i = 0; i < num_files; i++)
|
||||
{
|
||||
// read CDFH
|
||||
if(*(u32*)cdfh != *(u32*)cdfh_id)
|
||||
continue;
|
||||
const u32 csize = read_le32(cdfh+20);
|
||||
const u32 ucsize = read_le32(cdfh+24);
|
||||
const u16 fn_len = read_le16(cdfh+28);
|
||||
const u16 e_len = read_le16(cdfh+30);
|
||||
const u16 c_len = read_le16(cdfh+32);
|
||||
const u32 lfh_ofs = read_le32(cdfh+42);
|
||||
const u8 method = cdfh[10];
|
||||
|
||||
if(method & ~8) // neither deflated nor stored
|
||||
continue;
|
||||
|
||||
// read LFH
|
||||
const u8* const lfh = zfile + lfh_ofs;
|
||||
if(*(u32*)lfh != *(u32*)lfh_id)
|
||||
continue;
|
||||
const u16 lfh_fn_len = read_le16(lfh+26);
|
||||
const u16 lfh_e_len = read_le16(lfh+28);
|
||||
const char* lfh_fn = (const char*)lfh+30;
|
||||
|
||||
*hs++ = fnv_hash(lfh_fn, lfh_fn_len);
|
||||
f->ofs = lfh_ofs + 30 + lfh_fn_len + lfh_e_len;
|
||||
f->csize = csize;
|
||||
f->ucsize = ucsize;
|
||||
f++;
|
||||
|
||||
(int&)cdfh += 46 + fn_len + e_len + c_len;
|
||||
}
|
||||
|
||||
za->num_files = i;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
void zclose(const Handle h)
|
||||
{
|
||||
if(h_data(h, H_ZFILE))
|
||||
h_free(h, H_ZFILE);
|
||||
else
|
||||
h_free(h, H_ZARCHIVE);
|
||||
}
|
||||
|
||||
|
||||
Handle zopen(Handle hz, const char* fn)
|
||||
{
|
||||
HDATA* hzd = h_data(hz, H_ZFILE);
|
||||
if(!hzd)
|
||||
return 0;
|
||||
ZARCHIVE* za = (ZARCHIVE*)hzd->user;
|
||||
|
||||
// find its File descriptor
|
||||
const u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
uint i = za->last_file+1;
|
||||
if(i >= za->num_files || za->fn_hashs[i] != fn_hash)
|
||||
{
|
||||
for(i = 0; i < za->num_files; i++)
|
||||
if(za->fn_hashs[i] == fn_hash)
|
||||
break;
|
||||
if(i == za->num_files)
|
||||
return 0;
|
||||
|
||||
za->last_file = i;
|
||||
}
|
||||
const ZFILE* const f = &za->files[i];
|
||||
|
||||
//
|
||||
HDATA* hfd;
|
||||
Handle hf = h_alloc(fn_hash, H_ZFILE, 0, &hfd);
|
||||
return hf;
|
||||
}
|
||||
|
||||
int zaccess(Handle hz, const char* fn)
|
||||
{
|
||||
HDATA* hzd = h_data(hz, H_ZFILE);
|
||||
if(!hzd)
|
||||
return -1;
|
||||
ZARCHIVE* za = (ZARCHIVE*)hzd->user;
|
||||
|
||||
// find its File descriptor
|
||||
const u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
uint i = za->last_file+1;
|
||||
if(i >= za->num_files || za->fn_hashs[i] != fn_hash)
|
||||
{
|
||||
for(i = 0; i < za->num_files; i++)
|
||||
{
|
||||
if(za->fn_hashs[i] == fn_hash)
|
||||
break;
|
||||
}
|
||||
if(i == za->num_files)
|
||||
return -1;
|
||||
}
|
||||
za->last_file = i;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int zread(Handle hf, void*& p, size_t& size, size_t ofs)
|
||||
{
|
||||
HDATA* hfd = h_data(hf, 0);
|
||||
if(!hfd)
|
||||
return -1;
|
||||
|
||||
ZFILE* zf = (ZFILE*)hfd->user;
|
||||
const size_t ucsize = zf->ucsize;
|
||||
const size_t csize = zf->csize;
|
||||
|
||||
if(ofs > ucsize)
|
||||
return -1;
|
||||
|
||||
bool deflated = ucsize != csize;
|
||||
|
||||
// TODO: async read for uncompressed files?
|
||||
if(!deflated)
|
||||
{
|
||||
p = (u8*)hfd->p + zf->ofs + ofs;
|
||||
size = hfd->size - ofs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// double-buffered
|
||||
u32 slots[2];
|
||||
int active_read = 0;
|
||||
void* out_pos = 0;
|
||||
|
||||
void* out_mem = mem_alloc(ucsize, MEM_HEAP, 64*KB);
|
||||
if(!out_mem)
|
||||
return -1;
|
||||
|
||||
// inflating
|
||||
z_stream stream;
|
||||
if(deflated)
|
||||
{
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
if(inflateInit2(&stream, -MAX_WBITS) != Z_OK)
|
||||
return -1;
|
||||
// -MAX_WBITS indicates no zlib header present
|
||||
|
||||
stream.next_out = (u8*)out_mem;
|
||||
stream.avail_out = ucsize;
|
||||
}
|
||||
// read directly into output buffer
|
||||
else
|
||||
out_pos = out_mem;
|
||||
|
||||
bool first = true;
|
||||
bool done = false;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// start reading next block
|
||||
if(!done)
|
||||
slots[active_read] = vfs_start_read(hf, ofs, &out_pos);
|
||||
|
||||
active_read ^= 1;
|
||||
|
||||
// process block read in previous iteration
|
||||
if(!first)
|
||||
{
|
||||
void* p;
|
||||
size_t bytes_read;
|
||||
vfs_finish_read(slots[active_read], p, bytes_read);
|
||||
|
||||
// inflate what we read
|
||||
if(deflated)
|
||||
{
|
||||
stream.next_in = (u8*)p;
|
||||
stream.avail_in = bytes_read;
|
||||
inflate(&stream, 0);
|
||||
}
|
||||
}
|
||||
|
||||
first = false;
|
||||
// one more iteration to process the last pending block
|
||||
if(done)
|
||||
break;
|
||||
if(ofs >= csize)
|
||||
done = true;
|
||||
}
|
||||
|
||||
if(deflated)
|
||||
{
|
||||
inflateEnd(&stream);
|
||||
|
||||
if(stream.total_in != csize || stream.total_out != ucsize)
|
||||
{
|
||||
mem_free(out_mem);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
p = out_mem;
|
||||
size = ucsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//1 cache per zip - res layer doesnt know our internals (cache entry=ofs, csize,ucsize)
|
||||
//cache=array (allow finding next file quickly; need some mechanism for faster random access?)
|
||||
//sync is not a problem - zip file won't be updated during gameplay because it's still open
|
@ -1,38 +0,0 @@
|
||||
// ZIP archiving (on top of ZLib)
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef __UNZIP_H__
|
||||
#define __UNZIP_H__
|
||||
|
||||
|
||||
#include "res.h"
|
||||
|
||||
// open and return a handle to the zip archive indicated by <fn>
|
||||
extern Handle zopen(const char* fn);
|
||||
|
||||
// open and return a handle to file <fn> in the zip archive <hz>
|
||||
extern Handle zopen(Handle hz, const char* fn);
|
||||
|
||||
extern int zaccess( Handle hz, const char* fn );
|
||||
|
||||
extern void zclose(Handle hz);
|
||||
|
||||
extern int zread(Handle hf, void*& p, size_t& size, size_t ofs);
|
||||
|
||||
|
||||
#endif // #ifndef __UNZIP_H__
|
@ -1,3 +1,22 @@
|
||||
// virtual file system - transparent access to files in archives;
|
||||
// allows multiple search paths
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
@ -8,23 +27,44 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "posix.h"
|
||||
#include "unzip.h"
|
||||
#include "zip.h"
|
||||
#include "misc.h"
|
||||
#include "vfs.h"
|
||||
#include "mem.h"
|
||||
|
||||
|
||||
// H_VFILE handle
|
||||
struct VFILE
|
||||
{
|
||||
int fd;
|
||||
|
||||
size_t size; // compressed size, if a Zip file
|
||||
|
||||
// Zip only:
|
||||
size_t ucsize;
|
||||
size_t ofs;
|
||||
|
||||
Handle hm; // memory handle to the file or archive, if a Zip file
|
||||
};
|
||||
|
||||
|
||||
// rationale for n-archives per PATH entry:
|
||||
// We need to be able to unmount specific paths (e.g. when switching mods).
|
||||
// Don't want to remount everything (slow), or specify a mod tag when mounting
|
||||
// (not this module's job). Instead, we include all archives in one path entry;
|
||||
// the game keeps track of what paths it mounted for a mod, and unmounts those
|
||||
// when needed.
|
||||
// the game keeps track of what path(s) it mounted for a mod,
|
||||
// and unmounts those when needed.
|
||||
|
||||
struct PATH
|
||||
{
|
||||
char* dir; // relative to root; points to space at end of this struct
|
||||
struct PATH* next;
|
||||
struct PATH* next; // linked list
|
||||
|
||||
char* dir; // relative to root dir;
|
||||
// points to space at end of this struct
|
||||
|
||||
int num_archives;
|
||||
Handle archives[1];
|
||||
|
||||
// space allocated here for archive Handles + dir string
|
||||
};
|
||||
static PATH* path_list;
|
||||
@ -34,19 +74,13 @@ static void vfile_dtor(void* p)
|
||||
{
|
||||
VFILE* vf = (VFILE*)p;
|
||||
|
||||
// in archive
|
||||
if(vf->ha && vf->hz)
|
||||
{
|
||||
zclose(vf->hz);
|
||||
zclose(vf->ha);
|
||||
vf->ha = vf->hz = 0;
|
||||
}
|
||||
// normal file
|
||||
if(vf->fd > 0)
|
||||
{
|
||||
close(vf->fd);
|
||||
vf->fd = -1;
|
||||
}
|
||||
|
||||
mem_free(vf->hm);
|
||||
}
|
||||
|
||||
|
||||
@ -66,7 +100,7 @@ int vfs_set_root(const char* argv0, const char* root)
|
||||
return -1;
|
||||
*fn = 0;
|
||||
|
||||
chdir( fn + 1 );
|
||||
chdir(path);
|
||||
chdir(root);
|
||||
|
||||
return vfs_mount(".");
|
||||
@ -99,8 +133,8 @@ int vfs_mount(const char* path)
|
||||
|
||||
// alloc search path entry (add to front)
|
||||
const int archives_size = num_archives*sizeof(Handle);
|
||||
const int entry_size = round_up(sizeof(PATH)+archives_size+path_len+1, 8);
|
||||
PATH* entry = (PATH*)mem_alloc(entry_size);
|
||||
const int entry_size = round_up(sizeof(PATH)+archives_size+path_len+1, 32);
|
||||
PATH* entry = (PATH*)mem_alloc(entry_size, 32, MEM_HEAP);
|
||||
if(!entry)
|
||||
return -1;
|
||||
entry->next = path_list;
|
||||
@ -113,7 +147,7 @@ int vfs_mount(const char* path)
|
||||
std::sort(archives.begin(), archives.end());
|
||||
entry->num_archives = num_archives;
|
||||
for(int i = 0; i < num_archives; i++)
|
||||
entry->archives[i] = zopen(archives[i].c_str());
|
||||
entry->archives[i] = zip_open(archives[i].c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -130,7 +164,7 @@ int vfs_umount(const char* path)
|
||||
{
|
||||
// close all archives
|
||||
for(int i = 0; i < entry->num_archives; i++)
|
||||
zclose(entry->archives[i]);
|
||||
h_free(entry->archives[i], H_ZARCHIVE);
|
||||
|
||||
// remove from list
|
||||
*prev = entry->next;
|
||||
@ -148,107 +182,12 @@ int vfs_umount(const char* path)
|
||||
}
|
||||
|
||||
|
||||
Handle vfs_map(const char* fn)
|
||||
// call func, passing the data argument, for each mounted path
|
||||
// fail if its return value is < 0, stop if it returns 0
|
||||
static int vfs_foreach_path(int (*func)(const char* path, Handle ha, void* data), const char* fn, void* data)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
if(stat(fn, &stat_buf) != 0)
|
||||
return 0;
|
||||
size_t size = stat_buf.st_size;
|
||||
|
||||
int fd = open(fn, O_RDONLY);
|
||||
if(fd < 0)
|
||||
return 0;
|
||||
|
||||
u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
|
||||
void* p = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
if(p != MAP_FAILED)
|
||||
{
|
||||
HDATA* hd;
|
||||
Handle h = h_alloc(0, H_VFILE, vfile_dtor, &hd);
|
||||
if(h)
|
||||
{
|
||||
hd->p = p;
|
||||
hd->size = size;
|
||||
// VFILE* vf = (VFILE*)hd->user;
|
||||
// vf->fd = fd;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfs_access( char* fn )
|
||||
{
|
||||
// Alters 'fn' to the path of the file, if we find it...
|
||||
|
||||
// Mostly identical to vfs_stat, below.
|
||||
|
||||
struct stat dy;
|
||||
|
||||
// Strim out the path, if provided.
|
||||
char* name = strrchr( fn, '/' );
|
||||
if( name ) { name++; } else name = fn;
|
||||
|
||||
char buf[PATH_MAX+1]; buf[PATH_MAX] = 0;
|
||||
|
||||
// for each search path:
|
||||
for(PATH* entry = path_list; entry; entry = entry->next)
|
||||
{
|
||||
// dir
|
||||
const char* path = name;
|
||||
if(entry->dir[0] != '.' || entry->dir[1] != '\0')
|
||||
{
|
||||
// only prepend dir if not "." (root) - "./" isn't portable
|
||||
snprintf(buf, PATH_MAX, "%s/%s", entry->dir, name);
|
||||
path = buf;
|
||||
}
|
||||
if( !_stat( path, &dy ) )
|
||||
{
|
||||
strcpy( fn, path );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
// archive
|
||||
for(int i = 0; i < entry->num_archives; i++)
|
||||
{
|
||||
if( !zaccess(entry->archives[i], name) )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// not found
|
||||
return -1;
|
||||
}
|
||||
|
||||
int vfs_stat( const char* fn, struct stat *buffer )
|
||||
{
|
||||
// Mostly identical to vfs_open, below.
|
||||
|
||||
// Note: vfs_stat redefines the nlink member of stat for its own
|
||||
// nefarious ends.
|
||||
|
||||
// Check the specific location 'fn' first.
|
||||
// If the file's there, it's faster.
|
||||
|
||||
if( !_stat( fn, buffer ) )
|
||||
{
|
||||
buffer->st_nlink = 0;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
// Not there? Drop the old path.
|
||||
|
||||
char* name = strrchr( fn, '/' );
|
||||
if( name )
|
||||
fn = name + 1;
|
||||
|
||||
char buf[PATH_MAX+1]; buf[PATH_MAX] = 0;
|
||||
|
||||
// for each search path:
|
||||
for(PATH* entry = path_list; entry; entry = entry->next)
|
||||
{
|
||||
// dir
|
||||
@ -259,61 +198,150 @@ int vfs_stat( const char* fn, struct stat *buffer )
|
||||
snprintf(buf, PATH_MAX, "%s/%s", entry->dir, fn);
|
||||
path = buf;
|
||||
}
|
||||
if( !_stat( path, buffer ) )
|
||||
{
|
||||
buffer->st_nlink = 1;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
// Ignore files in an archive.
|
||||
int err = func(path, 0, data);
|
||||
if(err <= 0)
|
||||
return err;
|
||||
|
||||
// archive
|
||||
for(int i = 0; i < entry->num_archives; i++)
|
||||
{
|
||||
err = func(path, entry->archives[i], data);
|
||||
if(err <= 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
return -1;
|
||||
return -1; // func never returned 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int realpath_cb(const char* path, Handle ha, void* data)
|
||||
{
|
||||
char* full_path = (char*)data;
|
||||
struct stat s;
|
||||
|
||||
if(!path && !ha)
|
||||
{
|
||||
assert(0 && "realpath_cb: called with invalid path and archive handle");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(path)
|
||||
{
|
||||
if(!stat(path, &s))
|
||||
{
|
||||
strncpy(full_path, path, PATH_MAX);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if(ha)
|
||||
{
|
||||
if(!zip_stat(ha, path, &s))
|
||||
{
|
||||
zip_archive_info(ha, full_path, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vfs_realpath(const char* fn, char* full_path)
|
||||
{
|
||||
return vfs_foreach_path(realpath_cb, fn, full_path);
|
||||
}
|
||||
|
||||
|
||||
static int stat_cb(const char* path, Handle ha, void* data)
|
||||
{
|
||||
struct stat* s = (struct stat*)data;
|
||||
|
||||
if(path)
|
||||
return stat(path, s)? 1 : 0;
|
||||
else if(ha)
|
||||
return zip_stat(ha, path, s)? 1 : 0;
|
||||
|
||||
assert(0 && "stat_cb: called with invalid path and archive handle");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vfs_stat(const char* fn, struct stat* s)
|
||||
{
|
||||
return vfs_foreach_path(stat_cb, fn, s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int open_cb(const char* path, Handle ha, void* data)
|
||||
{
|
||||
struct stat s;
|
||||
VFILE* vf = (VFILE*)data;
|
||||
|
||||
// normal file
|
||||
if(path)
|
||||
{
|
||||
if(stat(path, &s) < 0)
|
||||
return 1;
|
||||
|
||||
int fd = open(path, O_RDONLY);
|
||||
if(fd < 0)
|
||||
return 1;
|
||||
|
||||
vf->fd = fd;
|
||||
vf->size = s.st_size;
|
||||
}
|
||||
// from archive
|
||||
else if(ha)
|
||||
{
|
||||
ZFILE* zf = zip_lookup(ha, path);
|
||||
if(!zf)
|
||||
return 1;
|
||||
|
||||
Handle hm;
|
||||
if(zip_archive_info(ha, 0, &hm) < 0)
|
||||
return 1;
|
||||
|
||||
vf->ofs = zf->ofs;
|
||||
vf->size = zf->csize;
|
||||
vf->ucsize = zf->ucsize;
|
||||
vf->fd = -1;
|
||||
vf->hm = hm;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0 && "open_cb: called with invalid path and archive handle");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Handle vfs_open(const char* fn)
|
||||
{
|
||||
char buf[PATH_MAX+1]; buf[PATH_MAX] = 0;
|
||||
u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
|
||||
// If a path to an existing file is given, use it.
|
||||
VFILE* vf;
|
||||
Handle hv = h_alloc(fn_hash, H_VFILE, vfile_dtor, (void**)&vf);
|
||||
if(!hv)
|
||||
return 0;
|
||||
|
||||
Handle h = vfs_map( fn );
|
||||
if( h )
|
||||
return( h );
|
||||
// already open
|
||||
if(vf->size)
|
||||
return hv;
|
||||
|
||||
char* name = strrchr( fn, '/' );
|
||||
if( name ) fn = name + 1;
|
||||
|
||||
// for each search path:
|
||||
for(PATH* entry = path_list; entry; entry = entry->next)
|
||||
if(vfs_foreach_path(open_cb, fn, vf) < 0)
|
||||
{
|
||||
// dir
|
||||
const char* path = fn;
|
||||
if(entry->dir[0] != '.' || entry->dir[1] != '\0')
|
||||
{
|
||||
// only prepend dir if not "." (root) - "./" isn't portable
|
||||
snprintf(buf, PATH_MAX, "%s/%s", entry->dir, fn);
|
||||
path = buf;
|
||||
}
|
||||
Handle h = vfs_map(path);
|
||||
if(h)
|
||||
return h;
|
||||
|
||||
// archive
|
||||
for(int i = 0; i < entry->num_archives; i++)
|
||||
{
|
||||
Handle h = zopen(entry->archives[i], fn);
|
||||
if(h)
|
||||
return h;
|
||||
}
|
||||
h_free(hv, H_VFILE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// not found
|
||||
return 0;
|
||||
return hv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const uint IDX_BITS = 4;
|
||||
const uint NUM_SLOTS = 1ul << IDX_BITS;
|
||||
const uint TAG_BITS = 32 - IDX_BITS;
|
||||
@ -326,12 +354,11 @@ slots[NUM_SLOTS];
|
||||
|
||||
u32 vfs_start_read(const Handle hf, size_t& ofs, void** buf)
|
||||
{
|
||||
HDATA* hfd = h_data(hf, 0);
|
||||
if(!hfd)
|
||||
VFILE* vf = (VFILE*)h_user_data(hf, H_VFILE);
|
||||
if(!vf)
|
||||
return 0;
|
||||
VFILE* vf = (VFILE*)hfd->user;
|
||||
|
||||
ssize_t bytes_left = hfd->size - ofs;
|
||||
ssize_t bytes_left = vf->size - ofs;
|
||||
if(bytes_left < 0)
|
||||
return 0;
|
||||
|
||||
@ -362,12 +389,12 @@ u32 vfs_start_read(const Handle hf, size_t& ofs, void** buf)
|
||||
|
||||
// use the buffer given (e.g. read directly into output buffer)
|
||||
if(buf)
|
||||
cb->aio_buf = buf;
|
||||
cb->aio_buf = *buf;
|
||||
// allocate our own (reused for subsequent requests)
|
||||
else
|
||||
if(!cb->aio_buf)
|
||||
{
|
||||
cb->aio_buf = mem_alloc(64*KB, MEM_HEAP, 64*KB);
|
||||
cb->aio_buf = mem_alloc(64*KB, 64*KB, MEM_HEAP);
|
||||
if(!cb->aio_buf)
|
||||
return 0;
|
||||
}
|
||||
@ -419,29 +446,120 @@ int vfs_finish_read(const u32 slot, void*& p, size_t& size)
|
||||
|
||||
|
||||
|
||||
int vfs_read(Handle h, void*& p, size_t& size, size_t ofs)
|
||||
Handle vfs_load(const char* fn, void*& _p, size_t& _size, bool dont_map)
|
||||
{
|
||||
p = 0;
|
||||
size = 0;
|
||||
_p = 0;
|
||||
_size = 0;
|
||||
|
||||
HDATA* hd = h_data(h, H_VFILE);
|
||||
if(hd)
|
||||
Handle hf = vfs_open(fn);
|
||||
if(!hf)
|
||||
return 0;
|
||||
|
||||
VFILE* vf = (VFILE*)h_user_data(hf, H_VFILE);
|
||||
|
||||
const bool deflated = vf->fd == -1 && vf->size != vf->ucsize;
|
||||
const size_t in_size = vf->size;
|
||||
const size_t out_size = deflated? vf->ucsize : vf->size;
|
||||
|
||||
// already mapped or read
|
||||
if(vf->hm)
|
||||
{
|
||||
if(ofs+size > hd->size)
|
||||
return -1;
|
||||
p = (u8*)hd->p + ofs;
|
||||
if(!size)
|
||||
size = hd->size - ofs;
|
||||
MEM* m = (MEM*)h_user_data(vf->hm, H_MEM);
|
||||
if(m)
|
||||
{
|
||||
assert(out_size == m->size && "vfs_load: mismatch between VFILE and MEM size");
|
||||
|
||||
_p = m->p;
|
||||
_size = m->size;
|
||||
return vf->hm;
|
||||
}
|
||||
else
|
||||
assert(0 && "vfs_load: invalid MEM attached to VFILE");
|
||||
}
|
||||
|
||||
// decide whether to map the file, or read it
|
||||
MemType mt = MEM_MAPPED;
|
||||
if(deflated || dont_map)
|
||||
mt = MEM_POOL;
|
||||
|
||||
// allocate memory / map the file
|
||||
Handle hm;
|
||||
void* out = mem_alloc(out_size, 64*KB, mt, vf->fd, &hm);
|
||||
if(!out)
|
||||
{
|
||||
vfs_close(hf);
|
||||
return 0;
|
||||
}
|
||||
// H_ZFILE
|
||||
else
|
||||
return zread(h, p, size, ofs);
|
||||
|
||||
if(mt == MEM_MAPPED)
|
||||
{
|
||||
_p = out;
|
||||
_size = out_size;
|
||||
return vf->hm = hm;
|
||||
}
|
||||
|
||||
// now we read the file in 64 KB chunks (double buffered);
|
||||
// if in an archive, we inflate while waiting for the next chunk to finish
|
||||
u32 slots[2];
|
||||
int active_read = 0;
|
||||
|
||||
void* pos = out; // if not inflating, read directly into output buffer
|
||||
size_t ofs = vf->ofs;
|
||||
|
||||
void* ctx;
|
||||
if(deflated)
|
||||
{
|
||||
pos = 0; // read into separate buffer
|
||||
ctx = zip_inflate_start(out, out_size);
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
bool done = false;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// start reading next block
|
||||
if(!done)
|
||||
slots[active_read] = vfs_start_read(hf, ofs, &pos);
|
||||
|
||||
active_read ^= 1;
|
||||
|
||||
// process block read in previous iteration
|
||||
if(!first)
|
||||
{
|
||||
void* p;
|
||||
size_t bytes_read;
|
||||
vfs_finish_read(slots[active_read], p, bytes_read);
|
||||
|
||||
// inflate what we read
|
||||
if(deflated)
|
||||
zip_inflate_process(ctx, p, bytes_read);
|
||||
}
|
||||
|
||||
first = false;
|
||||
if(done)
|
||||
break;
|
||||
// one more iteration to process the last pending block
|
||||
if(ofs >= in_size)
|
||||
done = true;
|
||||
}
|
||||
|
||||
if(deflated)
|
||||
{
|
||||
if(zip_inflate_end(ctx) < 0)
|
||||
{
|
||||
mem_free(out);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_p = out;
|
||||
_size = out_size;
|
||||
return vf->hm = hm;
|
||||
}
|
||||
|
||||
|
||||
int vfs_close(Handle h)
|
||||
{
|
||||
h_free(h, 0);
|
||||
return 0;
|
||||
}
|
||||
return h_free(h, H_VFILE);
|
||||
}
|
@ -1,10 +1,26 @@
|
||||
struct VFILE
|
||||
{
|
||||
int fd;
|
||||
// virtual file system - transparent access to files in archives;
|
||||
// allows multiple search paths
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
Handle hz; // position within archive (ZFILE)
|
||||
Handle ha; // archive (ZARCHIVE)
|
||||
};
|
||||
#ifndef __VFS_H__
|
||||
#define __VFS_H__
|
||||
|
||||
#include "res.h"
|
||||
|
||||
#define VFS_MAX_PATH 40
|
||||
|
||||
@ -12,17 +28,14 @@ extern int vfs_set_root(const char* argv0, const char* root);
|
||||
extern int vfs_mount(const char* path);
|
||||
extern int vfs_umount(const char* path);
|
||||
|
||||
extern Handle vfs_map(const char* fn); // actual path in real FS
|
||||
extern int vfs_stat(const char* fn, struct stat *buffer);
|
||||
extern int vfs_realpath(const char* fn, char* realpath);
|
||||
|
||||
extern int vfs_access( char* fn );
|
||||
extern int vfs_stat( const char* fn, struct stat *buffer );
|
||||
extern Handle vfs_load(const char* fn, void*& p, size_t& size, bool dont_map = false);
|
||||
|
||||
extern Handle vfs_open(const char* fn);
|
||||
extern int vfs_close(Handle h);
|
||||
|
||||
// size: in - maximum byte count
|
||||
// out - bytes actually read
|
||||
extern int vfs_read(Handle h, void*& p, size_t& size, size_t ofs = 0);
|
||||
|
||||
extern u32 vfs_start_read(Handle hf, size_t& ofs, void** buf = 0);
|
||||
extern int vfs_finish_read(u32 slot, void*& p, size_t& size);
|
||||
extern int vfs_finish_read(u32 slot, void*& p, size_t& size);
|
||||
|
||||
#endif // #ifndef __VFS_H__
|
@ -14,7 +14,7 @@
|
||||
#include "tex.h"
|
||||
#include "vfs.h"
|
||||
#include "ia32.h"
|
||||
#include "Config.h"
|
||||
#include "ps/Config.h"
|
||||
|
||||
#ifndef NO_GUI
|
||||
#include "gui/GUI.h"
|
||||
|
@ -61,11 +61,10 @@ PS_RESULT CConfig::Register( CStr Filename, void* Data, LoaderFunction DynamicLo
|
||||
|
||||
// Might as well check we can find the thing.
|
||||
char filepath[PATH_MAX];
|
||||
strcpy( filepath, Filename );
|
||||
|
||||
if( vfs_access( filepath ) ) // This changes filepath to the disk location
|
||||
// of the file, if we know it, to speed up
|
||||
// checks later.
|
||||
if( vfs_realpath( Filename, filepath ) ) // This changes filepath to the disk location
|
||||
// of the file, if we know it, to speed up
|
||||
// checks later.
|
||||
{
|
||||
if( m_LogFile )
|
||||
{
|
||||
@ -127,8 +126,7 @@ PS_RESULT CConfig::Update()
|
||||
// Find its new path and copy it back to the data we maintain
|
||||
// here to speed up future queries.
|
||||
char filepath[PATH_MAX];
|
||||
strcpy( filepath, i->Filename );
|
||||
vfs_access( filepath );
|
||||
vfs_realpath( i->Filename, filepath );
|
||||
if( m_LogFile )
|
||||
{
|
||||
CStr Report = _T( "File " );
|
||||
@ -212,8 +210,7 @@ PS_RESULT CConfig::ReloadAll()
|
||||
// We can't find the file. Seeing as this should reload everything,
|
||||
// check that it exists.
|
||||
char filepath[PATH_MAX];
|
||||
strcpy( filepath, i->Filename );
|
||||
if( vfs_access( filepath ) )
|
||||
if( vfs_realpath( i->Filename, filepath ) )
|
||||
{
|
||||
// Oops.
|
||||
notfound++;
|
||||
@ -237,8 +234,7 @@ PS_RESULT CConfig::ReloadAll()
|
||||
// Find its new path and copy it back to the data we maintain
|
||||
// here to speed up future queries.
|
||||
char filepath[PATH_MAX];
|
||||
strcpy( filepath, i->Filename );
|
||||
vfs_access( filepath );
|
||||
vfs_realpath( i->Filename, filepath );
|
||||
if( m_LogFile )
|
||||
{
|
||||
CStr Report = _T( "File " );
|
||||
|
@ -52,9 +52,9 @@ TDD at http://forums.wildfiregames.com/0ad
|
||||
#include "Singleton.h"
|
||||
#include "CStr.h"
|
||||
#include "LogFile.h"
|
||||
#include "..\lib\posix.h"
|
||||
#include "..\lib\unzip.h"
|
||||
#include "..\lib\misc.h"
|
||||
#include "posix.h"
|
||||
#include "zip.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "Terrain.H"
|
||||
#include "tex.h"
|
||||
#include "mem.h"
|
||||
|
||||
bool g_HillShading = true;
|
||||
|
||||
@ -46,7 +47,9 @@ TEX tex;
|
||||
Handle h = tex_load(filename, &tex);
|
||||
if(!h)
|
||||
return false;
|
||||
const u8* data = tex.ptr;
|
||||
Handle hm = tex.hm;
|
||||
MEM* mem = (MEM*)h_user_data(hm, H_MEM);
|
||||
const u8* data = (const u8*)mem->p;
|
||||
|
||||
m_pVertices = new STerrainVertex[MAP_SIZE*MAP_SIZE];
|
||||
if (m_pVertices == NULL)
|
||||
|
@ -299,14 +299,6 @@ SOURCE=..\lib\types.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\lib\unzip.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\lib\unzip.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\lib\vfs.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -325,6 +317,14 @@ SOURCE=..\lib\wsdl.cpp
|
||||
|
||||
SOURCE=..\lib\wsdl.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\lib\zip.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\lib\zip.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "ps"
|
||||
|
||||
@ -335,6 +335,14 @@ SOURCE=..\ps\BaseEntity.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\ps\Config.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\ps\Config.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\ps\CStr.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -8,4 +8,14 @@ Known problems:
|
||||
Ultimately the xml file reading's root dir should be
|
||||
binaries/ too.
|
||||
|
||||
/Gee
|
||||
/Gee
|
||||
|
||||
Known solution :))
|
||||
- I put the GUI init code before VFS init (which changes the dir
|
||||
as you mention to binaries/data), so that it'd work as you had it.
|
||||
When you're ready, just move all data to binaries/data, move
|
||||
the GUI init after vfs_set_root in main.cpp, and we're go.
|
||||
|
||||
p.s. we only need .vsproj and .sln in CVS; .ncb is built by VC.
|
||||
|
||||
janwas
|
@ -225,6 +225,10 @@
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="..\ps\BaseEntity.h"/>
|
||||
<File
|
||||
RelativePath="..\ps\Config.cpp"/>
|
||||
<File
|
||||
RelativePath="..\ps\Config.h"/>
|
||||
<File
|
||||
RelativePath="..\ps\CStr.cpp"/>
|
||||
<File
|
||||
@ -309,10 +313,6 @@
|
||||
RelativePath="..\lib\time.h"/>
|
||||
<File
|
||||
RelativePath="..\lib\types.h"/>
|
||||
<File
|
||||
RelativePath="..\lib\unzip.cpp"/>
|
||||
<File
|
||||
RelativePath="..\lib\unzip.h"/>
|
||||
<File
|
||||
RelativePath="..\lib\vfs.cpp"/>
|
||||
<File
|
||||
@ -323,6 +323,10 @@
|
||||
RelativePath="..\lib\wsdl.cpp"/>
|
||||
<File
|
||||
RelativePath="..\lib\wsdl.h"/>
|
||||
<File
|
||||
RelativePath="..\lib\zip.cpp"/>
|
||||
<File
|
||||
RelativePath="..\lib\zip.h"/>
|
||||
<Filter
|
||||
Name="posix"
|
||||
Filter="">
|
||||
|
@ -1 +0,0 @@
|
||||
Microsoft C/C++ MSF 7.00
|
Loading…
Reference in New Issue
Block a user