1 /*
2 bi_plist.c
3
4 QuakeC plist api
5
6 Copyright (C) 2003 Bill Currie
7
8 Author: Bill Currie <bill@taniwha.org>
9 Date: 2003/4/7
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20 See the GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to:
24
25 Free Software Foundation, Inc.
26 59 Temple Place - Suite 330
27 Boston, MA 02111-1307, USA
28
29 */
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #endif
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif
40 #include <stdlib.h>
41
42 #include "QF/hash.h"
43 #include "QF/progs.h"
44 #include "QF/qfplist.h"
45
46 #include "rua_internal.h"
47
48 typedef struct bi_plist_s {
49 struct bi_plist_s *next;
50 struct bi_plist_s **prev;
51 plitem_t *plitem;
52 int own;
53 } bi_plist_t;
54
55 typedef struct {
56 PR_RESMAP (bi_plist_t) plist_map;
57 bi_plist_t *plists;
58 hashtab_t *plist_tab;
59 } plist_resources_t;
60
61 static bi_plist_t *
plist_new(plist_resources_t * res)62 plist_new (plist_resources_t *res)
63 {
64 PR_RESNEW (bi_plist_t, res->plist_map);
65 }
66
67 static void
plist_free(plist_resources_t * res,bi_plist_t * plist)68 plist_free (plist_resources_t *res, bi_plist_t *plist)
69 {
70 PR_RESFREE (bi_plist_t, res->plist_map, plist);
71 }
72
73 static void
plist_reset(plist_resources_t * res)74 plist_reset (plist_resources_t *res)
75 {
76 PR_RESRESET (bi_plist_t, res->plist_map);
77 }
78
79 static inline bi_plist_t *
plist_get(plist_resources_t * res,unsigned index)80 plist_get (plist_resources_t *res, unsigned index)
81 {
82 PR_RESGET(res->plist_map, index);
83 }
84
85 static inline int
plist_index(plist_resources_t * res,bi_plist_t * plist)86 plist_index (plist_resources_t *res, bi_plist_t *plist)
87 {
88 PR_RESINDEX(res->plist_map, plist);
89 }
90
91 static void
bi_plist_clear(progs_t * pr,void * data)92 bi_plist_clear (progs_t *pr, void *data)
93 {
94 plist_resources_t *res = (plist_resources_t *) data;
95 bi_plist_t *plist;
96
97 for (plist = res->plists; plist; plist = plist->next) {
98 if (plist->own)
99 PL_Free (plist->plitem);
100 }
101 res->plists = 0;
102
103 Hash_FlushTable (res->plist_tab);
104 plist_reset (res);
105 }
106
107 static inline int
plist_handle(plist_resources_t * res,plitem_t * plitem)108 plist_handle (plist_resources_t *res, plitem_t *plitem)
109 {
110 bi_plist_t dummy = {0, 0, plitem, 0};
111 bi_plist_t *plist = Hash_FindElement (res->plist_tab, &dummy);
112
113 if (plist)
114 return plist_index (res, plist);
115
116 plist = plist_new (res);
117
118 if (!plist)
119 return 0;
120
121 plist->next = res->plists;
122 plist->prev = &res->plists;
123 if (res->plists)
124 res->plists->prev = &plist->next;
125 res->plists = plist;
126
127 plist->plitem = plitem;
128
129 Hash_AddElement (res->plist_tab, plist);
130 return plist_index (res, plist);
131 }
132
133 static inline void
plist_free_handle(plist_resources_t * res,bi_plist_t * plist)134 plist_free_handle (plist_resources_t *res, bi_plist_t *plist)
135 {
136 Hash_DelElement (res->plist_tab, plist);
137 *plist->prev = plist->next;
138 if (plist->next)
139 plist->next->prev = plist->prev;
140 plist_free (res, plist);
141 }
142
143 static inline bi_plist_t *
get_plist(progs_t * pr,const char * name,int handle)144 get_plist (progs_t *pr, const char *name, int handle)
145 {
146 plist_resources_t *res = PR_Resources_Find (pr, "plist");
147 bi_plist_t *plist = plist_get (res, handle);
148
149 // plist->prev will be null if the handle is unallocated
150 if (!plist || !plist->prev)
151 PR_RunError (pr, "invalid plist passed to %s", name + 3);
152 return plist;
153 }
154
155 static inline int
plist_retain(plist_resources_t * res,plitem_t * plitem)156 plist_retain (plist_resources_t *res, plitem_t *plitem)
157 {
158 int handle;
159 bi_plist_t *plist;
160
161 if (!plitem)
162 return 0;
163
164 handle = plist_handle (res, plitem);
165 if (!handle) {
166 // we're taking ownership of the plitem, but we have nowhere to store
167 // it, so we have to lose it. However, in this situation, we have worse
168 // things to worry about.
169 PL_Free (plitem);
170 return 0;
171 }
172
173 plist = plist_get (res, handle);
174 plist->own = 1;
175 return handle;
176 }
177
178 static void
bi_PL_GetFromFile(progs_t * pr)179 bi_PL_GetFromFile (progs_t *pr)
180 {
181 plist_resources_t *res = PR_Resources_Find (pr, "plist");
182 QFile *file = QFile_GetFile (pr, P_INT (pr, 0));
183 plitem_t *plitem;
184 long offset;
185 long size;
186 long len;
187 char *buf;
188
189 offset = Qtell (file);
190 size = Qfilesize (file);
191 len = size - offset;
192 buf = malloc (len + 1);
193 Qread (file, buf, len);
194 buf[len] = 0;
195
196 plitem = PL_GetPropertyList (buf);
197
198 R_INT (pr) = plist_retain (res, plitem);
199 }
200
201 static void
bi_PL_GetPropertyList(progs_t * pr)202 bi_PL_GetPropertyList (progs_t *pr)
203 {
204 plist_resources_t *res = PR_Resources_Find (pr, "plist");
205 plitem_t *plitem = PL_GetPropertyList (P_GSTRING (pr, 0));
206
207 R_INT (pr) = plist_retain (res, plitem);
208 }
209
210 static void
bi_PL_WritePropertyList(progs_t * pr)211 bi_PL_WritePropertyList (progs_t *pr)
212 {
213 int handle = P_INT (pr, 0);
214 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
215 char *pl = PL_WritePropertyList (plist->plitem);
216
217 R_STRING (pr) = PR_SetDynamicString (pr, pl);
218 free (pl);
219 }
220
221 static void
bi_PL_Type(progs_t * pr)222 bi_PL_Type (progs_t *pr)
223 {
224 int handle = P_INT (pr, 0);
225 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
226
227 R_INT (pr) = PL_Type (plist->plitem);
228 }
229
230 static void
bi_PL_String(progs_t * pr)231 bi_PL_String (progs_t *pr)
232 {
233 int handle = P_INT (pr, 0);
234 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
235 const char *str = PL_String (plist->plitem);
236
237 RETURN_STRING (pr, str);
238 }
239
240 static void
bi_PL_ObjectForKey(progs_t * pr)241 bi_PL_ObjectForKey (progs_t *pr)
242 {
243 plist_resources_t *res = PR_Resources_Find (pr, "plist");
244 int handle = P_INT (pr, 0);
245 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
246 const char *key = P_GSTRING (pr, 1);
247 plitem_t *plitem = PL_ObjectForKey (plist->plitem, key);
248
249 R_INT (pr) = 0;
250 if (!plitem)
251 return;
252 R_INT (pr) = plist_handle (res, plitem);
253 }
254
255 static void
bi_PL_RemoveObjectForKey(progs_t * pr)256 bi_PL_RemoveObjectForKey (progs_t *pr)
257 {
258 plist_resources_t *res = PR_Resources_Find (pr, "plist");
259 int handle = P_INT (pr, 0);
260 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
261 const char *key = P_GSTRING (pr, 1);
262 plitem_t *plitem = PL_RemoveObjectForKey (plist->plitem, key);
263
264 R_INT (pr) = plist_retain (res, plitem);
265 }
266
267 static void
bi_PL_ObjectAtIndex(progs_t * pr)268 bi_PL_ObjectAtIndex (progs_t *pr)
269 {
270 plist_resources_t *res = PR_Resources_Find (pr, "plist");
271 int handle = P_INT (pr, 0);
272 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
273 int ind = P_INT (pr, 1);
274 plitem_t *plitem = PL_ObjectAtIndex (plist->plitem, ind);
275
276 R_INT (pr) = 0;
277 if (!plitem)
278 return;
279 R_INT (pr) = plist_handle (res, plitem);
280 }
281
282 static void
bi_PL_D_AllKeys(progs_t * pr)283 bi_PL_D_AllKeys (progs_t *pr)
284 {
285 plist_resources_t *res = PR_Resources_Find (pr, "plist");
286 int handle = P_INT (pr, 0);
287 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
288 plitem_t *plitem = PL_D_AllKeys (plist->plitem);
289
290 R_INT (pr) = plist_retain (res, plitem);
291 }
292
293 static void
bi_PL_D_NumKeys(progs_t * pr)294 bi_PL_D_NumKeys (progs_t *pr)
295 {
296 int handle = P_INT (pr, 0);
297 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
298
299 R_INT (pr) = PL_D_NumKeys (plist->plitem);
300 }
301
302 static void
bi_PL_D_AddObject(progs_t * pr)303 bi_PL_D_AddObject (progs_t *pr)
304 {
305 int dict_handle = P_INT (pr, 0);
306 int obj_handle = P_INT (pr, 2);
307 bi_plist_t *dict = get_plist (pr, __FUNCTION__, dict_handle);
308 const char *key = P_GSTRING (pr, 1);
309 bi_plist_t *obj = get_plist (pr, __FUNCTION__, obj_handle);
310
311 obj->own = 0;
312 R_INT (pr) = PL_D_AddObject (dict->plitem, key, obj->plitem);
313 }
314
315 static void
bi_PL_A_AddObject(progs_t * pr)316 bi_PL_A_AddObject (progs_t *pr)
317 {
318 int arr_handle = P_INT (pr, 0);
319 int obj_handle = P_INT (pr, 1);
320 bi_plist_t *arr = get_plist (pr, __FUNCTION__, arr_handle);
321 bi_plist_t *obj = get_plist (pr, __FUNCTION__, obj_handle);
322
323 obj->own = 0;
324 R_INT (pr) = PL_A_AddObject (arr->plitem, obj->plitem);
325 }
326
327 static void
bi_PL_A_NumObjects(progs_t * pr)328 bi_PL_A_NumObjects (progs_t *pr)
329 {
330 int handle = P_INT (pr, 0);
331 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
332
333 R_INT (pr) = PL_A_NumObjects (plist->plitem);
334 }
335
336 static void
bi_PL_A_InsertObjectAtIndex(progs_t * pr)337 bi_PL_A_InsertObjectAtIndex (progs_t *pr)
338 {
339 int dict_handle = P_INT (pr, 0);
340 int obj_handle = P_INT (pr, 1);
341 bi_plist_t *arr = get_plist (pr, __FUNCTION__, dict_handle);
342 bi_plist_t *obj = get_plist (pr, __FUNCTION__, obj_handle);
343 int ind = P_INT (pr, 2);
344
345 obj->own = 0;
346 R_INT (pr) = PL_A_InsertObjectAtIndex (arr->plitem, obj->plitem, ind);
347 }
348
349 static void
bi_PL_RemoveObjectAtIndex(progs_t * pr)350 bi_PL_RemoveObjectAtIndex (progs_t *pr)
351 {
352 plist_resources_t *res = PR_Resources_Find (pr, "plist");
353 int handle = P_INT (pr, 0);
354 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
355 int ind = P_INT (pr, 1);
356 plitem_t *plitem = PL_RemoveObjectAtIndex (plist->plitem, ind);
357
358 R_INT (pr) = plist_retain (res, plitem);
359 }
360
361 static void
bi_PL_NewDictionary(progs_t * pr)362 bi_PL_NewDictionary (progs_t *pr)
363 {
364 plist_resources_t *res = PR_Resources_Find (pr, "plist");
365 plitem_t *plitem = PL_NewDictionary ();
366
367 R_INT (pr) = plist_retain (res, plitem);
368 }
369
370 static void
bi_PL_NewArray(progs_t * pr)371 bi_PL_NewArray (progs_t *pr)
372 {
373 plist_resources_t *res = PR_Resources_Find (pr, "plist");
374 plitem_t *plitem = PL_NewArray ();
375
376 R_INT (pr) = plist_retain (res, plitem);
377 }
378
379 static void
bi_PL_NewData(progs_t * pr)380 bi_PL_NewData (progs_t *pr)
381 {
382 //FIXME not safe
383 plist_resources_t *res = PR_Resources_Find (pr, "plist");
384 plitem_t *plitem = PL_NewData (P_GPOINTER (pr, 0), P_INT (pr, 1));
385
386 R_INT (pr) = plist_retain (res, plitem);
387 }
388
389 static void
bi_PL_NewString(progs_t * pr)390 bi_PL_NewString (progs_t *pr)
391 {
392 plist_resources_t *res = PR_Resources_Find (pr, "plist");
393 plitem_t *plitem = PL_NewString (P_GSTRING (pr, 0));
394
395 R_INT (pr) = plist_retain (res, plitem);
396 }
397
398 static void
bi_PL_Free(progs_t * pr)399 bi_PL_Free (progs_t *pr)
400 {
401 plist_resources_t *res = PR_Resources_Find (pr, "plist");
402 int handle = P_INT (pr, 0);
403 bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle);
404
405 if (!plist->own)
406 PR_RunError (pr, "attempt to free unowned plist");
407
408 PL_Free (plist->plitem);
409
410 plist_free_handle (res, plist);
411 }
412
413 static uintptr_t
plist_get_hash(const void * key,void * unused)414 plist_get_hash (const void *key, void *unused)
415 {
416 bi_plist_t *plist = (bi_plist_t *) key;
417 return (uintptr_t) plist->plitem;
418 }
419
420 static int
plist_compare(const void * k1,const void * k2,void * unused)421 plist_compare (const void *k1, const void *k2, void *unused)
422 {
423 bi_plist_t *pl1 = (bi_plist_t *) k1;
424 bi_plist_t *pl2 = (bi_plist_t *) k2;
425 return pl1->plitem == pl2->plitem;
426 }
427
428 static builtin_t builtins[] = {
429 {"PL_GetFromFile", bi_PL_GetFromFile, -1},
430 {"PL_GetPropertyList", bi_PL_GetPropertyList, -1},
431 {"PL_WritePropertyList", bi_PL_WritePropertyList, -1},
432 {"PL_Type", bi_PL_Type, -1},
433 {"PL_String", bi_PL_String, -1},
434 {"PL_ObjectForKey", bi_PL_ObjectForKey, -1},
435 {"PL_RemoveObjectForKey", bi_PL_RemoveObjectForKey, -1},
436 {"PL_ObjectAtIndex", bi_PL_ObjectAtIndex, -1},
437 {"PL_D_AllKeys", bi_PL_D_AllKeys, -1},
438 {"PL_D_NumKeys", bi_PL_D_NumKeys, -1},
439 {"PL_D_AddObject", bi_PL_D_AddObject, -1},
440 {"PL_A_AddObject", bi_PL_A_AddObject, -1},
441 {"PL_A_NumObjects", bi_PL_A_NumObjects, -1},
442 {"PL_A_InsertObjectAtIndex", bi_PL_A_InsertObjectAtIndex, -1},
443 {"PL_RemoveObjectAtIndex", bi_PL_RemoveObjectAtIndex, -1},
444 {"PL_NewDictionary", bi_PL_NewDictionary, -1},
445 {"PL_NewArray", bi_PL_NewArray, -1},
446 {"PL_NewData", bi_PL_NewData, -1},
447 {"PL_NewString", bi_PL_NewString, -1},
448 {"PL_Free", bi_PL_Free, -1},
449 {0}
450 };
451
452 void
RUA_Plist_Init(progs_t * pr,int secure)453 RUA_Plist_Init (progs_t *pr, int secure)
454 {
455 plist_resources_t *res = calloc (1, sizeof (plist_resources_t));
456 res->plist_tab = Hash_NewTable (1021, 0, 0, 0);
457 Hash_SetHashCompare (res->plist_tab, plist_get_hash, plist_compare);
458
459 PR_Resources_Register (pr, "plist", res, bi_plist_clear);
460 PR_RegisterBuiltins (pr, builtins);
461 }
462