934a97c53e
fix q2bsp textures. fix some vulkan validation issues. MOVE_OTHERONLY is now an official feature (replacing MOVE_ONLYENT which is now removed, same functionality, better behaved behaviour). network up edited brushes on initial connect. still needs more work for entity editing, but should otherwise be okay for now. add sys_browserredirect console command for emscripten builds (can be used to trigger window redirections - including download requests) git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5001 fc73d0e0-1445-4013-8a0c-d673dee63da5
829 lines
No EOL
21 KiB
C
829 lines
No EOL
21 KiB
C
#include "quakedef.h"
|
|
#include "fs.h"
|
|
|
|
#include <ppapi/c/pp_errors.h>
|
|
#include <ppapi/c/ppb_core.h>
|
|
#include <ppapi/c/pp_file_info.h>
|
|
#include <ppapi/c/ppb_file_system.h>
|
|
#include <ppapi/c/ppb_file_ref.h>
|
|
#include <ppapi/c/ppb_url_request_info.h>
|
|
#include <ppapi/c/ppb_url_response_info.h>
|
|
#include <ppapi/c/pp_var.h>
|
|
#include <ppapi/c/ppb_var.h>
|
|
#include <ppapi/c/ppb_file_io.h>
|
|
#include <ppapi/c/ppb_url_loader.h>
|
|
|
|
extern PPB_FileIO *ppb_fileio;
|
|
extern PPB_FileRef *ppb_fileref;
|
|
extern PPB_FileSystem *ppb_filesystem;
|
|
extern PPB_Core *ppb_core;
|
|
extern PPB_URLLoader *urlloader;
|
|
extern PPB_URLRequestInfo *urlrequestinfo;
|
|
extern PPB_URLResponseInfo *urlresponseinfo;
|
|
extern PPB_Var *ppb_var_interface;
|
|
extern PP_Instance pp_instance;
|
|
|
|
#define GOOGLE_DONT_KNOW_HOW_TO_CREATE_USABLE_APIS
|
|
#ifdef GOOGLE_DONT_KNOW_HOW_TO_CREATE_USABLE_APIS
|
|
//the pepper api is flawed. deeply flawed.
|
|
//1: api calls (including various gl calls) may only be made on the main thread).
|
|
//2: the main thread may not use non-asyncronous calls.
|
|
//the recommendation to get around this is to run everything on a worker thread, but to make calls to the main thread to do the actual call, then signal the worker thread to wake up again in the main thread's callback.
|
|
//which is impractical when you have 80+ different sorts of performance-dependant gl calls.
|
|
//I can't easily put things requiring file access on another thread, if only because it would make alias/exec console commands non-synchronous
|
|
//to get around this, I instead make my own memory-only 'filesystem', populating it at startup with downloads. I *really* hope your browser/server are set to enable file caching.
|
|
//at some point I'll periodically write the data back to a persistant store/reload it at startup so saved games/configs can work
|
|
|
|
#define FSPPAPI_OpenTemp FS_OpenTemp
|
|
#define VFSPPAPI_Open VFSOS_Open
|
|
#define FSPPAPI_OpenPath VFSOS_OpenPath
|
|
|
|
typedef struct mfchunk_s
|
|
{
|
|
struct mfchunk_s *prev;
|
|
struct mfchunk_s *next;
|
|
unsigned long startpos;
|
|
unsigned int len;
|
|
char data[64];
|
|
} mfchunk_t;
|
|
typedef struct mfile_s
|
|
{
|
|
/*chunks can be trimmed only when there's no refs*/
|
|
char name[MAX_QPATH];
|
|
int refs;
|
|
int unlinked:1;
|
|
unsigned long length;
|
|
|
|
mfchunk_t *chunkhead;
|
|
mfchunk_t *chunktail;
|
|
|
|
struct mfile_s *prev;
|
|
struct mfile_s *next;
|
|
} mfile_t;
|
|
mfile_t *mfiles;
|
|
|
|
typedef struct
|
|
{
|
|
vfsfile_t funcs;
|
|
|
|
mfile_t *file;
|
|
unsigned long offset;
|
|
mfchunk_t *cchunk;
|
|
} vfsmfile_t;
|
|
|
|
typedef struct
|
|
{
|
|
searchpathfuncs_t pub;
|
|
int depth;
|
|
char rootpath[1];
|
|
} pppath_t;
|
|
|
|
qboolean FSPPAPI_Init(int *fileid)
|
|
{
|
|
return true; /*engine has all the content it needs*/
|
|
}
|
|
|
|
static int preparechunk(vfsmfile_t *f, int bytes, void **data)
|
|
{
|
|
int sz;
|
|
mfchunk_t *cnk;
|
|
if (!bytes)
|
|
{
|
|
*data = 0;
|
|
return 0;
|
|
}
|
|
|
|
if (!f->cchunk)
|
|
cnk = f->file->chunkhead;
|
|
else
|
|
{
|
|
cnk = f->cchunk;
|
|
//rewind through the chunks
|
|
while (cnk->startpos > f->offset)
|
|
cnk = cnk->prev;
|
|
}
|
|
//find the chunk that contains our start offset
|
|
while (!cnk || cnk->startpos+cnk->len <= f->offset)
|
|
{
|
|
if (!cnk)
|
|
{
|
|
sz = (bytes + sizeof(*cnk) - sizeof(cnk->data) + 4095) & ~4095;
|
|
if (sz < 65536)
|
|
sz = 65536;
|
|
cnk = malloc(sz);
|
|
memset(cnk, 0xcc, sz);
|
|
if (!cnk)
|
|
{
|
|
*data = 0;
|
|
return 0;
|
|
}
|
|
cnk->len = (sz + sizeof(cnk->data) - sizeof(*cnk));
|
|
cnk->next = NULL;
|
|
if (f->file->chunktail)
|
|
{
|
|
cnk->prev = f->file->chunktail;
|
|
cnk->prev->next = cnk;
|
|
cnk->startpos = cnk->prev->startpos + cnk->prev->len;
|
|
}
|
|
else
|
|
{
|
|
f->file->chunkhead = cnk;
|
|
cnk->prev = NULL;
|
|
cnk->startpos = 0;
|
|
}
|
|
// Sys_Printf("Allocated chunk %p: %u-%u\n", cnk, cnk->startpos, cnk->startpos + cnk->len);
|
|
f->file->chunktail = cnk;
|
|
}
|
|
else
|
|
cnk = cnk->next;
|
|
}
|
|
|
|
// Sys_Printf("Returning offset %p, %i\n", cnk, (f->offset - cnk->startpos));
|
|
// Sys_Printf("%u %u\n", f->offset, cnk->startpos);
|
|
|
|
*data = cnk->data + (f->offset - cnk->startpos);
|
|
f->cchunk = cnk;
|
|
|
|
sz = cnk->startpos + cnk->len - f->offset;
|
|
if (sz > bytes)
|
|
{
|
|
// Sys_Printf("Returning len %u\n", bytes);
|
|
return bytes;
|
|
}
|
|
// Sys_Printf("Returning len %u\n", sz);
|
|
return sz;
|
|
|
|
}
|
|
|
|
static int VFSMEM_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
|
|
{
|
|
int total = 0;
|
|
int chunklen;
|
|
void *chunkdat;
|
|
vfsmfile_t *f = (vfsmfile_t*)file;
|
|
|
|
if (bytestoread > f->file->length - f->offset)
|
|
bytestoread = f->file->length - f->offset;
|
|
|
|
while ((chunklen = preparechunk(f, bytestoread, &chunkdat)) > 0)
|
|
{
|
|
// Sys_Printf("Read %i at %u\n", chunklen, f->offset);
|
|
memcpy(buffer, chunkdat, chunklen);
|
|
buffer = (char*)buffer + chunklen;
|
|
bytestoread -= chunklen;
|
|
total += chunklen;
|
|
f->offset += chunklen;
|
|
}
|
|
|
|
// Sys_Printf("%s", (char*)buffer-total);
|
|
return total;
|
|
}
|
|
static int VFSMEM_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestoread)
|
|
{
|
|
int total = 0;
|
|
int chunklen;
|
|
void *chunkdat;
|
|
vfsmfile_t *f = (vfsmfile_t*)file;
|
|
|
|
while ((chunklen = preparechunk(f, bytestoread, &chunkdat)) > 0)
|
|
{
|
|
// Sys_Printf("Write %i at %u\n", chunklen, f->offset);
|
|
memcpy(chunkdat, buffer, chunklen);
|
|
buffer = (char*)buffer + chunklen;
|
|
bytestoread -= chunklen;
|
|
total += chunklen;
|
|
f->offset += chunklen;
|
|
}
|
|
|
|
if (f->file->length < f->offset)
|
|
f->file->length = f->offset;
|
|
|
|
// Sys_Printf("written: %i, file is now at %i\n", total, f->offset);
|
|
return total;
|
|
}
|
|
static qboolean VFSMEM_Seek (struct vfsfile_s *file, qofs_t pos)
|
|
{
|
|
vfsmfile_t *f = (vfsmfile_t*)file;
|
|
f->offset = pos;
|
|
return true;
|
|
}
|
|
static qofs_t VFSMEM_Tell (struct vfsfile_s *file)
|
|
{
|
|
vfsmfile_t *f = (vfsmfile_t*)file;
|
|
return f->offset;
|
|
}
|
|
static qofs_t VFSMEM_GetSize (struct vfsfile_s *file)
|
|
{
|
|
vfsmfile_t *f = (vfsmfile_t*)file;
|
|
return f->file->length;
|
|
}
|
|
static void FSPPAPI_DoUnlink(mfile_t *file)
|
|
{
|
|
mfchunk_t *cnk;
|
|
//must have no lingering references.
|
|
|
|
//free any file chunks.
|
|
while (file->chunkhead)
|
|
{
|
|
cnk = file->chunkhead->next;
|
|
free(file->chunkhead);
|
|
file->chunkhead = cnk;
|
|
}
|
|
//unlink the file so nothing else is harmed
|
|
if (file->prev)
|
|
file->prev->next = file->next;
|
|
else if (file == mfiles)
|
|
mfiles = file->next;
|
|
if (file->next)
|
|
file->next->prev = file->prev;
|
|
//and finally free the last bit of memory.
|
|
free(file);
|
|
}
|
|
static void VFSMEM_Close(vfsfile_t *file)
|
|
{
|
|
vfsmfile_t *f = (vfsmfile_t*)file;
|
|
f->file->refs -= 1;
|
|
if (!f->file->refs)
|
|
if (f->file->unlinked)
|
|
FSPPAPI_DoUnlink(f->file);
|
|
free(f);
|
|
}
|
|
static void VFSMEM_Flush(struct vfsfile_s *file)
|
|
{
|
|
// vfsmfile_t *f = (vfsmfile_t*)file;
|
|
}
|
|
|
|
|
|
vfsfile_t *FSPPAPI_OpenTemp(void)
|
|
{
|
|
/*create a file which is already unlinked*/
|
|
mfile_t *f;
|
|
vfsmfile_t *r;
|
|
f = malloc(sizeof(*f));
|
|
if (!f)
|
|
return NULL;
|
|
|
|
strcpy(f->name, "some temp file");
|
|
f->refs = 0;
|
|
f->unlinked = true;
|
|
f->length = 0;
|
|
f->next = NULL;
|
|
f->prev = NULL;
|
|
f->chunkhead = NULL;
|
|
f->chunktail = NULL;
|
|
|
|
r = malloc(sizeof(*r));
|
|
if (!r)
|
|
return NULL;
|
|
r->file = f;
|
|
r->offset = 0;
|
|
r->cchunk = NULL;
|
|
f->refs++;
|
|
|
|
r->funcs.ReadBytes = VFSMEM_ReadBytes;
|
|
r->funcs.WriteBytes = VFSMEM_WriteBytes;
|
|
r->funcs.Seek = VFSMEM_Seek;
|
|
r->funcs.Tell = VFSMEM_Tell;
|
|
r->funcs.GetLen = VFSMEM_GetSize;
|
|
r->funcs.Close = VFSMEM_Close;
|
|
r->funcs.Flush = VFSMEM_Flush;
|
|
|
|
return &r->funcs;
|
|
}
|
|
|
|
qboolean Sys_remove (char *path)
|
|
{
|
|
mfile_t *f;
|
|
for (f = mfiles; f; f = f->next)
|
|
{
|
|
if (!strcmp(f->name, path))
|
|
{
|
|
if (!f->refs)
|
|
FSPPAPI_DoUnlink(f);
|
|
else
|
|
f->unlinked = true; //can't delete it yet, but we can orphan it so we can kill it later.
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
qboolean Sys_Rename (char *oldfname, char *newfname)
|
|
{
|
|
mfile_t *f;
|
|
for (f = mfiles; f; f = f->next)
|
|
{
|
|
if (!strcmp(f->name, oldfname))
|
|
{
|
|
Q_strncpyz(f->name, newfname, sizeof(f->name));
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
//no concept of directories.
|
|
void Sys_mkdir (char *path)
|
|
{
|
|
}
|
|
|
|
vfsfile_t *VFSPPAPI_Open(const char *osname, const char *mode)
|
|
{
|
|
mfile_t *f;
|
|
vfsmfile_t *r;
|
|
|
|
if (strlen(osname) >= sizeof(f->name)) //yay strcpy!
|
|
return NULL;
|
|
|
|
for (f = mfiles; f; f = f->next)
|
|
{
|
|
if (!strcmp(f->name, osname))
|
|
break;
|
|
}
|
|
if (!f && (*mode == 'w' || *mode == 'a'))
|
|
{
|
|
f = malloc(sizeof(*f));
|
|
if (f)
|
|
{
|
|
strcpy(f->name, osname);
|
|
f->refs = 0;
|
|
f->unlinked = false;
|
|
f->length = 0;
|
|
f->next = mfiles;
|
|
f->prev = NULL;
|
|
if (mfiles)
|
|
mfiles->prev = f;
|
|
mfiles = f;
|
|
f->chunkhead = NULL;
|
|
f->chunktail = NULL;
|
|
}
|
|
}
|
|
if (!f)
|
|
return NULL;
|
|
|
|
r = malloc(sizeof(*r));
|
|
if (!r)
|
|
return NULL;
|
|
r->file = f;
|
|
r->offset = 0;
|
|
r->cchunk = NULL;
|
|
f->refs++;
|
|
|
|
r->funcs.ReadBytes = VFSMEM_ReadBytes;
|
|
r->funcs.WriteBytes = VFSMEM_WriteBytes;
|
|
r->funcs.Seek = VFSMEM_Seek;
|
|
r->funcs.Tell = VFSMEM_Tell;
|
|
r->funcs.GetLen = VFSMEM_GetSize;
|
|
r->funcs.Close = VFSMEM_Close;
|
|
r->funcs.Flush = VFSMEM_Flush;
|
|
|
|
return &r->funcs;
|
|
}
|
|
|
|
static vfsfile_t *FSPPAPI_OpenVFS(searchpathfuncs_t *handle, flocation_t *loc, const char *mode)
|
|
{
|
|
pppath_t *sp = (void*)handle;
|
|
char diskname[MAX_OSPATH];
|
|
|
|
//path is already cleaned, as anything that gets a valid loc needs cleaning up first.
|
|
|
|
snprintf(diskname, sizeof(diskname), "%s/%s", sp->rootpath, loc->rawname);
|
|
|
|
return VFSPPAPI_Open(diskname, mode);
|
|
}
|
|
|
|
static void FSPPAPI_ClosePath(searchpathfuncs_t *handle)
|
|
{
|
|
Z_Free(handle);
|
|
}
|
|
|
|
int Sys_EnumerateFiles (const char *rootpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
|
|
{
|
|
int rootlen = strlen(rootpath);
|
|
char *sub;
|
|
mfile_t *f;
|
|
if (*match == '/')
|
|
match++;
|
|
for (f = mfiles; f; f = f->next)
|
|
{
|
|
sub = f->name;
|
|
if (strncmp(sub, rootpath, rootlen))
|
|
continue;
|
|
sub += rootlen;
|
|
if (*sub == '/')
|
|
sub++;
|
|
if (wildcmp(match, sub))
|
|
{
|
|
if (!func(sub, f->length, (time_t)0, parm, spath))
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
static int FSPPAPI_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm)
|
|
{
|
|
pppath_t *sp = (void*)handle;
|
|
return Sys_EnumerateFiles(sp->rootpath, match, func, parm, handle);
|
|
}
|
|
|
|
static int FSPPAPI_RebuildFSHash(const char *filename, qofs_t filesize, void *data, searchpathfuncs_t *handle)
|
|
{
|
|
pppath_t *sp = (void*)handle;
|
|
void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle) = data;
|
|
if (filename[strlen(filename)-1] == '/')
|
|
{ //this is actually a directory
|
|
|
|
char childpath[256];
|
|
Q_snprintfz(childpath, sizeof(childpath), "%s*", filename);
|
|
Sys_EnumerateFiles(sp->rootpath, childpath, FSPPAPI_RebuildFSHash, data, handle);
|
|
return true;
|
|
}
|
|
AddFileHash(0, filename, NULL, handle);
|
|
return true;
|
|
}
|
|
static void FSPPAPI_BuildHash(searchpathfuncs_t *handle, int depth, void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle))
|
|
{
|
|
pppath_t *sp = (void*)handle;
|
|
Sys_EnumerateFiles(sp->rootpath, "*", FSPPAPI_RebuildFSHash, AddFileHash, handle);
|
|
}
|
|
|
|
static qboolean FSPPAPI_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult)
|
|
{
|
|
pppath_t *sp = (void*)handle;
|
|
int len;
|
|
char netpath[MAX_OSPATH];
|
|
|
|
if (hashedresult && (void *)hashedresult != handle)
|
|
return false;
|
|
|
|
/*
|
|
if (!static_registered)
|
|
{ // if not a registered version, don't ever go beyond base
|
|
if ( strchr (filename, '/') || strchr (filename,'\\'))
|
|
continue;
|
|
}
|
|
*/
|
|
|
|
// check a file in the directory tree
|
|
snprintf (netpath, sizeof(netpath)-1, "%s/%s",sp->rootpath, filename);
|
|
|
|
{
|
|
vfsfile_t *f = VFSPPAPI_Open(netpath, "rb");
|
|
if (!f)
|
|
return false;
|
|
len = VFS_GETLEN(f);
|
|
VFS_CLOSE(f);
|
|
}
|
|
|
|
if (loc)
|
|
{
|
|
loc->len = len;
|
|
loc->offset = 0;
|
|
loc->index = 0;
|
|
Q_strncpyz(loc->rawname, filename, sizeof(loc->rawname));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
static void FSPPAPI_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, char *buffer)
|
|
{
|
|
vfsfile_t *f;
|
|
size_t result;
|
|
|
|
f = VFSPPAPI_Open(loc->rawname, "rb");
|
|
if (!f) //err...
|
|
return;
|
|
VFS_SEEK(f, loc->offset);
|
|
result = VFS_READ(f, buffer, loc->len);
|
|
|
|
if (result != loc->len)
|
|
Con_Printf("FSPPAPI_ReadFile() fread: Filename: %s, expected %i, result was %u\n",loc->rawname,loc->len,(unsigned int)result);
|
|
|
|
VFS_CLOSE(f);
|
|
}
|
|
|
|
searchpathfuncs_t *QDECL FSPPAPI_OpenPath(vfsfile_t *mustbenull, const char *desc, const char *prefix)
|
|
{
|
|
pppath_t *np;
|
|
int dlen = strlen(desc);
|
|
if (mustbenull)
|
|
return NULL;
|
|
if (prefix && *prefix)
|
|
return NULL; //don't try to support this. too risky with absolute paths etc.
|
|
np = Z_Malloc(sizeof(*np) + dlen);
|
|
if (np)
|
|
{
|
|
np->depth = 0;
|
|
memcpy(np->rootpath, desc, dlen+1);
|
|
}
|
|
|
|
np->pub.fsver = FSVER;
|
|
np->pub.ClosePath = FSPPAPI_ClosePath;
|
|
np->pub.BuildHash = FSPPAPI_BuildHash;
|
|
np->pub.FindFile = FSPPAPI_FLocate;
|
|
np->pub.ReadFile = FSPPAPI_ReadFile;
|
|
np->pub.EnumerateFiles = FSPPAPI_EnumerateFiles;
|
|
np->pub.OpenVFS = FSPPAPI_OpenVFS;
|
|
//np->pub.PollChanges = FSPPAPI_PollChanges;
|
|
return &np->pub;
|
|
}
|
|
|
|
#else
|
|
|
|
//this code is old and won't work.
|
|
|
|
#define FSPPAPI_OpenTemp FS_OpenTemp
|
|
#define VFSPPAPI_Open VFSOS_Open
|
|
|
|
extern PPB_FileIO *ppb_fileio;
|
|
extern PPB_FileRef *ppb_fileref;
|
|
extern PPB_FileSystem *ppb_filesystem;
|
|
extern PPB_Core *ppb_core;
|
|
extern PP_Instance pp_instance;
|
|
static PP_Resource mainfilesystem;
|
|
|
|
|
|
struct PP_CompletionCallback nullccb;
|
|
|
|
void FSPPAPI_Init(void)
|
|
{
|
|
mainfilesystem = ppb_filesystem->Create(pp_instance, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
|
|
ppb_filesystem->Open(mainfilesystem, 100*1024*1024, nullccb);
|
|
}
|
|
|
|
typedef struct {
|
|
vfsfile_t funcs;
|
|
PP_Resource handle;
|
|
int64_t offset;
|
|
} vfsppapifile_t;
|
|
static int VFSPPAPI_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
|
|
{
|
|
int res;
|
|
vfsppapifile_t *intfile = (vfsppapifile_t*)file;
|
|
|
|
res = ppb_fileio->Read(intfile->handle, intfile->offset, buffer, bytestoread, nullccb);
|
|
if (res > 0)
|
|
intfile->offset += res;
|
|
return res;
|
|
}
|
|
static int VFSPPAPI_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestoread)
|
|
{
|
|
int res;
|
|
vfsppapifile_t *intfile = (vfsppapifile_t*)file;
|
|
res = ppb_fileio->Write(intfile->handle, intfile->offset, buffer, bytestoread, nullccb);
|
|
if (res > 0)
|
|
intfile->offset += res;
|
|
return res;
|
|
}
|
|
static qboolean VFSPPAPI_Seek (struct vfsfile_s *file, qofs_t pos)
|
|
{
|
|
vfsppapifile_t *intfile = (vfsppapifile_t*)file;
|
|
intfile->offset = pos;
|
|
return true;
|
|
}
|
|
static qofs_t VFSPPAPI_Tell (struct vfsfile_s *file)
|
|
{
|
|
vfsppapifile_t *intfile = (vfsppapifile_t*)file;
|
|
return intfile->offset;
|
|
}
|
|
static void VFSPPAPI_Flush(struct vfsfile_s *file)
|
|
{
|
|
vfsppapifile_t *intfile = (vfsppapifile_t*)file;
|
|
ppb_fileio->Flush(intfile->handle, nullccb);
|
|
}
|
|
static qofs_t VFSPPAPI_GetSize (struct vfsfile_s *file)
|
|
{
|
|
vfsppapifile_t *intfile = (vfsppapifile_t*)file;
|
|
struct PP_FileInfo fileinfo;
|
|
|
|
fileinfo.size = 0;
|
|
ppb_fileio->Query(intfile->handle, &fileinfo, nullccb);
|
|
return fileinfo.size;
|
|
}
|
|
static void VFSPPAPI_Close(vfsfile_t *file)
|
|
{
|
|
vfsppapifile_t *intfile = (vfsppapifile_t*)file;
|
|
ppb_fileio->Close(intfile->handle);
|
|
ppb_core->ReleaseResource(intfile->handle);
|
|
Z_Free(file);
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
static void VFSPPAPI_CloseTemp(vfsfile_t *file)
|
|
{
|
|
vfsppapifile_t *intfile = (vfsppapifile_t*)file;
|
|
char *fname = (char*)(intfile+1);
|
|
ppb_fileio->Close(intfile->handle);
|
|
ppb_core->ReleaseResource(intfile->handle);
|
|
/*FIXME: add the remove somewhere*/
|
|
// _unlink(fname);
|
|
Z_Free(file);
|
|
}
|
|
#endif
|
|
|
|
vfsfile_t *FSPPAPI_OpenTemp(void)
|
|
{
|
|
return NULL;
|
|
#if 0
|
|
FILE *f;
|
|
vfsppapifile_t *file;
|
|
|
|
f = tmpfile();
|
|
if (!f)
|
|
return NULL;
|
|
|
|
file = Z_Malloc(sizeof(vfsppapifile_t));
|
|
file->funcs.Close = VFSPPAPI_Close;
|
|
file->funcs.ReadBytes = VFSPPAPI_ReadBytes;
|
|
file->funcs.WriteBytes = VFSPPAPI_WriteBytes;
|
|
file->funcs.Seek = VFSPPAPI_Seek;
|
|
file->funcs.Tell = VFSPPAPI_Tell;
|
|
file->funcs.GetLen = VFSPPAPI_GetSize;
|
|
file->funcs.Flush = VFSPPAPI_Flush;
|
|
file->handle = f;
|
|
|
|
return (vfsfile_t*)file;
|
|
#endif
|
|
}
|
|
|
|
vfsfile_t *VFSPPAPI_Open(const char *osname, const char *mode)
|
|
{
|
|
int e;
|
|
PP_Resource f;
|
|
PP_Resource fsf;
|
|
vfsppapifile_t *file;
|
|
qboolean read = !!strchr(mode, 'r');
|
|
qboolean write = !!strchr(mode, 'w');
|
|
qboolean append = !!strchr(mode, 'a');
|
|
int newmode = 0;
|
|
|
|
if (read)
|
|
newmode |= PP_FILEOPENFLAG_READ;
|
|
if (write)
|
|
newmode |= PP_FILEOPENFLAG_WRITE|PP_FILEOPENFLAG_TRUNCATE|PP_FILEOPENFLAG_CREATE;
|
|
if (append)
|
|
newmode |= PP_FILEOPENFLAG_WRITE|PP_FILEOPENFLAG_CREATE;
|
|
|
|
/*should we support w+ or r+ */
|
|
|
|
fsf = ppb_fileref->Create(mainfilesystem, osname);
|
|
f = ppb_fileio->Create(pp_instance);
|
|
e = ppb_fileio->Open(f, fsf, newmode, nullccb);
|
|
ppb_core->ReleaseResource(fsf);
|
|
|
|
if (e != PP_OK)
|
|
{
|
|
Con_Printf("unable to open %s. error %i\n", osname, e);
|
|
return NULL;
|
|
}
|
|
|
|
file = Z_Malloc(sizeof(vfsppapifile_t));
|
|
file->funcs.ReadBytes = strchr(mode, 'r')?VFSPPAPI_ReadBytes:NULL;
|
|
file->funcs.WriteBytes = (strchr(mode, 'w')||strchr(mode, 'a'))?VFSPPAPI_WriteBytes:NULL;
|
|
file->funcs.Seek = VFSPPAPI_Seek;
|
|
file->funcs.Tell = VFSPPAPI_Tell;
|
|
file->funcs.GetLen = VFSPPAPI_GetSize;
|
|
file->funcs.Close = VFSPPAPI_Close;
|
|
file->funcs.Flush = VFSPPAPI_Flush;
|
|
file->handle = f;
|
|
|
|
if (append)
|
|
file->offset = VFSPPAPI_GetSize((vfsfile_t*)file);
|
|
else
|
|
file->offset = 0;
|
|
|
|
return (vfsfile_t*)file;
|
|
}
|
|
|
|
static vfsfile_t *FSPPAPI_OpenVFS(void *handle, flocation_t *loc, const char *mode)
|
|
{
|
|
char diskname[MAX_OSPATH];
|
|
|
|
//path is already cleaned, as anything that gets a valid loc needs cleaning up first.
|
|
|
|
snprintf(diskname, sizeof(diskname), "%s/%s", (char*)handle, loc->rawname);
|
|
|
|
return VFSPPAPI_Open(diskname, mode);
|
|
}
|
|
|
|
static void FSPPAPI_PrintPath(searchpathfuncs_t *handle)
|
|
{
|
|
Con_Printf("%s\n", (char*)handle);
|
|
}
|
|
static void FSPPAPI_ClosePath(searchpathfuncs_t *handle)
|
|
{
|
|
Z_Free(handle);
|
|
}
|
|
static int FSPPAPI_RebuildFSHash(const char *filename, qofs_t filesize, void *data)
|
|
{
|
|
if (filename[strlen(filename)-1] == '/')
|
|
{ //this is actually a directory
|
|
|
|
char childpath[256];
|
|
Q_snprintfz(childpath, sizeof(childpath), "%s*", filename);
|
|
Sys_EnumerateFiles((char*)data, childpath, FSPPAPI_RebuildFSHash, data);
|
|
return true;
|
|
}
|
|
if (!Hash_GetInsensative(&filesystemhash, filename))
|
|
{
|
|
bucket_t *bucket = (bucket_t*)BZ_Malloc(sizeof(bucket_t) + strlen(filename)+1);
|
|
strcpy((char *)(bucket+1), filename);
|
|
//#ifdef _WIN32
|
|
// Q_strlwr((char *)(bucket+1));
|
|
//#endif
|
|
Hash_AddInsensative(&filesystemhash, (char *)(bucket+1), data, bucket);
|
|
|
|
fs_hash_files++;
|
|
}
|
|
else
|
|
fs_hash_dups++;
|
|
return true;
|
|
}
|
|
static void FSPPAPI_BuildHash(searchpathfuncs_t *handle)
|
|
{
|
|
Sys_EnumerateFiles(handle, "*", FSPPAPI_RebuildFSHash, handle);
|
|
}
|
|
static qboolean FSPPAPI_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult)
|
|
{
|
|
int len;
|
|
char netpath[MAX_OSPATH];
|
|
|
|
Con_Printf("Locate %s\n", filename);
|
|
|
|
|
|
if (hashedresult && (void *)hashedresult != handle)
|
|
return false;
|
|
|
|
/*
|
|
if (!static_registered)
|
|
{ // if not a registered version, don't ever go beyond base
|
|
if ( strchr (filename, '/') || strchr (filename,'\\'))
|
|
continue;
|
|
}
|
|
*/
|
|
|
|
// check a file in the directory tree
|
|
snprintf (netpath, sizeof(netpath)-1, "%s/%s",(char*)handle, filename);
|
|
|
|
{
|
|
vfsfile_t *f = VFSPPAPI_Open(netpath, "rb");
|
|
if (!f)
|
|
return false;
|
|
len = VFS_GETLEN(f);
|
|
VFS_CLOSE(f);
|
|
}
|
|
|
|
if (loc)
|
|
{
|
|
loc->len = len;
|
|
loc->offset = 0;
|
|
loc->index = 0;
|
|
Q_strncpyz(loc->rawname, filename, sizeof(loc->rawname));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
static void FSPPAPI_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, char *buffer)
|
|
{
|
|
vfsfile_t *f;
|
|
size_t result;
|
|
|
|
f = VFSPPAPI_Open(loc->rawname, "rb");
|
|
if (!f) //err...
|
|
return;
|
|
VFS_SEEK(f, loc->offset);
|
|
result = VFS_READ(f, buffer, loc->len);
|
|
|
|
if (result != loc->len)
|
|
Con_Printf("FSPPAPI_ReadFile() fread: Filename: %s, expected %i, result was %u\n",loc->rawname,loc->len,(unsigned int)result);
|
|
|
|
VFS_CLOSE(f);
|
|
}
|
|
static int FSPPAPI_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (*func)(const char *, int, void *), void *parm)
|
|
{
|
|
return Sys_EnumerateFiles(handle, match, func, parm);
|
|
}
|
|
|
|
searchpathfuncs_t *QDECL FSPPAPI_OpenPath(vfsfile_t *mustbenull, const char *desc)
|
|
{
|
|
stdiopath_t *np;
|
|
int dlen = strlen(desc);
|
|
if (mustbenull)
|
|
return NULL;
|
|
np = Z_Malloc(sizeof(*np) + dlen);
|
|
if (np)
|
|
{
|
|
np->depth = 0;
|
|
memcpy(np->rootpath, desc, dlen+1);
|
|
}
|
|
|
|
np->pub.fsver = FSVER;
|
|
np->pub.ClosePath = FSPPAPI_ClosePath;
|
|
np->pub.BuildHash = FSPPAPI_BuildHash;
|
|
np->pub.FindFile = FSPPAPI_FLocate;
|
|
np->pub.ReadFile = FSPPAPI_ReadFile;
|
|
np->pub.EnumerateFiles = FSPPAPI_EnumerateFiles;
|
|
np->pub.OpenVFS = FSPPAPI_OpenVFS;
|
|
//np->pub.PollChanges = FSPPAPI_PollChanges;
|
|
return &np->pub;
|
|
}
|
|
|
|
#endif |