1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 
23 /*****************************************************************************
24  * name:		l_struct.c
25  *
26  * desc:		structure reading / writing
27  *
28  * $Archive: /MissionPack/CODE/botlib/l_struct.c $
29  *
30  *****************************************************************************/
31 
32 #ifdef BOTLIB
33 #include "../qcommon/q_shared.h"
34 #include "botlib.h"				//for the include of be_interface.h
35 #include "l_script.h"
36 #include "l_precomp.h"
37 #include "l_struct.h"
38 #include "l_utils.h"
39 #include "be_interface.h"
40 #endif //BOTLIB
41 
42 #ifdef BSPC
43 //include files for usage in the BSP Converter
44 #include "../bspc/qbsp.h"
45 #include "../bspc/l_log.h"
46 #include "../bspc/l_mem.h"
47 #include "l_precomp.h"
48 #include "l_struct.h"
49 
50 #define qtrue	true
51 #define qfalse	false
52 #endif //BSPC
53 
54 //===========================================================================
55 //
56 // Parameter:				-
57 // Returns:					-
58 // Changes Globals:		-
59 //===========================================================================
FindField(fielddef_t * defs,char * name)60 fielddef_t *FindField(fielddef_t *defs, char *name)
61 {
62 	int i;
63 
64 	for (i = 0; defs[i].name; i++)
65 	{
66 		if (!strcmp(defs[i].name, name)) return &defs[i];
67 	} //end for
68 	return NULL;
69 } //end of the function FindField
70 //===========================================================================
71 //
72 // Parameter:				-
73 // Returns:					-
74 // Changes Globals:		-
75 //===========================================================================
ReadNumber(source_t * source,fielddef_t * fd,void * p)76 qboolean ReadNumber(source_t *source, fielddef_t *fd, void *p)
77 {
78 	token_t token;
79 	int negative = qfalse;
80 	long int intval, intmin = 0, intmax = 0;
81 	double floatval;
82 
83 	if (!PC_ExpectAnyToken(source, &token)) return 0;
84 
85 	//check for minus sign
86 	if (token.type == TT_PUNCTUATION)
87 	{
88 		if (fd->type & FT_UNSIGNED)
89 		{
90 			SourceError(source, "expected unsigned value, found %s", token.string);
91 			return 0;
92 		} //end if
93 		//if not a minus sign
94 		if (strcmp(token.string, "-"))
95 		{
96 			SourceError(source, "unexpected punctuation %s", token.string);
97 			return 0;
98 		} //end if
99 		negative = qtrue;
100 		//read the number
101 		if (!PC_ExpectAnyToken(source, &token)) return 0;
102 	} //end if
103 	//check if it is a number
104 	if (token.type != TT_NUMBER)
105 	{
106 		SourceError(source, "expected number, found %s", token.string);
107 		return 0;
108 	} //end if
109 	//check for a float value
110 	if (token.subtype & TT_FLOAT)
111 	{
112 		if ((fd->type & FT_TYPE) != FT_FLOAT)
113 		{
114 			SourceError(source, "unexpected float");
115 			return 0;
116 		} //end if
117 		floatval = token.floatvalue;
118 		if (negative) floatval = -floatval;
119 		if (fd->type & FT_BOUNDED)
120 		{
121 			if (floatval < fd->floatmin || floatval > fd->floatmax)
122 			{
123 				SourceError(source, "float out of range [%f, %f]", fd->floatmin, fd->floatmax);
124 				return 0;
125 			} //end if
126 		} //end if
127 		*(float *) p = (float) floatval;
128 		return 1;
129 	} //end if
130 	//
131 	intval = token.intvalue;
132 	if (negative) intval = -intval;
133 	//check bounds
134 	if ((fd->type & FT_TYPE) == FT_CHAR)
135 	{
136 		if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 255;}
137 		else {intmin = -128; intmax = 127;}
138 	} //end if
139 	if ((fd->type & FT_TYPE) == FT_INT)
140 	{
141 		if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 65535;}
142 		else {intmin = -32768; intmax = 32767;}
143 	} //end else if
144 	if ((fd->type & FT_TYPE) == FT_CHAR || (fd->type & FT_TYPE) == FT_INT)
145 	{
146 		if (fd->type & FT_BOUNDED)
147 		{
148 			intmin = Maximum(intmin, fd->floatmin);
149 			intmax = Minimum(intmax, fd->floatmax);
150 		} //end if
151 		if (intval < intmin || intval > intmax)
152 		{
153 			SourceError(source, "value %d out of range [%d, %d]", intval, intmin, intmax);
154 			return 0;
155 		} //end if
156 	} //end if
157 	else if ((fd->type & FT_TYPE) == FT_FLOAT)
158 	{
159 		if (fd->type & FT_BOUNDED)
160 		{
161 			if (intval < fd->floatmin || intval > fd->floatmax)
162 			{
163 				SourceError(source, "value %d out of range [%f, %f]", intval, fd->floatmin, fd->floatmax);
164 				return 0;
165 			} //end if
166 		} //end if
167 	} //end else if
168 	//store the value
169 	if ((fd->type & FT_TYPE) == FT_CHAR)
170 	{
171 		if (fd->type & FT_UNSIGNED) *(unsigned char *) p = (unsigned char) intval;
172 		else *(char *) p = (char) intval;
173 	} //end if
174 	else if ((fd->type & FT_TYPE) == FT_INT)
175 	{
176 		if (fd->type & FT_UNSIGNED) *(unsigned int *) p = (unsigned int) intval;
177 		else *(int *) p = (int) intval;
178 	} //end else
179 	else if ((fd->type & FT_TYPE) == FT_FLOAT)
180 	{
181 		*(float *) p = (float) intval;
182 	} //end else
183 	return 1;
184 } //end of the function ReadNumber
185 //===========================================================================
186 //
187 // Parameter:				-
188 // Returns:					-
189 // Changes Globals:		-
190 //===========================================================================
ReadChar(source_t * source,fielddef_t * fd,void * p)191 qboolean ReadChar(source_t *source, fielddef_t *fd, void *p)
192 {
193 	token_t token;
194 
195 	if (!PC_ExpectAnyToken(source, &token)) return 0;
196 
197 	//take literals into account
198 	if (token.type == TT_LITERAL)
199 	{
200 		StripSingleQuotes(token.string);
201 		*(char *) p = token.string[0];
202 	} //end if
203 	else
204 	{
205 		PC_UnreadLastToken(source);
206 		if (!ReadNumber(source, fd, p)) return 0;
207 	} //end if
208 	return 1;
209 } //end of the function ReadChar
210 //===========================================================================
211 //
212 // Parameter:				-
213 // Returns:					-
214 // Changes Globals:		-
215 //===========================================================================
ReadString(source_t * source,fielddef_t * fd,void * p)216 int ReadString(source_t *source, fielddef_t *fd, void *p)
217 {
218 	token_t token;
219 
220 	if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) return 0;
221 	//remove the double quotes
222 	StripDoubleQuotes(token.string);
223 	//copy the string
224 	strncpy((char *) p, token.string, MAX_STRINGFIELD);
225 	//make sure the string is closed with a zero
226 	((char *)p)[MAX_STRINGFIELD-1] = '\0';
227 	//
228 	return 1;
229 } //end of the function ReadString
230 //===========================================================================
231 //
232 // Parameter:				-
233 // Returns:					-
234 // Changes Globals:		-
235 //===========================================================================
ReadStructure(source_t * source,structdef_t * def,char * structure)236 int ReadStructure(source_t *source, structdef_t *def, char *structure)
237 {
238 	token_t token;
239 	fielddef_t *fd;
240 	void *p;
241 	int num;
242 
243 	if (!PC_ExpectTokenString(source, "{")) return 0;
244 	while(1)
245 	{
246 		if (!PC_ExpectAnyToken(source, &token)) return qfalse;
247 		//if end of structure
248 		if (!strcmp(token.string, "}")) break;
249 		//find the field with the name
250 		fd = FindField(def->fields, token.string);
251 		if (!fd)
252 		{
253 			SourceError(source, "unknown structure field %s", token.string);
254 			return qfalse;
255 		} //end if
256 		if (fd->type & FT_ARRAY)
257 		{
258 			num = fd->maxarray;
259 			if (!PC_ExpectTokenString(source, "{")) return qfalse;
260 		} //end if
261 		else
262 		{
263 			num = 1;
264 		} //end else
265 		p = (void *)(structure + fd->offset);
266 		while (num-- > 0)
267 		{
268 			if (fd->type & FT_ARRAY)
269 			{
270 				if (PC_CheckTokenString(source, "}")) break;
271 			} //end if
272 			switch(fd->type & FT_TYPE)
273 			{
274 				case FT_CHAR:
275 				{
276 					if (!ReadChar(source, fd, p)) return qfalse;
277 					p = (char *) p + sizeof(char);
278 					break;
279 				} //end case
280 				case FT_INT:
281 				{
282 					if (!ReadNumber(source, fd, p)) return qfalse;
283 					p = (char *) p + sizeof(int);
284 					break;
285 				} //end case
286 				case FT_FLOAT:
287 				{
288 					if (!ReadNumber(source, fd, p)) return qfalse;
289 					p = (char *) p + sizeof(float);
290 					break;
291 				} //end case
292 				case FT_STRING:
293 				{
294 					if (!ReadString(source, fd, p)) return qfalse;
295 					p = (char *) p + MAX_STRINGFIELD;
296 					break;
297 				} //end case
298 				case FT_STRUCT:
299 				{
300 					if (!fd->substruct)
301 					{
302 						SourceError(source, "BUG: no sub structure defined");
303 						return qfalse;
304 					} //end if
305 					ReadStructure(source, fd->substruct, (char *) p);
306 					p = (char *) p + fd->substruct->size;
307 					break;
308 				} //end case
309 			} //end switch
310 			if (fd->type & FT_ARRAY)
311 			{
312 				if (!PC_ExpectAnyToken(source, &token)) return qfalse;
313 				if (!strcmp(token.string, "}")) break;
314 				if (strcmp(token.string, ","))
315 				{
316 					SourceError(source, "expected a comma, found %s", token.string);
317 					return qfalse;
318 				} //end if
319 			} //end if
320 		} //end while
321 	} //end while
322 	return qtrue;
323 } //end of the function ReadStructure
324 //===========================================================================
325 //
326 // Parameter:				-
327 // Returns:					-
328 // Changes Globals:		-
329 //===========================================================================
WriteIndent(FILE * fp,int indent)330 int WriteIndent(FILE *fp, int indent)
331 {
332 	while(indent-- > 0)
333 	{
334 		if (fprintf(fp, "\t") < 0) return qfalse;
335 	} //end while
336 	return qtrue;
337 } //end of the function WriteIndent
338 //===========================================================================
339 //
340 // Parameter:				-
341 // Returns:					-
342 // Changes Globals:		-
343 //===========================================================================
WriteFloat(FILE * fp,float value)344 int WriteFloat(FILE *fp, float value)
345 {
346 	char buf[128];
347 	int l;
348 
349 	sprintf(buf, "%f", value);
350 	l = strlen(buf);
351 	//strip any trailing zeros
352 	while(l-- > 1)
353 	{
354 		if (buf[l] != '0' && buf[l] != '.') break;
355 		if (buf[l] == '.')
356 		{
357 			buf[l] = 0;
358 			break;
359 		} //end if
360 		buf[l] = 0;
361 	} //end while
362 	//write the float to file
363 	if (fprintf(fp, "%s", buf) < 0) return 0;
364 	return 1;
365 } //end of the function WriteFloat
366 //===========================================================================
367 //
368 // Parameter:				-
369 // Returns:					-
370 // Changes Globals:		-
371 //===========================================================================
WriteStructWithIndent(FILE * fp,structdef_t * def,char * structure,int indent)372 int WriteStructWithIndent(FILE *fp, structdef_t *def, char *structure, int indent)
373 {
374 	int i, num;
375 	void *p;
376 	fielddef_t *fd;
377 
378 	if (!WriteIndent(fp, indent)) return qfalse;
379 	if (fprintf(fp, "{\r\n") < 0) return qfalse;
380 
381 	indent++;
382 	for (i = 0; def->fields[i].name; i++)
383 	{
384 		fd = &def->fields[i];
385 		if (!WriteIndent(fp, indent)) return qfalse;
386 		if (fprintf(fp, "%s\t", fd->name) < 0) return qfalse;
387 		p = (void *)(structure + fd->offset);
388 		if (fd->type & FT_ARRAY)
389 		{
390 			num = fd->maxarray;
391 			if (fprintf(fp, "{") < 0) return qfalse;
392 		} //end if
393 		else
394 		{
395 			num = 1;
396 		} //end else
397 		while(num-- > 0)
398 		{
399 			switch(fd->type & FT_TYPE)
400 			{
401 				case FT_CHAR:
402 				{
403 					if (fprintf(fp, "%d", *(char *) p) < 0) return qfalse;
404 					p = (char *) p + sizeof(char);
405 					break;
406 				} //end case
407 				case FT_INT:
408 				{
409 					if (fprintf(fp, "%d", *(int *) p) < 0) return qfalse;
410 					p = (char *) p + sizeof(int);
411 					break;
412 				} //end case
413 				case FT_FLOAT:
414 				{
415 					if (!WriteFloat(fp, *(float *)p)) return qfalse;
416 					p = (char *) p + sizeof(float);
417 					break;
418 				} //end case
419 				case FT_STRING:
420 				{
421 					if (fprintf(fp, "\"%s\"", (char *) p) < 0) return qfalse;
422 					p = (char *) p + MAX_STRINGFIELD;
423 					break;
424 				} //end case
425 				case FT_STRUCT:
426 				{
427 					if (!WriteStructWithIndent(fp, fd->substruct, structure, indent)) return qfalse;
428 					p = (char *) p + fd->substruct->size;
429 					break;
430 				} //end case
431 			} //end switch
432 			if (fd->type & FT_ARRAY)
433 			{
434 				if (num > 0)
435 				{
436 					if (fprintf(fp, ",") < 0) return qfalse;
437 				} //end if
438 				else
439 				{
440 					if (fprintf(fp, "}") < 0) return qfalse;
441 				} //end else
442 			} //end if
443 		} //end while
444 		if (fprintf(fp, "\r\n") < 0) return qfalse;
445 	} //end for
446 	indent--;
447 
448 	if (!WriteIndent(fp, indent)) return qfalse;
449 	if (fprintf(fp, "}\r\n") < 0) return qfalse;
450 	return qtrue;
451 } //end of the function WriteStructWithIndent
452 //===========================================================================
453 //
454 // Parameter:				-
455 // Returns:					-
456 // Changes Globals:		-
457 //===========================================================================
WriteStructure(FILE * fp,structdef_t * def,char * structure)458 int WriteStructure(FILE *fp, structdef_t *def, char *structure)
459 {
460 	return WriteStructWithIndent(fp, def, structure, 0);
461 } //end of the function WriteStructure
462 
463