mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-29 15:12:19 +00:00
484e8bbfc2
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6). tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly. rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents. qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate). rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan. ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released! reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming. fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation. fixed ogg decoder to retain sync properly if seeked. updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?) r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing. added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc. added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is. fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded. fixed potential crash inside runclientphys. experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server. browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server). updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar). git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
834 lines
No EOL
21 KiB
C
834 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 qboolean 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);
|
|
return true;
|
|
}
|
|
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 (const 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 (const char *oldfname, const 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 (const char *path)
|
|
{
|
|
}
|
|
qboolean Sys_rmdir (const char *path)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
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, time_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, time_t time, 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->fhandle = 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,(int)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 |