diff --git a/source/lib/lib.cpp b/source/lib/lib.cpp
index 609ed40eac..7e2700bf7d 100755
--- a/source/lib/lib.cpp
+++ b/source/lib/lib.cpp
@@ -36,7 +36,7 @@
// - call atexit (our exit handler would be called before its handler,
// so we may have shut down something important already).
-const int MAX_EXIT_FUNCS = 32;
+const int MAX_EXIT_FUNCS = 64;
static struct ExitFunc
diff --git a/source/lib/lib.h b/source/lib/lib.h
index 051258767b..ee28f46731 100755
--- a/source/lib/lib.h
+++ b/source/lib/lib.h
@@ -51,18 +51,24 @@ STMT(\
STMT(\
int err = (int)(func);\
if(err < 0)\
+ {\
+ assert(0 && "FYI: CHECK_ERR reports that a function failed."\
+ "feel free to ignore or suppress this warning.");\
return err;\
+ }\
)
enum LibError
{
- ERR_INVALID_HANDLE = -1000,
- ERR_NO_MEM = -1001,
- ERR_EOF = -1002, // attempted to read beyond EOF
- ERR_INVALID_PARAM = -1003,
- ERR_FILE_NOT_FOUND = -1004,
- ERR_PATH_NOT_FOUND = -1005,
+ ERR_INVALID_HANDLE = -1000,
+ ERR_NO_MEM = -1001,
+ ERR_EOF = -1002, // attempted to read beyond EOF
+ ERR_INVALID_PARAM = -1003,
+ ERR_FILE_NOT_FOUND = -1004,
+ ERR_PATH_NOT_FOUND = -1005,
+
+ ERR_VFS_PATH_LENGTH = -1006,
ERR_LAST
};
diff --git a/source/lib/res/file.cpp b/source/lib/res/file.cpp
index 976c430ff4..9f46ec48af 100755
--- a/source/lib/res/file.cpp
+++ b/source/lib/res/file.cpp
@@ -162,6 +162,10 @@ typedef DirEnts::iterator DirEntsIt;
static bool dirent_less(DirEnt& d1, DirEnt& d2)
{ return d1.name.compare(d2.name) < 0; }
+// rationale: we pass the directory entry name only to the callback -
+// not the absolute path, nor
prepended. some users don't need it,
+// and would need to strip it. this routine generates the absolute path,
+// but in native form - can't use that.
int file_enum(const char* dir, FileCB cb, uintptr_t user)
{
char n_path[PATH_MAX+1];
diff --git a/source/lib/res/file.h b/source/lib/res/file.h
index 16d1e4336f..6e244b2fc4 100755
--- a/source/lib/res/file.h
+++ b/source/lib/res/file.h
@@ -68,6 +68,7 @@ extern int file_set_root_dir(const char* argv0, const char* root);
typedef int(*FileCB)(const char* name, uint flags, ssize_t size, uintptr_t user);
+// not recursive - only the files in !
extern int file_enum(const char* dir, FileCB cb, uintptr_t user);
extern int file_stat(const char* path, struct stat*);
diff --git a/source/lib/res/h_mgr.cpp b/source/lib/res/h_mgr.cpp
index 986453502d..1dd00f6611 100755
--- a/source/lib/res/h_mgr.cpp
+++ b/source/lib/res/h_mgr.cpp
@@ -78,7 +78,7 @@ cassert(IDX_BITS + TAG_BITS <= sizeof(Handle)*CHAR_BIT);
// return the handle's index field (always non-negative).
// no error checking!
static inline u32 h_idx(const Handle h)
-{ return (u32)((h >> IDX_SHIFT) & IDX_MASK); }
+{ return (u32)((h >> IDX_SHIFT) & IDX_MASK) - 1; }
// return the handle's tag field.
// no error checking!
@@ -86,14 +86,15 @@ static inline u32 h_tag(const Handle h)
{ return (u32)((h >> TAG_SHIFT) & TAG_MASK); }
// build a handle from index and tag
-static inline Handle handle(const u32 idx, const u32 tag)
+static inline Handle handle(const u32 _idx, const u32 tag)
{
+ const u32 idx = _idx+1;
assert(idx <= IDX_MASK && tag <= TAG_MASK && "handle: idx or tag too big");
// somewhat clunky, but be careful with the shift:
// *_SHIFT may be larger than its field's type.
- Handle _idx = idx & IDX_MASK; _idx <<= IDX_SHIFT;
- Handle _tag = tag & TAG_MASK; _tag <<= TAG_SHIFT;
- return _idx | _tag;
+ Handle h_idx = idx & IDX_MASK; h_idx <<= IDX_SHIFT;
+ Handle h_tag = tag & TAG_MASK; h_tag <<= TAG_SHIFT;
+ return h_idx | h_tag;
}
@@ -119,9 +120,10 @@ cassert(REF_BITS + TYPE_BITS <= IDX_BITS);
// and array page usage).
static const size_t HDATA_USER_SIZE = 48;
-static const size_t HDATA_MAX_PATH = 64;
+///static const size_t HDATA_MAX_PATH = 64;
// 64 bytes
+// TODO: not anymore, fix later
struct HDATA
{
uintptr_t key;
@@ -132,7 +134,7 @@ struct HDATA
u8 user[HDATA_USER_SIZE];
- char fn[HDATA_MAX_PATH];
+ const char* fn;
};
@@ -363,7 +365,7 @@ int h_free(Handle& h, H_Type type)
// any further params are passed to type's init routine
Handle h_alloc(H_Type type, const char* fn, uint flags, ...)
{
- ONCE(atexit(cleanup));
+ ONCE(atexit2(cleanup));
Handle err;
@@ -437,6 +439,20 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...)
hd->type = type;
Handle h = handle(idx, tag);
+// regular filename
+hd->fn = 0;
+if(!(flags & RES_KEY))
+{
+ if(fn)
+ {
+ const size_t fn_len = strlen(fn);
+ hd->fn = (const char*)malloc(fn_len+1);
+ strcpy((char*)hd->fn, fn);
+ }
+}
+
+
+
H_VTbl* vtbl = type;
va_list args;
@@ -476,7 +492,6 @@ const char* h_filename(const Handle h)
return hd? hd->fn : 0;
}
-
int h_reload(const char* fn)
{
if(!fn)
diff --git a/source/lib/res/h_mgr.h b/source/lib/res/h_mgr.h
index d441556e11..2d685cbb57 100755
--- a/source/lib/res/h_mgr.h
+++ b/source/lib/res/h_mgr.h
@@ -181,6 +181,8 @@ extern void* h_user_data(Handle h, H_Type type);
extern const char* h_filename(Handle h);
+extern int h_reload(const char* fn);
+
extern int res_cur_scope;
#ifdef __cplusplus
diff --git a/source/lib/res/tex.cpp b/source/lib/res/tex.cpp
index 2b7b43efda..61834e3d61 100755
--- a/source/lib/res/tex.cpp
+++ b/source/lib/res/tex.cpp
@@ -58,6 +58,8 @@ struct Tex
size_t ofs; // offset to image data in file
Handle hm; // H_MEM handle to loaded file
uint id;
+
+bool uploaded;
};
H_TYPE_DEFINE(Tex)
@@ -673,10 +675,12 @@ fail:
#endif
+
static void Tex_init(Tex* t, va_list args)
{
}
+
static void Tex_dtor(Tex* t)
{
mem_free_h(t->hm);
@@ -685,6 +689,9 @@ static void Tex_dtor(Tex* t)
}
+// HACK HACK
+static int tex_upload_t(Tex* t, int filter, int int_fmt);
+
// TEX output param is invalid if function fails
static int Tex_reload(Tex* t, const char* fn)
{
@@ -748,12 +755,16 @@ static int Tex_reload(Tex* t, const char* fn)
// TODO: check file name, go to 32 bit if wrong
}
+
uint id;
glGenTextures(1, &id);
t->id = id;
// this can't realistically fail, just note that the already_loaded
// check above assumes (id > 0) <==> texture is loaded and valid
+if(t->uploaded)
+tex_upload_t(t, 0,0);
+
return 0;
}
@@ -789,9 +800,9 @@ int tex_bind(const Handle h)
int tex_filter = GL_LINEAR;
uint tex_bpp = 32; // 16 or 32
-int tex_upload(const Handle ht, int filter, int int_fmt)
+static int tex_upload_t(Tex* t, int filter, int int_fmt)
{
- H_DEREF(ht, Tex, t);
+t->uploaded = true;
// data we will take from Tex
GLsizei w;
@@ -846,22 +857,25 @@ int tex_upload(const Handle ht, int filter, int int_fmt)
if(err)
{
- const char* fn = h_filename(ht);
+/* const char* fn = h_filename(ht);
if(!fn)
{
fn = "(could not determine filename)";
assert(0);
}
debug_out("tex_upload: %s: %s\n", fn, err);
+*/
debug_warn("tex_upload failed");
return -1;
}
- int ret = tex_bind(ht);
+// CHECK_ERR(tex_bind(ht));
// we know ht is valid (H_DEREF above), but tex_bind can
// fail in debug builds if Tex.id isn't a valid texture name
- if(ret < 0)
- return ret;
+
+
+glBindTexture(GL_TEXTURE_2D, t->id);
+// HACK HACK HACK
// set filter
if(!filter)
@@ -976,6 +990,12 @@ int tex_upload(const Handle ht, int filter, int int_fmt)
return 0;
}
+int tex_upload(const Handle ht, int filter, int int_fmt)
+{
+ H_DEREF(ht, Tex, t);
+ return tex_upload_t(t, filter, int_fmt);
+}
+
int tex_free(Handle& ht)
{
diff --git a/source/lib/res/vfs.cpp b/source/lib/res/vfs.cpp
index b43cd6ea6a..45b97ac42d 100755
--- a/source/lib/res/vfs.cpp
+++ b/source/lib/res/vfs.cpp
@@ -1,7 +1,7 @@
// virtual file system - transparent access to files in archives;
-// allows multiple search paths
+// allows multiple mount points
//
-// Copyright (c) 2003 Jan Wassenberg
+// Copyright (c) 2004 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
@@ -28,8 +28,8 @@
#include "adts.h"
-// currently not thread safe, but that will most likely change
-// (if prefetch thread is to be used).
+// currently not thread safe. will have to change that if
+// a prefetch thread is to be used.
// not safe to call before main!
@@ -62,8 +62,6 @@
// version - that's what they're for).
-
-
///////////////////////////////////////////////////////////////////////////////
//
// path
@@ -71,24 +69,35 @@
///////////////////////////////////////////////////////////////////////////////
// path types:
-// portable (/ as directory separator; no ':' or '\\')
-// v_* : VFS
-// f_* : no path at all, filename only
+// fn : filename only, no path at all.
+// f_* : path intended directly for underlying file layer.
+// component separator is '/'; no ':' or '\\' allowed.
+// * : as above, but path within the VFS.
-static int path_append(char* dst, const char* path, const char* path2)
+// path1 and path2 may be empty, filenames, or full paths.
+static int path_append(char* dst, const char* path1, const char* path2)
{
- const size_t path_len = strlen(path);
+ const size_t path1_len = strlen(path1);
const size_t path2_len = strlen(path2);
- if(path_len+path2_len+1 > VFS_MAX_PATH)
- return -1;
+ bool need_separator = false;
+
+ size_t total_len = path1_len + path2_len + 1; // includes '\0'
+ if(path1_len > 0 && path1[path1_len-1] != '/')
+ {
+ total_len++; // for '/'
+ need_separator = true;
+ }
+
+ if(total_len+1 > VFS_MAX_PATH)
+ return ERR_VFS_PATH_LENGTH;
char* p = dst;
- strcpy(p, path);
- p += path_len;
- if(path_len > 0 && p[-1] != '/')
+ strcpy(p, path1);
+ p += path1_len;
+ if(need_separator)
*p++ = '/';
strcpy(p, path2);
return 0;
@@ -102,7 +111,7 @@ static int path_validate(const uint line, const char* const path)
const char* msg = 0; // error occurred <==> != 0
int err = -1; // pass error code to caller
- // disallow absolute path
+ // disallow absolute path for safety, in case of *nix systems.
if(path[0] == '/')
{
msg = "absolute path";
@@ -169,7 +178,6 @@ ok:
///////////////////////////////////////////////////////////////////////////////
-
// the VFS stores the location (archive or directory) of each file;
// this allows multiple search paths without having to check each one
// when opening a file (slow).
@@ -202,14 +210,12 @@ struct Loc
};
-
-
struct VDir;
typedef std::map SubDirs;
typedef SubDirs::iterator SubDirIt;
-typedef std::map Files;
+typedef std::map Files;
typedef Files::iterator FileIt;
// note: priority is accessed by following the Loc pointer.
// keeping a copy in the map would lead to better cache coherency,
@@ -223,11 +229,11 @@ struct VDir
void* watch;
- int file_add(const char* const fn, const uint pri, Loc* const loc)
+ int file_add(const char* const fn, const uint pri, const Loc* const loc)
{
std::string _fn(fn);
- typedef std::pair Ent;
+ typedef std::pair Ent;
Ent ent = std::make_pair(_fn, loc);
std::pair ret;
ret = files.insert(ent);
@@ -235,7 +241,7 @@ struct VDir
if(!ret.second)
{
FileIt it = ret.first;
- Loc*& old_loc = it->second;
+ const Loc*& old_loc = it->second;
// new Loc is of higher priority; replace pointer
if(old_loc->pri <= loc->pri)
@@ -251,7 +257,7 @@ struct VDir
return 0;
}
- Loc* file_find(const char* fn)
+ const Loc* file_find(const char* fn)
{
std::string _fn(fn);
FileIt it = files.find(_fn);
@@ -263,7 +269,7 @@ struct VDir
VDir* subdir_add(const char* name)
{
VDir* vdir = new VDir;
- std::string _name(name);
+ const std::string _name(name);
vdir->v_name = _name;
std::pair item = std::make_pair(_name, vdir);
@@ -277,15 +283,22 @@ struct VDir
return it->second;
}
- VDir* subdir_find(const char* fn)
+ VDir* subdir_find(const char* name)
{
- std::string _fn(fn);
- SubDirIt it = subdirs.find(_fn);
+ const std::string _name(name);
+ SubDirIt it = subdirs.find(_name);
if(it == subdirs.end())
return 0;
return it->second;
}
+ void subdir_clear()
+ {
+ for(SubDirIt it = subdirs.begin(); it != subdirs.end(); ++it)
+ delete(it->second);
+ subdirs.clear();
+ }
+
friend void tree_clearR(VDir*);
SubDirs subdirs; // can't make private; needed for iterator
@@ -303,11 +316,12 @@ static VDir vfs_root;
enum LookupFlags
{
- LF_DEFAULT,
+ LF_DEFAULT = 0,
LF_CREATE_MISSING_COMPONENTS = 1
};
-static int tree_lookup(const char* vfs_path, Loc** loc = 0, VDir** dir = 0, LookupFlags flags = LF_DEFAULT)
+
+static int tree_lookup(const char* vfs_path, const Loc** const loc = 0, VDir** const dir = 0, LookupFlags flags = LF_DEFAULT)
{
CHECK_PATH(vfs_path);
@@ -376,7 +390,7 @@ static void tree_clearR(VDir* const dir)
}
dir->files.clear();
- dir->subdirs.clear();
+ dir->subdir_clear();
}
@@ -386,25 +400,12 @@ static inline void tree_clear()
}
-
-
-
-
-
-
struct FileCBParams
{
VDir* dir;
- Loc* loc;
+ const Loc* loc;
};
- // somewhat of a hack. which archives are mounted into the VFS is stored
- // in an Archives list in the Mount struct; they don't have anything to
- // do with a VFS dir. we want to enumerate the archives in a dir via the
- // normal populate(), though, so have to pass this to its callback.
-
-
-
// called for each OS dir ent.
// add each file and directory to the VFS dir.
//
@@ -416,60 +417,61 @@ struct FileCBParams
// to try to open it as an archive - not good.
// this restriction also simplifies the code a bit, but if it's a problem,
// just generate a list of archives here and mount them from the caller.
-static int add_dirent_cb(const char* fn, uint flags, ssize_t size, uintptr_t user)
+static int add_dirent_cb(const char* const fn, const uint flags, const ssize_t size, const uintptr_t user)
{
- FileCBParams* params = (FileCBParams*)user;
- VDir* cur_dir = params->dir;
- Loc* cur_loc = params->loc;
+ const FileCBParams* const params = (FileCBParams*)user;
+ VDir* const cur_dir = params->dir;
+ const Loc* const cur_loc = params->loc;
// directory
if(flags & LOC_DIR)
cur_dir->subdir_add(fn);
// file
else
- cur_dir->file_add(fn, cur_loc->pri, cur_loc);
+ CHECK_ERR(cur_dir->file_add(fn, cur_loc->pri, cur_loc));
return 0;
}
-static int tree_add_dirR(VDir* vdir, const char* dir, Loc* loc)
+static int tree_add_dirR(VDir* const vdir, const char* const f_path, const Loc* const loc)
{
+ CHECK_PATH(f_path);
+
// add watch
if(!vdir->watch)
vdir->watch = 0;
- // add files and subdirs to dir
- FileCBParams params = { vdir, loc };
- file_enum(dir, add_dirent_cb, (uintptr_t)¶ms);
+ // add files and subdirs to vdir
+ const FileCBParams params = { vdir, loc };
+ file_enum(f_path, add_dirent_cb, (uintptr_t)¶ms);
for(SubDirIt it = vdir->subdirs.begin(); it != vdir->subdirs.end(); ++it)
{
- VDir* subdir = it->second;
+ VDir* const vsubdir = it->second;
- char v_subdir_path[PATH_MAX];
- const char* v_subdir_name_c = subdir->v_name.c_str();
- CHECK_ERR(path_append(v_subdir_path, dir, v_subdir_name_c));
+ char f_subdir_path[VFS_MAX_PATH];
+ const char* const v_subdir_name_c = vsubdir->v_name.c_str();
+ CHECK_ERR(path_append(f_subdir_path, f_path, v_subdir_name_c));
- tree_add_dirR(subdir, v_subdir_path, loc);
+ tree_add_dirR(vsubdir, f_subdir_path, loc);
}
return 0;
}
-static int tree_add_loc(VDir* vdir, Loc* loc)
+static int tree_add_loc(VDir* const vdir, const Loc* const loc)
{
- const char* dir = loc->dir.c_str();
-
- FileCBParams params = { vdir, loc };
-
if(loc->archive > 0)
+ {
+ FileCBParams params = { vdir, loc };
return zip_enum(loc->archive, add_dirent_cb, (uintptr_t)¶ms);
+ }
else
{
- CHECK_PATH(dir);
- return tree_add_dirR(vdir, dir, loc);
+ const char* f_path_c = loc->dir.c_str();
+ return tree_add_dirR(vdir, f_path_c, loc);
}
}
@@ -481,23 +483,43 @@ static int tree_add_loc(VDir* vdir, Loc* loc)
///////////////////////////////////////////////////////////////////////////////
-
-typedef std::vector Locs;
+// container must not invalidate iterators after insertion!
+// (we keep and pass around pointers to Mount.archive_locs elements)
+// see below.
+typedef std::list Locs;
typedef Locs::iterator LocIt;
+
struct Mount
{
- std::string vfs_mount_point;
- std::string name;
+ // mounting into this VFS directory ("" for root)
+ std::string v_path;
+
+ // what is being mounted; either directory,
+ // or archive filename (=> is_single_archive = true)
+ std::string f_name;
uint pri;
- Loc loc;
+ // storage for all Locs ensuing from this mounting.
+ // the VFS tree only holds pointers to Loc, which is why the
+ // Locs container must not invalidate its contents after adding,
+ // and also why the VFS tree must be rebuilt after unmounting something.
+ Loc dir_loc;
Locs archive_locs;
+ // if not is_single_archive, contains one Loc for every archive
+ // in the directory (but not its children - see remount()).
+ // otherwise, contains exactly one Loc for the single archive.
+
+ // is f_name an archive filename? if not, it's a directory.
+ bool is_single_archive;
Mount() {}
- Mount(const char* _vfs_mount_point, const char* _name, uint _pri)
- : vfs_mount_point(_vfs_mount_point), name(_name), pri(_pri) {}
+ Mount(const char* _v_path, const char* _f_name, uint _pri)
+ : v_path(_v_path), f_name(_f_name), pri(_pri),
+ dir_loc(0, "", 0), archive_locs(), is_single_archive(false)
+ {
+ }
};
typedef std::vector Mounts;
@@ -505,34 +527,58 @@ typedef Mounts::iterator MountIt;
static Mounts mounts;
+// support for mounting multiple archives in a directory
+// (useful for mix-in mods and patches).
+// all archives are enumerated, added to a Locs list,
+// and mounted (in alphabetical order!)
-
-// called for each OS dir ent.
-// add each archive to list.
-static int archive_cb(const char* fn, uint flags, ssize_t size, uintptr_t user)
+struct ArchiveCBParams
{
- Locs* archive_locs = (Locs*)user;
- // only add to list; don't enumerate its files yet for easier debugging
- // (we see which files are in a dir / archives)
- // also somewhat faster, due to better locality.
- //
+ // we need a full path to open the archive, and only receive
+ // the filename, so prepend this (the directory being searched).
+ const char* f_dir;
+
+ // priority at which the archive is to be mounted.
+ // specify here, instead of when actually adding the archive,
+ // because Locs are created const.
+ uint pri;
+
+ // will add one Loc to this container for
+ // every archive successfully opened.
+ Locs* archive_locs;
+};
+
+// called for each directory entry.
+// add each successfully opened archive to list.
+static int archive_cb(const char* const fn, const uint flags, const ssize_t size, const uintptr_t user)
+{
+ // not interested in subdirectories
+ if(flags & LOC_DIR)
+ return 0;
+
+ const ArchiveCBParams* const params = (ArchiveCBParams*)user;
+ const char* const f_dir = params->f_dir;
+ const uint pri = params->pri;
+ Locs* const archive_locs = params->archive_locs;
+
+ // get full path (fn is filename only)
+ char f_path[VFS_MAX_PATH];
+ CHECK_ERR(path_append(f_path, f_dir, fn));
+
// don't check filename extension - archives won't necessarily
// be called .zip (example: Quake III .pk3).
// just try to open the file.
- const Handle archive = zip_archive_open(fn);
+ const Handle archive = zip_archive_open(f_path);
if(archive > 0)
- archive_locs->push_back(Loc(archive, "", 0));
+ archive_locs->push_back(Loc(archive, "", pri));
-/// HACK HACK HACK pass along pri
-
-
- // tree_add_loc them here?
+ // only add archive to list; don't add its files into the VFS yet,
+ // to simplify debugging (we see which files are in which archive)
return 0;
}
-
// actually mount the specified entry (either Zip archive or dir).
// split out of vfs_mount because we need to mount without changing the
// mount list, when invalidating (reloading) the VFS.
@@ -540,32 +586,43 @@ static int remount(Mount& m)
{
int err;
- const char* vfs_mount_point = m.vfs_mount_point.c_str();
- const char* name = m.name.c_str();
- const uint pri = m.pri;
+ const char* const v_path = m.v_path.c_str();
+ const char* const f_name = m.f_name.c_str();
+ const uint pri = m.pri;
+ Loc& dir_loc = m.dir_loc;
+ Locs& archive_locs = m.archive_locs;
VDir* vdir;
- CHECK_ERR(tree_lookup(vfs_mount_point, 0, &vdir, LF_CREATE_MISSING_COMPONENTS));
+ CHECK_ERR(tree_lookup(v_path, 0, &vdir, LF_CREATE_MISSING_COMPONENTS));
// check if target is a single Zip archive
// order doesn't matter; can't have both an archive and dir
-
- const Handle archive = zip_archive_open(name);
+ const Handle archive = zip_archive_open(f_name);
if(archive > 0)
{
- m.archive_locs.push_back(Loc(archive, "", pri));
- LocIt it = m.archive_locs.end();
- Loc* loc = &*(--it);
+ m.is_single_archive = true;
+ archive_locs.push_back(Loc(archive, "", pri));
+ const Loc* loc = &archive_locs.front();
return tree_add_loc(vdir, loc);
}
- m.loc.dir.assign(m.name);
- err = tree_add_loc(vdir, &m.loc);
+ // enumerate all archives
+ ArchiveCBParams params = { f_name, pri, &archive_locs };
+ file_enum(f_name, archive_cb, (uintptr_t)¶ms);
+
+ for(LocIt it = archive_locs.begin(); it != archive_locs.end(); ++it)
+ {
+ const Loc* const loc = &*it;
+ tree_add_loc(vdir, loc);
+ }
+
+
+ dir_loc.dir = f_name;
+ err = tree_add_loc(vdir, &dir_loc);
if(err < 0)
err = err;
- // enumerate all archives
- return file_enum(name, archive_cb, (uintptr_t)&m.archive_locs);
+return 0;
}
@@ -582,22 +639,27 @@ static int unmount(Mount& m)
}
-static void unmount_all(void)
+static inline void unmount_all(void)
{ std::for_each(mounts.begin(), mounts.end(), unmount); }
-static void remount_all()
+static inline void remount_all()
{ std::for_each(mounts.begin(), mounts.end(), remount); }
+static void cleanup(void)
+{
+ tree_clear();
+ unmount_all();
+}
+
+
int vfs_mount(const char* const vfs_mount_point, const char* const name, const uint pri)
{
- ONCE(atexit(unmount_all));
-
- MountIt it;
+ ONCE(atexit2(cleanup));
// make sure it's not already mounted, i.e. in mounts
- for(it = mounts.begin(); it != mounts.end(); ++it)
- if(it->name == name)
+ for(MountIt it = mounts.begin(); it != mounts.end(); ++it)
+ if(it->f_name == name)
{
debug_warn("vfs_mount: already mounted");
return -1;
@@ -606,8 +668,7 @@ int vfs_mount(const char* const vfs_mount_point, const char* const name, const u
mounts.push_back(Mount(vfs_mount_point, name, pri));
// actually mount the entry
- it = mounts.end();
- Mount& m = *(--it);
+ Mount& m = mounts.back();
return remount(m);
}
@@ -626,7 +687,7 @@ int vfs_unmount(const char* name)
{
for(MountIt it = mounts.begin(); it != mounts.end(); ++it)
// found the corresponding entry
- if(it->name == name)
+ if(it->f_name == name)
{
Mount& m = *it;
unmount(m);
@@ -639,8 +700,6 @@ int vfs_unmount(const char* name)
}
-
-
///////////////////////////////////////////////////////////////////////////////
//
//
@@ -656,9 +715,15 @@ int vfs_unmount(const char* name)
// and unmounts those when needed.
+int vfs_reload(const char* fn)
+{
+ return h_reload(fn);
+}
+
+
int vfs_realpath(const char* fn, char* full_path)
{
- Loc* loc;
+ const Loc* loc;
CHECK_ERR(tree_lookup(fn, &loc));
if(loc->archive > 0)
@@ -679,7 +744,7 @@ int vfs_realpath(const char* fn, char* full_path)
int vfs_stat(const char* fn, struct stat* s)
{
- Loc* loc;
+ const Loc* loc;
CHECK_ERR(tree_lookup(fn, &loc));
if(loc->archive > 0)
@@ -774,7 +839,7 @@ static void VFile_dtor(VFile* vf)
-static int VFile_reload(VFile* vf, const char* fn)
+static int VFile_reload(VFile* vf, const char* path)
{
int& flags = vf_flags(vf);
@@ -786,15 +851,15 @@ static int VFile_reload(VFile* vf, const char* fn)
int err = -1;
- Loc* loc;
- CHECK_ERR(tree_lookup(fn, &loc));
+ const Loc* loc;
+ CHECK_ERR(tree_lookup(path, &loc));
if(loc->archive <= 0)
{
- char path[PATH_MAX];
+ char f_path[PATH_MAX];
const char* dir = loc->dir.c_str();
- CHECK_ERR(path_append(path, dir, fn));
- CHECK_ERR(file_open(path, vf_flags(vf), &vf->f));
+ CHECK_ERR(path_append(f_path, dir, path));
+ CHECK_ERR(file_open(f_path, vf_flags(vf), &vf->f));
}
else
{
@@ -804,7 +869,7 @@ static int VFile_reload(VFile* vf, const char* fn)
return -1;
}
- CHECK_ERR(zip_open(loc->archive, fn, &vf->zf));
+ CHECK_ERR(zip_open(loc->archive, path, &vf->zf));
flags |= VF_ZIP;
}
diff --git a/source/lib/res/vfs.h b/source/lib/res/vfs.h
index f9f6bb187a..eed9432f0a 100755
--- a/source/lib/res/vfs.h
+++ b/source/lib/res/vfs.h
@@ -1,7 +1,7 @@
// virtual file system - transparent access to files in archives;
-// allows multiple search paths
+// allows multiple mount points
//
-// Copyright (c) 2003 Jan Wassenberg
+// Copyright (c) 2004 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
@@ -23,7 +23,12 @@
#include "h_mgr.h"
#include "posix.h" // struct stat
-#define VFS_MAX_PATH 256 // includes trailing '\0'
+// the VFS doesn't require this length restriction - VFS internal storage
+// is not fixed-length. the purpose here is to allow fixed-sized path buffers
+// allocated on the stack.
+//
+// length includes trailing '\0'.
+#define VFS_MAX_PATH 256
extern int vfs_mount(const char* vfs_mount_point, const char* name, uint pri);
extern int vfs_umount(const char* name);
@@ -39,6 +44,11 @@ extern int vfs_close(Handle& h);
extern Handle vfs_map(Handle hf, uint flags, void*& p, size_t& size);
+extern int vfs_reload(const char* fn);
+extern int vfs_rebuild();
+
+
+
//
// async read interface
diff --git a/source/lib/res/zip.cpp b/source/lib/res/zip.cpp
index c168f9fb29..abc4a65ec2 100755
--- a/source/lib/res/zip.cpp
+++ b/source/lib/res/zip.cpp
@@ -58,6 +58,19 @@ struct ZFileLoc
};
+static inline int zip_validate(const void* const file, const size_t size)
+{
+ if(size < 2)
+ return -1;
+
+ const u8* p = (const u8*)file;
+ if(p[0] != 'P' || p[1] != 'K')
+ return -1;
+
+ return 0;
+}
+
+
// find end of central dir record in file (loaded or mapped).
static int zip_find_ecdr(const void* const file, const size_t size, const u8*& ecdr_)
{
@@ -356,7 +369,7 @@ static int lookup_add_file_cb(const uintptr_t user, const i32 idx, const char* c
ZEnt* ent = li->ents + idx;
- FnHash fn_hash = fnv_hash(fn);
+ FnHash fn_hash = fnv_hash(fn, fn_len);
(*li->idx)[fn_hash] = idx;
li->fn_hashes[idx] = fn_hash;
@@ -367,7 +380,8 @@ static int lookup_add_file_cb(const uintptr_t user, const i32 idx, const char* c
ent->fn = (const char*)malloc(fn_len+1);
if(!ent->fn)
return ERR_NO_MEM;
- strcpy((char*)ent->fn, fn);
+ strncpy((char*)ent->fn, fn, fn_len);
+ ((char*)ent->fn)[fn_len] = '\0';
ent->loc = *loc;
}
@@ -388,7 +402,14 @@ static int lookup_init(LookupInfo* const li, const void* const file, const size_
li->idx = new LookupIdx;
- return zip_enum_files(file, size, lookup_add_file_cb, (uintptr_t)li);
+ int err = zip_enum_files(file, size, lookup_add_file_cb, (uintptr_t)li);
+ if(err < 0)
+ {
+ delete li->idx;
+ return err;
+ }
+
+ return 0;
}
@@ -439,7 +460,7 @@ static int lookup_file(LookupInfo* const li, const char* const fn, i32& idx)
// return file information, given file key (from lookup_file).
static int lookup_get_file_info(LookupInfo* const li, const i32 idx, const char*& fn, ZFileLoc* const loc)
{
- if(idx < 0 || idx >= li->num_files-1)
+ if(idx < 0 || idx > li->num_files-1)
{
debug_warn("lookup_get_file_info: index out of bounds");
return -1;
@@ -524,10 +545,19 @@ static int ZArchive_reload(ZArchive* za, const char* fn)
if(err < 0)
goto exit_close;
+ // early out: check if it's even a Zip file
+ err = zip_validate(file, size);
+ if(err < 0)
+ goto exit_unmap_close;
+
err = lookup_init(&za->li, file, size);
if(err < 0)
goto exit_unmap_close;
+ // we map the file only for convenience when loading;
+ // extraction is via aio (faster, better mem use).
+ file_unmap(&za->f);
+
za->is_open = true;
return 0;
diff --git a/source/lib/res/zip.h b/source/lib/res/zip.h
index 5fdce45bde..2c5f641735 100755
--- a/source/lib/res/zip.h
+++ b/source/lib/res/zip.h
@@ -56,6 +56,7 @@ enum ZIP_CB_FLAGS
LOC_ZIP = BIT(1)
};
+// all files in archive!
typedef int(*ZipFileCB)(const char* const fn, const uint flags, const ssize_t size, const uintptr_t user);
extern int zip_enum(const Handle ha, const ZipFileCB cb, const uintptr_t user);
diff --git a/source/lib/sysdep/win/hrt.cpp b/source/lib/sysdep/win/hrt.cpp
index d825568520..1fafb2a84c 100755
--- a/source/lib/sysdep/win/hrt.cpp
+++ b/source/lib/sysdep/win/hrt.cpp
@@ -24,6 +24,9 @@
#include "detect.h"
#include "win_internal.h"
+
+// we no longer use TGT, due to issues on Win9x; GTC is just as good.
+// still need the header for the event timer (triggers periodic recalibration)
#include
// not included by win_internal due to its WIN32_LEAN_AND_MEAN define
#ifdef _MSC_VER
@@ -53,7 +56,7 @@ static i64 hrt_nominal_freq = -1;
// decide upon a HRT implementation, checking if we can work around
// each timer's issues on this platform, but allow user override
// in case there are unforeseen problems with one of them.
-// order of preference (due to resolution and speed): TSC, QPC, TGT.
+// order of preference (due to resolution and speed): TSC, QPC, GTC.
// split out of reset_impl so we can just return when impl is chosen.
static void choose_impl()
{
@@ -157,11 +160,11 @@ static void choose_impl()
#endif // QPC
//
- // TGT
+ // GTC
//
if(1)
{
- hrt_impl = HRT_TGT;
+ hrt_impl = HRT_GTC;
hrt_nominal_freq = 1000;
return;
}
@@ -202,8 +205,8 @@ static i64 ticks_lk()
// TGT
#ifdef _WIN32
- case HRT_TGT:
- t = (i64)timeGetTime();
+ case HRT_GTC:
+ t = (i64)GetTickCount();
break;
#endif
@@ -369,7 +372,7 @@ unlock();
int hrt_override_impl(HRTOverride ovr, HRTImpl impl)
{
if((ovr != HRT_DISABLE && ovr != HRT_FORCE && ovr != HRT_DEFAULT) ||
- (impl != HRT_TSC && impl != HRT_QPC && impl != HRT_TGT && impl != HRT_NONE))
+ (impl != HRT_TSC && impl != HRT_QPC && impl != HRT_GTC && impl != HRT_NONE))
{
debug_warn("hrt_override: invalid ovr or impl param");
return -1;
@@ -452,7 +455,7 @@ unlock();
// setup calibration thread
// note: winmm event is better than a thread or just checking elapsed time
-// in hrt_ticks, because it's called right after TGT is updated;
+// in hrt_ticks, because it's called right after GTC is updated;
// otherwise, we may be in the middle of a tick.
static UINT mm_event;
diff --git a/source/lib/sysdep/win/hrt.h b/source/lib/sysdep/win/hrt.h
index 78db0ead7c..a3b7dfe09d 100755
--- a/source/lib/sysdep/win/hrt.h
+++ b/source/lib/sysdep/win/hrt.h
@@ -28,8 +28,8 @@ enum HRTImpl
// Windows QueryPerformanceCounter
HRT_QPC,
- // Windows timeGetTime
- HRT_TGT,
+ // Windows GetTickCount
+ HRT_GTC,
// there will always be a valid timer in use.
// this is only used with hrt_override_impl.
diff --git a/source/main.cpp b/source/main.cpp
index 04bf2db3ad..566b1ca42a 100755
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -124,6 +124,12 @@ static bool handler(const SDL_Event& ev)
case SDLK_ESCAPE:
quit = true;
break;
+
+
+ case '1':
+ case SDLK_F1:
+ vfs_reload("art/textures/terrain/types/grass/Base1.tga");
+ break;
}
break;
@@ -216,7 +222,6 @@ static void do_tick()
-
int main(int argc, char* argv[])
{
diff --git a/source/terrain/TextureManager.cpp b/source/terrain/TextureManager.cpp
index 0cbdd22da5..0e77642afe 100755
--- a/source/terrain/TextureManager.cpp
+++ b/source/terrain/TextureManager.cpp
@@ -113,6 +113,7 @@ CTextureEntry* CTextureManager::AddTexture(const char* filename,int type)
} else {
tex_upload(h,GL_LINEAR_MIPMAP_LINEAR);
}
+
// setup texture to repeat
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);