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