1 /*
2 	bi_file.c
3 
4 	CSQC file builtins
5 
6 	Copyright (C) 1996-1997  Id Software, Inc.
7 
8 	This program is free software; you can redistribute it and/or
9 	modify it under the terms of the GNU General Public License
10 	as published by the Free Software Foundation; either version 2
11 	of the License, or (at your option) any later version.
12 
13 	This program is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 	See the GNU General Public License for more details.
18 
19 	You should have received a copy of the GNU General Public License
20 	along with this program; if not, write to:
21 
22 		Free Software Foundation, Inc.
23 		59 Temple Place - Suite 330
24 		Boston, MA  02111-1307, USA
25 
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 
31 #include <stdlib.h>
32 #ifdef HAVE_STRING_H
33 # include <string.h>
34 #endif
35 #ifdef HAVE_STRINGS_H
36 # include <strings.h>
37 #endif
38 
39 #include "QF/dstring.h"
40 #include "QF/progs.h"
41 #include "QF/quakefs.h"
42 #include "QF/va.h"
43 #include "QF/zone.h"
44 
45 #include "rua_internal.h"
46 
47 typedef struct qfile_s {
48 	struct qfile_s *next;
49 	struct qfile_s **prev;
50 	QFile      *file;
51 } qfile_t;
52 
53 typedef struct {
54 	PR_RESMAP (qfile_t) handle_map;
55 	qfile_t    *handles;
56 } qfile_resources_t;
57 
58 static qfile_t *
handle_new(qfile_resources_t * res)59 handle_new (qfile_resources_t *res)
60 {
61 	PR_RESNEW (qfile_t, res->handle_map);
62 }
63 
64 static void
handle_free(qfile_resources_t * res,qfile_t * handle)65 handle_free (qfile_resources_t *res, qfile_t *handle)
66 {
67 	PR_RESFREE (qfile_t, res->handle_map, handle);
68 }
69 
70 static void
handle_reset(qfile_resources_t * res)71 handle_reset (qfile_resources_t *res)
72 {
73 	PR_RESRESET (qfile_t, res->handle_map);
74 }
75 
76 static inline qfile_t *
handle_get(qfile_resources_t * res,int index)77 handle_get (qfile_resources_t *res, int index)
78 {
79 	PR_RESGET(res->handle_map, index);
80 }
81 
82 static inline int
handle_index(qfile_resources_t * res,qfile_t * handle)83 handle_index (qfile_resources_t *res, qfile_t *handle)
84 {
85 	PR_RESINDEX(res->handle_map, handle);
86 }
87 
88 static void
bi_qfile_clear(progs_t * pr,void * data)89 bi_qfile_clear (progs_t *pr, void *data)
90 {
91 	qfile_resources_t *res = (qfile_resources_t *) data;
92 	qfile_t    *handle;
93 
94 	for (handle = res->handles; handle; handle = handle->next)
95 		Qclose (handle->file);
96 	res->handles = 0;
97 	handle_reset (res);
98 }
99 
100 static int
alloc_handle(qfile_resources_t * res,QFile * file)101 alloc_handle (qfile_resources_t *res, QFile *file)
102 {
103 	qfile_t    *handle = handle_new (res);
104 
105 	if (!handle)
106 		return 0;
107 
108 	handle->next = res->handles;
109 	handle->prev = &res->handles;
110 	if (res->handles)
111 		res->handles->prev = &handle->next;
112 	res->handles = handle;
113 	handle->file = file;
114 	return handle_index (res, handle);
115 }
116 
117 int
QFile_AllocHandle(progs_t * pr,QFile * file)118 QFile_AllocHandle (progs_t *pr, QFile *file)
119 {
120 	qfile_resources_t *res = PR_Resources_Find (pr, "QFile");
121 
122 	return alloc_handle (res, file);
123 }
124 
125 static void
secured(progs_t * pr)126 secured (progs_t *pr)
127 {
128 	PR_RunError (pr, "Secured function called");
129 }
130 
131 static void
bi_Qrename(progs_t * pr)132 bi_Qrename (progs_t *pr)
133 {
134 	const char *old = P_GSTRING (pr, 0);
135 	const char *new = P_GSTRING (pr, 1);
136 
137 	R_INT (pr) = Qrename (old, new);
138 }
139 
140 static void
bi_Qremove(progs_t * pr)141 bi_Qremove (progs_t *pr)
142 {
143 	const char *path = P_GSTRING (pr, 0);
144 
145 	R_INT (pr) = Qremove (path);
146 }
147 
148 static void
bi_Qopen(progs_t * pr)149 bi_Qopen (progs_t *pr)
150 {
151 	qfile_resources_t *res = PR_Resources_Find (pr, "QFile");
152 	const char *path = P_GSTRING (pr, 0);
153 	const char *mode = P_GSTRING (pr, 1);
154 	QFile      *file;
155 
156 	R_INT (pr) = 0;
157 	if (!(file = Qopen (path, mode)))
158 		return;
159 	if (!(R_INT (pr) = alloc_handle (res, file)))
160 		Qclose (file);
161 }
162 
163 static qfile_t *
get_handle(progs_t * pr,const char * name,int handle)164 get_handle (progs_t *pr, const char *name, int handle)
165 {
166 	qfile_resources_t *res = PR_Resources_Find (pr, "QFile");
167 	qfile_t    *h = handle_get (res, handle);
168 
169 	if (!h)
170 		PR_RunError (pr, "invalid file handle passed to %s", name + 3);
171 	return h;
172 }
173 
174 QFile *
QFile_GetFile(progs_t * pr,int handle)175 QFile_GetFile (progs_t *pr, int handle)
176 {
177 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
178 
179 	return h->file;
180 }
181 
182 static void
bi_Qclose(progs_t * pr)183 bi_Qclose (progs_t *pr)
184 {
185 	qfile_resources_t *res = PR_Resources_Find (pr, "QFile");
186 	int         handle = P_INT (pr, 0);
187 	qfile_t    *h = handle_get (res, handle);
188 
189 	if (!h)
190 		PR_RunError (pr, "invalid file handle passed to Qclose");
191 	Qclose (h->file);
192 	*h->prev = h->next;
193 	if (h->next)
194 		h->next->prev = h->prev;
195 	handle_free (res, h);
196 }
197 
198 static void
bi_Qgetline(progs_t * pr)199 bi_Qgetline (progs_t *pr)
200 {
201 	int         handle = P_INT (pr, 0);
202 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
203 	const char *s;
204 
205 	s = Qgetline (h->file);
206 	if (s)
207 		RETURN_STRING (pr, s);
208 	else
209 		R_STRING (pr) = 0;
210 }
211 
212 static void
bi_Qreadstring(progs_t * pr)213 bi_Qreadstring (progs_t *pr)
214 {
215 	int         handle = P_INT (pr, 0);
216 	int         len = P_INT (pr, 1);
217 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
218 	string_t    str = PR_NewMutableString (pr);
219 	dstring_t  *dstr = PR_GetMutableString (pr, str);
220 
221 	dstr->size = len + 1;
222 	dstring_adjust (dstr);
223 	len = Qread (h->file, dstr->str, len);
224 	dstr->size = len + 1;
225 	dstr->str[len] = 0;
226 	R_STRING (pr) = str;
227 }
228 
229 static void
check_buffer(progs_t * pr,pr_type_t * buf,int count,const char * name)230 check_buffer (progs_t *pr, pr_type_t *buf, int count, const char *name)
231 {
232 	int         len;
233 
234 	len = (count + sizeof (pr_type_t) - 1) / sizeof (pr_type_t);
235 	if (buf < pr->pr_globals || buf + len > pr->pr_globals + pr->globals_size)
236 		PR_RunError (pr, "%s: bad buffer", name);
237 }
238 
239 static void
bi_Qread(progs_t * pr)240 bi_Qread (progs_t *pr)
241 {
242 	int         handle = P_INT (pr, 0);
243 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
244 	pr_type_t  *buf = P_GPOINTER (pr, 1);
245 	int         count = P_INT (pr, 2);
246 
247 	check_buffer (pr, buf, count, "Qread");
248 	R_INT (pr) = Qread (h->file, buf, count);
249 }
250 
251 static void
bi_Qwrite(progs_t * pr)252 bi_Qwrite (progs_t *pr)
253 {
254 	int         handle = P_INT (pr, 0);
255 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
256 	pr_type_t  *buf = P_GPOINTER (pr, 1);
257 	int         count = P_INT (pr, 2);
258 
259 	check_buffer (pr, buf, count, "Qwrite");
260 	R_INT (pr) = Qwrite (h->file, buf, count);
261 }
262 
263 static void
bi_Qputs(progs_t * pr)264 bi_Qputs (progs_t *pr)
265 {
266 	int         handle = P_INT (pr, 0);
267 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
268 	const char *str = P_GSTRING (pr, 1);
269 
270 	R_INT (pr) = Qputs (h->file, str);
271 }
272 #if 0
273 static void
274 bi_Qgets (progs_t *pr)
275 {
276 	int         handle = P_INT (pr, 0);
277 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
278 	pr_type_t  *buf = P_GPOINTER (pr, 1);
279 	int         count = P_INT (pr, 2);
280 
281 	check_buffer (pr, buf, count, "Qgets");
282 	RETURN_POINTER (pr, Qgets (h->file, (char *) buf, count));
283 }
284 #endif
285 static void
bi_Qgetc(progs_t * pr)286 bi_Qgetc (progs_t *pr)
287 {
288 	int         handle = P_INT (pr, 0);
289 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
290 
291 	R_INT (pr) = Qgetc (h->file);
292 }
293 
294 static void
bi_Qputc(progs_t * pr)295 bi_Qputc (progs_t *pr)
296 {
297 	int         handle = P_INT (pr, 0);
298 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
299 	int         c = P_INT (pr, 1);
300 
301 	R_INT (pr) = Qputc (h->file, c);
302 }
303 
304 static void
bi_Qseek(progs_t * pr)305 bi_Qseek (progs_t *pr)
306 {
307 	int         handle = P_INT (pr, 0);
308 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
309 	int         offset = P_INT (pr, 1);
310 	int         whence = P_INT (pr, 2);
311 
312 	R_INT (pr) = Qseek (h->file, offset, whence);
313 }
314 
315 static void
bi_Qtell(progs_t * pr)316 bi_Qtell (progs_t *pr)
317 {
318 	int         handle = P_INT (pr, 0);
319 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
320 
321 	R_INT (pr) = Qtell (h->file);
322 }
323 
324 static void
bi_Qflush(progs_t * pr)325 bi_Qflush (progs_t *pr)
326 {
327 	int         handle = P_INT (pr, 0);
328 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
329 
330 	R_INT (pr) = Qflush (h->file);
331 }
332 
333 static void
bi_Qeof(progs_t * pr)334 bi_Qeof (progs_t *pr)
335 {
336 	int         handle = P_INT (pr, 0);
337 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
338 
339 	R_INT (pr) = Qeof (h->file);
340 }
341 
342 static void
bi_Qfilesize(progs_t * pr)343 bi_Qfilesize (progs_t *pr)
344 {
345 	int         handle = P_INT (pr, 0);
346 	qfile_t    *h = get_handle (pr, __FUNCTION__, handle);
347 
348 	R_INT (pr) = Qfilesize (h->file);
349 }
350 
351 static builtin_t secure_builtins[] = {
352 	{"Qrename",		secured,		-1},
353 	{"Qremove",		secured,		-1},
354 	{"Qopen",		secured,		-1},
355 	{0}
356 };
357 
358 static builtin_t insecure_builtins[] = {
359 	{"Qrename",		bi_Qrename,		-1},
360 	{"Qremove",		bi_Qremove,		-1},
361 	{"Qopen",		bi_Qopen,		-1},
362 	{0}
363 };
364 
365 static builtin_t builtins[] = {
366 	{"Qclose",		bi_Qclose,		-1},
367 	{"Qgetline",	bi_Qgetline,	-1},
368 	{"Qreadstring",	bi_Qreadstring,	-1},
369 	{"Qread",		bi_Qread,		-1},
370 	{"Qwrite",		bi_Qwrite,		-1},
371 	{"Qputs",		bi_Qputs,		-1},
372 //	{"Qgets",		bi_Qgets,		-1},
373 	{"Qgetc",		bi_Qgetc,		-1},
374 	{"Qputc",		bi_Qputc,		-1},
375 	{"Qseek",		bi_Qseek,		-1},
376 	{"Qtell",		bi_Qtell,		-1},
377 	{"Qflush",		bi_Qflush,		-1},
378 	{"Qeof",		bi_Qeof,		-1},
379 	{"Qfilesize",	bi_Qfilesize,	-1},
380 	{0}
381 };
382 
383 void
RUA_QFile_Init(progs_t * pr,int secure)384 RUA_QFile_Init (progs_t *pr, int secure)
385 {
386 	qfile_resources_t *res = calloc (sizeof (qfile_resources_t), 1);
387 
388 	PR_Resources_Register (pr, "QFile", res, bi_qfile_clear);
389 	if (secure) {
390 		PR_RegisterBuiltins (pr, secure_builtins);
391 	} else {
392 		PR_RegisterBuiltins (pr, insecure_builtins);
393 	}
394 	PR_RegisterBuiltins (pr, builtins);
395 }
396