quakeforge/libs/gamecode/builtins/bi_file.c
Bill Currie c2c3a62956 nuke Qexpand_squiggle. instead, expand ~ to $HOME on qfs initialization and
cache the value.

don't call Qopen directly in the engine. instead call QFS_Open (generic) or
QFS_WOpen (write only, zip flag).

rework QFS_NextFilename to use a dstring (avoiding a potential buffer
overflow), support 10000 files and work from the top-level fs_userpath
directory. adjust QFS_WriteFile and QFS_WriteBuffers etc to suit.

make sw32 screenshots actually get written.

hopefully everything gets written to the right places :)
2003-05-23 17:17:01 +00:00

180 lines
3.4 KiB
C

/*
bi_file.c
CSQC file builtins
Copyright (C) 1996-1997 Id Software, Inc.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((unused)) const char rcsid[] =
"$Id$";
#include <stdlib.h>
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_FNMATCH_H
# define model_t sunmodel_t
# include <fnmatch.h>
# undef model_t
#else
# ifdef WIN32
# include "fnmatch.h"
# endif
#endif
#ifndef HAVE_FNMATCH_PROTO
int fnmatch (const char *__pattern, const char *__string, int __flags);
#endif
#include "QF/csqc.h"
#include "QF/cvar.h"
#include "QF/progs.h"
#include "QF/quakefs.h"
#include "QF/va.h"
#include "QF/zone.h"
static const char *file_ban_list[] = {
"default.cfg{,.gz}",
"demo1.dem{,.gz}",
"demo2.dem{,.gz}",
"demo3.dem{,.gz}",
"end1.bin{,.gz}",
"end2.bin{,.gz}",
"gfx.wad{,.gz}",
"progs.dat{,.gz}",
"quake.rc{,.gz}",
0,
};
static const char *dir_ban_list[] = {
"gfx",
"maps",
"progs",
"skins",
"sound",
0,
};
static int
file_readable (char *path)
{
char t;
char *p = strchr (path, '/');
const char **match;
if (p) {
t = *p;
*p = 0;
for (match = dir_ban_list; *match; match++) {
if (fnmatch (*match, path, FNM_PATHNAME) == 0) {
*p = t;
return 0;
}
}
} else {
for (match = file_ban_list; *match; match++) {
if (fnmatch (*match, path, FNM_PATHNAME) == 0) {
return 0;
}
}
}
return 1;
}
static int
file_writeable (char *path)
{
return file_readable (path);
}
static void
bi_File_Open (progs_t *pr)
{
qfile_resources_t *res = PR_Resources_Find (pr, "QFile");
QFile **file = QFile_AllocHandle (pr, res);
const char *pth = P_GSTRING (pr, 0);
const char *mode = P_GSTRING (pr, 1);
char *path;
char *p;
int do_write = 0;
int do_read = 0;
p = strchr (mode, 'r');
if (p) {
do_read |= 1;
if (p[1] == '+')
do_write |= 1;
}
p = strchr (mode, 'w');
if (p) {
do_write |= 1;
if (p[1] == '+')
do_read |= 1;
}
p = strchr (mode, 'a');
if (p) {
do_write |= 1;
if (p[1] == '+')
do_read |= 1;
}
path = QFS_CompressPath (pth);
//printf ("'%s' '%s'\n", P_GSTRING (pr, 0), path);
if (!path[0])
goto error;
if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || path [2] == 0))
goto error;
if (path[strlen (path) - 1] =='/')
goto error;
if (!do_read && !do_write)
goto error;
if (do_read && !file_readable (path))
goto error;
if (do_write && !file_writeable (path))
goto error;
*file = QFS_Open (va ("%s/%s", qfs_gamedir->dir.def, path), mode);
if (!*file)
goto error;
R_INT (pr) = (file - res->handles) + 1;
free (path);
return;
error:
free (path);
R_INT (pr) = 0;
}
void
File_Progs_Init (progs_t *pr)
{
PR_AddBuiltin (pr, "File_Open", bi_File_Open, -1);
}