diff --git a/engine/common/common.c b/engine/common/common.c index 59eeb13bd..80c9d14d9 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -2680,20 +2680,31 @@ void SZ_Print (sizebuf_t *buf, const char *data) //============================================================================ -char *COM_TrimString(char *str, char *buffer, int buffersize) +qboolean COM_TrimString(char *str, char *buffer, int buffersize) { int i; + if (buffersize <= 0) + { + Sys_Error("COM_TrimString: no buffer\n"); + return false; + } + while (*str <= ' ' && *str>'\0') str++; - for (i = 0; i < buffersize-1; i++) + for (i = 0; ; i++) { + if (i == buffersize-1) + { + buffer[i] = '\0'; + return false; + } if (*str <= ' ') break; buffer[i] = *str++; } buffer[i] = '\0'; - return buffer; + return true; } /* diff --git a/engine/common/common.h b/engine/common/common.h index 536ea67f6..a744998b9 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -456,7 +456,7 @@ char *COM_ParseCString (const char *data, char *out, size_t maxoutlen, size_t *w char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qboolean expandmacros, qboolean qctokenize); //fancy version used for console etc parsing #define COM_ParseToken(data,punct) COM_ParseTokenOut(data, punct, com_token, sizeof(com_token), &com_tokentype) char *COM_ParseTokenOut (const char *data, const char *punctuation, char *token, size_t tokenlen, com_tokentype_t *tokentype); //note that line endings are a special type of token. -char *COM_TrimString(char *str, char *buffer, int buffersize); +qboolean COM_TrimString(char *str, char *buffer, int buffersize); //trims leading+trailing whitespace writing to the specified buffer. returns false on truncation. const char *COM_QuotedString(const char *string, char *buf, int buflen, qboolean omitquotes); //inverse of COM_StringParse diff --git a/engine/common/fs.c b/engine/common/fs.c index 41f0b6663..49628a8f7 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -5672,7 +5672,7 @@ static qboolean FS_DirHasAPackage(char *basedir, ftemanifest_t *man) } //false stops the search (and returns that value to FS_DirHasGame) -int QDECL FS_DirDoesHaveGame(const char *fname, qofs_t fsize, time_t modtime, void *ctx, searchpathfuncs_t *subdir) +static int QDECL FS_DirDoesHaveGame(const char *fname, qofs_t fsize, time_t modtime, void *ctx, searchpathfuncs_t *subdir) { return false; } @@ -6001,7 +6001,7 @@ static qboolean FS_FoundManifest(void *usr, ftemanifest_t *man) //reads the default manifest based upon the basedir, the commandline arguments, the name of the exe, etc. //may still fail if no game was identified. //if fixedbasedir is true, stuff like -quake won't override/change the active basedir (ie: -basedir or gamedir switching without breaking gamedir) -ftemanifest_t *FS_ReadDefaultManifest(char *newbasedir, size_t newbasedirsize, qboolean fixedbasedir) +static ftemanifest_t *FS_ReadDefaultManifest(char *newbasedir, size_t newbasedirsize, qboolean fixedbasedir) { int i; int game = -1; diff --git a/engine/common/fs_stdio.c b/engine/common/fs_stdio.c index 0f4450927..f4ceb949a 100644 --- a/engine/common/fs_stdio.c +++ b/engine/common/fs_stdio.c @@ -10,6 +10,10 @@ #ifdef WEBSVONLY #define Z_Free free #define Z_Malloc malloc + #define Con_Printf printf + #define fs_readonly true + #define FS_FlushFSHashFull() + int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t modtime, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) {return 0;} #else #if !defined(_WIN32) || defined(FTE_SDL) || defined(WINRT) || defined(_XBOX) #define FSSTDIO_OpenPath VFSOS_OpenPath @@ -238,7 +242,6 @@ vfsfile_t *VFSSTDIO_Open(const char *osname, const char *mode, qboolean *needsfl return (vfsfile_t*)file; } -#ifndef WEBSVONLY #if !defined(_WIN32) || defined(FTE_SDL) || defined(WINRT) || defined(_XBOX) vfsfile_t *VFSOS_Open(const char *osname, const char *mode) { @@ -300,6 +303,9 @@ static unsigned int QDECL FSSTDIO_CreateLoc(searchpathfuncs_t *handle, flocation stdiopath_t *sp = (void*)handle; char *ofs; + if (fs_readonly) + return FF_NOTFOUND; + loc->len = 0; loc->offset = 0; loc->fhandle = handle; @@ -492,5 +498,4 @@ searchpathfuncs_t *QDECL FSSTDIO_OpenPath(vfsfile_t *mustbenull, searchpathfuncs } #endif -#endif diff --git a/engine/http/httpserver.c b/engine/http/httpserver.c index 6686eb53e..42e29ccd9 100644 --- a/engine/http/httpserver.c +++ b/engine/http/httpserver.c @@ -534,6 +534,7 @@ const char *HTTP_RunClient (HTTP_active_connections_t *cl) } else if (!stricmp(mode, "GET") || !stricmp(mode, "HEAD") || !stricmp(mode, "POST")) { + time_t timestamp = 0; qboolean gzipped = false; if (*resource != '/') { @@ -555,17 +556,23 @@ const char *HTTP_RunClient (HTTP_active_connections_t *cl) if (SV_AllowDownload(filename)) { char nbuf[MAX_OSPATH]; + flocation_t loc = {NULL}; if (cl->acceptgzip && strlen(filename) < sizeof(nbuf)-4) { Q_strncpyz(nbuf, filename, sizeof(nbuf)); Q_strncatz(nbuf, ".gz", sizeof(nbuf)); - cl->file = FS_OpenVFS(nbuf, "rb", FS_GAME); + gzipped = !!FS_FLocateFile(nbuf, FSLF_IFFOUND|FSLF_DONTREFERENCE, &loc); } - if (cl->file) - gzipped = true; else - cl->file = FS_OpenVFS(filename, "rb", FS_GAME); + gzipped = false; + if (gzipped || FS_FLocateFile(filename, FSLF_IFFOUND|FSLF_DONTREFERENCE, &loc)) + { + FS_GetLocMTime(&loc, ×tamp); + cl->file = FS_OpenReadLocation(NULL, &loc); + } + else + cl->file = NULL; } if (!cl->file) @@ -595,6 +602,7 @@ const char *HTTP_RunClient (HTTP_active_connections_t *cl) else { const char *mimeline; + char modifiedline[128]; if (strstr(resource, ".htm")) mimeline = "Content-Type: text/html\r\n"; else if (strstr(resource, ".wasm")) @@ -604,11 +612,16 @@ const char *HTTP_RunClient (HTTP_active_connections_t *cl) else mimeline = ""; + if (timestamp) + strftime(modifiedline, sizeof(modifiedline), "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n", gmtime(×tamp)); + else + *modifiedline = 0; + //fixme: add connection: keep-alive or whatever so that ie3 is happy... if (HTTPmarkup>=3) - sprintf(resource, "HTTP/1.1 200 OK\r\n" "%s%s" "Connection: %s\r\n" "Content-Length: %i\r\n" "Server: "FULLENGINENAME"/0\r\n" "\r\n", mimeline, gzipped?"Content-Encoding: gzip\r\nCache-Control: public, max-age=86400\r\n":"", cl->closeaftertransaction?"close":"keep-alive", (int)VFS_GETLEN(cl->file)); + sprintf(resource, "HTTP/1.1 200 OK\r\n" "%s%s%s" "Connection: %s\r\n" "Content-Length: %i\r\n" "Server: "FULLENGINENAME"/0\r\n" "\r\n", modifiedline, mimeline, gzipped?"Content-Encoding: gzip\r\nCache-Control: public, max-age=86400\r\n":"", cl->closeaftertransaction?"close":"keep-alive", (int)VFS_GETLEN(cl->file)); else if (HTTPmarkup==2) - sprintf(resource, "HTTP/1.0 200 OK\r\n" "%s%s" "Connection: %s\r\n" "Content-Length: %i\r\n" "Server: "FULLENGINENAME"/0\r\n" "\r\n", mimeline, gzipped?"Content-Encoding: gzip\r\nCache-Control: public, max-age=86400\r\n":"", cl->closeaftertransaction?"close":"keep-alive", (int)VFS_GETLEN(cl->file)); + sprintf(resource, "HTTP/1.0 200 OK\r\n" "%s%s%s" "Connection: %s\r\n" "Content-Length: %i\r\n" "Server: "FULLENGINENAME"/0\r\n" "\r\n", modifiedline, mimeline, gzipped?"Content-Encoding: gzip\r\nCache-Control: public, max-age=86400\r\n":"", cl->closeaftertransaction?"close":"keep-alive", (int)VFS_GETLEN(cl->file)); else if (HTTPmarkup) sprintf(resource, "HTTP/0.9 200 OK\r\n\r\n"); else @@ -616,8 +629,7 @@ const char *HTTP_RunClient (HTTP_active_connections_t *cl) msg = resource; if (*mode == 'H' || *mode == 'h') - { - + { //'head' VFS_CLOSE(cl->file); cl->file = NULL; } diff --git a/engine/http/iwebiface.c b/engine/http/iwebiface.c index 78dbbb9c2..8b0051fcd 100644 --- a/engine/http/iwebiface.c +++ b/engine/http/iwebiface.c @@ -72,6 +72,41 @@ vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_rela { return VFSSTDIO_Open(filename, mode, NULL); } + +#include "fs.h" +searchpathfuncs_t *QDECL FSSTDIO_OpenPath(vfsfile_t *mustbenull, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); +static searchpath_t filesystem; +int FS_FLocateFile(const char *filename, unsigned int lflags, flocation_t *loc) +{ + if (!filesystem.handle) + { + filesystem.handle = FSSTDIO_OpenPath(NULL, NULL, ".", ".", NULL); + if (!filesystem.handle) + { + printf("Filesystem unavailable\n"); + return 0; + } + } + + if (filesystem.handle->FindFile(filesystem.handle, loc, filename, NULL)) + { + loc->search = &filesystem; + return 1; + } + return (lflags&FSLF_DEEPONFAILURE)?0x7fffffff:0; +} +qboolean FS_GetLocMTime(flocation_t *location, time_t *modtime) +{ + *modtime = 0; + if (!location->search->handle->FileStat || !location->search->handle->FileStat(location->search->handle, location, modtime)) + return false; + return true; +} +struct vfsfile_s *FS_OpenReadLocation(const char *fname, flocation_t *location) +{ + return location->search->handle->OpenVFS(location->search->handle, location, "rb"); +} + void Q_strncpyz(char *d, const char *s, int n) { int i; diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 6041e2b9d..5f97f211a 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -679,7 +679,7 @@ ddef32_t *ED_FindLocalOrGlobal(progfuncs_t *progfuncs, const char *name, eval_t return &def; } -static char *COM_TrimString(const char *str, char *buffer, int buffersize) +static char *TrimString(const char *str, char *buffer, int buffersize) { int i; while (*str <= ' ' && *str>'\0') @@ -758,7 +758,7 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, const char *key, eval_t **result, if (!fdef) { char trimmed[256]; - c2 = COM_TrimString(c2, trimmed, sizeof(trimmed)); + c2 = TrimString(c2, trimmed, sizeof(trimmed)); def = ED_FindLocalOrGlobal(progfuncs, c2, &fval); if (def && def->type == ev_field) { @@ -955,7 +955,7 @@ char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *ppf, const char *key) if (type != ev_entity) return "'.' without entity"; if (c)*c = '\0'; - fdef = ED_FindField(progfuncs, COM_TrimString(c2)); + fdef = ED_FindField(progfuncs, TrimString(c2)); if (c)*c = '.'; if (!fdef) return "(Bad string)";