1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 #include "q_shared.h"
21 
22 vec3_t vec3_origin = { 0, 0, 0 };
23 
24 
25 const color_t colorBlack	= {   0,   0,   0, 255 };
26 const color_t colorRed		= { 255,   0,   0, 255 };
27 const color_t colorGreen	= {   0, 255,   0, 255 };
28 const color_t colorYellow	= { 255, 255,   0, 255 };
29 const color_t colorBlue		= {   0,   0, 255, 255 };
30 const color_t colorCyan		= {   0, 255, 255, 255 };
31 const color_t colorMagenta	= { 255,   0, 255, 255 };
32 const color_t colorWhite	= { 255, 255, 255, 255 };
33 
34 const color_t colorTable[8] = {
35 	{   0,   0,   0, 255 },
36 	{ 255,   0,   0, 255 },
37 	{   0, 255,   0, 255 },
38 	{ 255, 255,   0, 255 },
39 	{   0,   0, 255, 255 },
40 	{   0, 255, 255, 255 },
41 	{ 255,   0, 255, 255 },
42 	{ 255, 255, 255, 255 }
43 };
44 
45 vec3_t bytedirs[NUMVERTEXNORMALS] = {
46 {-0.525731, 0.000000, 0.850651},
47 {-0.442863, 0.238856, 0.864188},
48 {-0.295242, 0.000000, 0.955423},
49 {-0.309017, 0.500000, 0.809017},
50 {-0.162460, 0.262866, 0.951056},
51 {0.000000, 0.000000, 1.000000},
52 {0.000000, 0.850651, 0.525731},
53 {-0.147621, 0.716567, 0.681718},
54 {0.147621, 0.716567, 0.681718},
55 {0.000000, 0.525731, 0.850651},
56 {0.309017, 0.500000, 0.809017},
57 {0.525731, 0.000000, 0.850651},
58 {0.295242, 0.000000, 0.955423},
59 {0.442863, 0.238856, 0.864188},
60 {0.162460, 0.262866, 0.951056},
61 {-0.681718, 0.147621, 0.716567},
62 {-0.809017, 0.309017, 0.500000},
63 {-0.587785, 0.425325, 0.688191},
64 {-0.850651, 0.525731, 0.000000},
65 {-0.864188, 0.442863, 0.238856},
66 {-0.716567, 0.681718, 0.147621},
67 {-0.688191, 0.587785, 0.425325},
68 {-0.500000, 0.809017, 0.309017},
69 {-0.238856, 0.864188, 0.442863},
70 {-0.425325, 0.688191, 0.587785},
71 {-0.716567, 0.681718, -0.147621},
72 {-0.500000, 0.809017, -0.309017},
73 {-0.525731, 0.850651, 0.000000},
74 {0.000000, 0.850651, -0.525731},
75 {-0.238856, 0.864188, -0.442863},
76 {0.000000, 0.955423, -0.295242},
77 {-0.262866, 0.951056, -0.162460},
78 {0.000000, 1.000000, 0.000000},
79 {0.000000, 0.955423, 0.295242},
80 {-0.262866, 0.951056, 0.162460},
81 {0.238856, 0.864188, 0.442863},
82 {0.262866, 0.951056, 0.162460},
83 {0.500000, 0.809017, 0.309017},
84 {0.238856, 0.864188, -0.442863},
85 {0.262866, 0.951056, -0.162460},
86 {0.500000, 0.809017, -0.309017},
87 {0.850651, 0.525731, 0.000000},
88 {0.716567, 0.681718, 0.147621},
89 {0.716567, 0.681718, -0.147621},
90 {0.525731, 0.850651, 0.000000},
91 {0.425325, 0.688191, 0.587785},
92 {0.864188, 0.442863, 0.238856},
93 {0.688191, 0.587785, 0.425325},
94 {0.809017, 0.309017, 0.500000},
95 {0.681718, 0.147621, 0.716567},
96 {0.587785, 0.425325, 0.688191},
97 {0.955423, 0.295242, 0.000000},
98 {1.000000, 0.000000, 0.000000},
99 {0.951056, 0.162460, 0.262866},
100 {0.850651, -0.525731, 0.000000},
101 {0.955423, -0.295242, 0.000000},
102 {0.864188, -0.442863, 0.238856},
103 {0.951056, -0.162460, 0.262866},
104 {0.809017, -0.309017, 0.500000},
105 {0.681718, -0.147621, 0.716567},
106 {0.850651, 0.000000, 0.525731},
107 {0.864188, 0.442863, -0.238856},
108 {0.809017, 0.309017, -0.500000},
109 {0.951056, 0.162460, -0.262866},
110 {0.525731, 0.000000, -0.850651},
111 {0.681718, 0.147621, -0.716567},
112 {0.681718, -0.147621, -0.716567},
113 {0.850651, 0.000000, -0.525731},
114 {0.809017, -0.309017, -0.500000},
115 {0.864188, -0.442863, -0.238856},
116 {0.951056, -0.162460, -0.262866},
117 {0.147621, 0.716567, -0.681718},
118 {0.309017, 0.500000, -0.809017},
119 {0.425325, 0.688191, -0.587785},
120 {0.442863, 0.238856, -0.864188},
121 {0.587785, 0.425325, -0.688191},
122 {0.688191, 0.587785, -0.425325},
123 {-0.147621, 0.716567, -0.681718},
124 {-0.309017, 0.500000, -0.809017},
125 {0.000000, 0.525731, -0.850651},
126 {-0.525731, 0.000000, -0.850651},
127 {-0.442863, 0.238856, -0.864188},
128 {-0.295242, 0.000000, -0.955423},
129 {-0.162460, 0.262866, -0.951056},
130 {0.000000, 0.000000, -1.000000},
131 {0.295242, 0.000000, -0.955423},
132 {0.162460, 0.262866, -0.951056},
133 {-0.442863, -0.238856, -0.864188},
134 {-0.309017, -0.500000, -0.809017},
135 {-0.162460, -0.262866, -0.951056},
136 {0.000000, -0.850651, -0.525731},
137 {-0.147621, -0.716567, -0.681718},
138 {0.147621, -0.716567, -0.681718},
139 {0.000000, -0.525731, -0.850651},
140 {0.309017, -0.500000, -0.809017},
141 {0.442863, -0.238856, -0.864188},
142 {0.162460, -0.262866, -0.951056},
143 {0.238856, -0.864188, -0.442863},
144 {0.500000, -0.809017, -0.309017},
145 {0.425325, -0.688191, -0.587785},
146 {0.716567, -0.681718, -0.147621},
147 {0.688191, -0.587785, -0.425325},
148 {0.587785, -0.425325, -0.688191},
149 {0.000000, -0.955423, -0.295242},
150 {0.000000, -1.000000, 0.000000},
151 {0.262866, -0.951056, -0.162460},
152 {0.000000, -0.850651, 0.525731},
153 {0.000000, -0.955423, 0.295242},
154 {0.238856, -0.864188, 0.442863},
155 {0.262866, -0.951056, 0.162460},
156 {0.500000, -0.809017, 0.309017},
157 {0.716567, -0.681718, 0.147621},
158 {0.525731, -0.850651, 0.000000},
159 {-0.238856, -0.864188, -0.442863},
160 {-0.500000, -0.809017, -0.309017},
161 {-0.262866, -0.951056, -0.162460},
162 {-0.850651, -0.525731, 0.000000},
163 {-0.716567, -0.681718, -0.147621},
164 {-0.716567, -0.681718, 0.147621},
165 {-0.525731, -0.850651, 0.000000},
166 {-0.500000, -0.809017, 0.309017},
167 {-0.238856, -0.864188, 0.442863},
168 {-0.262866, -0.951056, 0.162460},
169 {-0.864188, -0.442863, 0.238856},
170 {-0.809017, -0.309017, 0.500000},
171 {-0.688191, -0.587785, 0.425325},
172 {-0.681718, -0.147621, 0.716567},
173 {-0.442863, -0.238856, 0.864188},
174 {-0.587785, -0.425325, 0.688191},
175 {-0.309017, -0.500000, 0.809017},
176 {-0.147621, -0.716567, 0.681718},
177 {-0.425325, -0.688191, 0.587785},
178 {-0.162460, -0.262866, 0.951056},
179 {0.442863, -0.238856, 0.864188},
180 {0.162460, -0.262866, 0.951056},
181 {0.309017, -0.500000, 0.809017},
182 {0.147621, -0.716567, 0.681718},
183 {0.000000, -0.525731, 0.850651},
184 {0.425325, -0.688191, 0.587785},
185 {0.587785, -0.425325, 0.688191},
186 {0.688191, -0.587785, 0.425325},
187 {-0.955423, 0.295242, 0.000000},
188 {-0.951056, 0.162460, 0.262866},
189 {-1.000000, 0.000000, 0.000000},
190 {-0.850651, 0.000000, 0.525731},
191 {-0.955423, -0.295242, 0.000000},
192 {-0.951056, -0.162460, 0.262866},
193 {-0.864188, 0.442863, -0.238856},
194 {-0.951056, 0.162460, -0.262866},
195 {-0.809017, 0.309017, -0.500000},
196 {-0.864188, -0.442863, -0.238856},
197 {-0.951056, -0.162460, -0.262866},
198 {-0.809017, -0.309017, -0.500000},
199 {-0.681718, 0.147621, -0.716567},
200 {-0.681718, -0.147621, -0.716567},
201 {-0.850651, 0.000000, -0.525731},
202 {-0.688191, 0.587785, -0.425325},
203 {-0.587785, 0.425325, -0.688191},
204 {-0.425325, 0.688191, -0.587785},
205 {-0.425325, -0.688191, -0.587785},
206 {-0.587785, -0.425325, -0.688191},
207 {-0.688191, -0.587785, -0.425325},
208 };
209 
DirToByte(const vec3_t dir)210 int DirToByte( const vec3_t dir ) {
211 	int		i, best;
212 	float	d, bestd;
213 
214 	if( !dir ) {
215 		return 0;
216 	}
217 
218 	bestd = 0;
219 	best = 0;
220 	for( i = 0; i < NUMVERTEXNORMALS; i++ ) {
221 		d = DotProduct( dir, bytedirs[i] );
222 		if( d > bestd ) {
223 			bestd = d;
224 			best = i;
225 		}
226 	}
227 
228 	return best;
229 }
230 
ByteToDir(int index,vec3_t dir)231 void ByteToDir( int index, vec3_t dir ) {
232 	if( index < 0 || index >= NUMVERTEXNORMALS ) {
233 		Com_Error( ERR_FATAL, "ByteToDir: illegal index" );
234 	}
235 
236 	VectorCopy( bytedirs[index], dir );
237 }
238 
239 //============================================================================
240 
241 #ifdef __MSC_VER
242 #pragma optimize( "", off )
243 #endif
244 
RotatePointAroundVector(vec3_t dst,const vec3_t dir,const vec3_t point,float degrees)245 void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
246 {
247 	float	m[3][3];
248 	float	im[3][3];
249 	float	zrot[3][3];
250 	float	tmpmat[3][3];
251 	float	rot[3][3];
252 	int	i;
253 	vec3_t vr, vup, vf;
254 
255 	vf[0] = dir[0];
256 	vf[1] = dir[1];
257 	vf[2] = dir[2];
258 
259 	PerpendicularVector( vr, dir );
260 	CrossProduct( vr, vf, vup );
261 
262 	m[0][0] = vr[0];
263 	m[1][0] = vr[1];
264 	m[2][0] = vr[2];
265 
266 	m[0][1] = vup[0];
267 	m[1][1] = vup[1];
268 	m[2][1] = vup[2];
269 
270 	m[0][2] = vf[0];
271 	m[1][2] = vf[1];
272 	m[2][2] = vf[2];
273 
274 	memcpy( im, m, sizeof( im ) );
275 
276 	im[0][1] = m[1][0];
277 	im[0][2] = m[2][0];
278 	im[1][0] = m[0][1];
279 	im[1][2] = m[2][1];
280 	im[2][0] = m[0][2];
281 	im[2][1] = m[1][2];
282 
283 	memset( zrot, 0, sizeof( zrot ) );
284 	zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
285 
286 	zrot[0][0] = cos( DEG2RAD( degrees ) );
287 	zrot[0][1] = sin( DEG2RAD( degrees ) );
288 	zrot[1][0] = -sin( DEG2RAD( degrees ) );
289 	zrot[1][1] = cos( DEG2RAD( degrees ) );
290 
291 	R_ConcatRotations( m, zrot, tmpmat );
292 	R_ConcatRotations( tmpmat, im, rot );
293 
294 	for ( i = 0; i < 3; i++ )
295 	{
296 		dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
297 	}
298 }
299 
300 #ifdef __MSC_VER
301 #pragma optimize( "", on )
302 #endif
303 
304 
305 
AngleVectors(vec3_t angles,vec3_t forward,vec3_t right,vec3_t up)306 void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
307 {
308 	float		angle;
309 	float		sr, sp, sy, cr, cp, cy;
310 	// static to help MS compiler fp bugs
311 
312 	angle = angles[YAW] * (M_PI*2 / 360);
313 	sy = sin(angle);
314 	cy = cos(angle);
315 	angle = angles[PITCH] * (M_PI*2 / 360);
316 	sp = sin(angle);
317 	cp = cos(angle);
318 	angle = angles[ROLL] * (M_PI*2 / 360);
319 	sr = sin(angle);
320 	cr = cos(angle);
321 
322 	if (forward)
323 	{
324 		forward[0] = cp*cy;
325 		forward[1] = cp*sy;
326 		forward[2] = -sp;
327 	}
328 	if (right)
329 	{
330 		right[0] = (-1*sr*sp*cy+-1*cr*-sy);
331 		right[1] = (-1*sr*sp*sy+-1*cr*cy);
332 		right[2] = -1*sr*cp;
333 	}
334 	if (up)
335 	{
336 		up[0] = (cr*sp*cy+-sr*-sy);
337 		up[1] = (cr*sp*sy+-sr*cy);
338 		up[2] = cr*cp;
339 	}
340 }
341 
342 
ProjectPointOnPlane(vec3_t dst,const vec3_t p,const vec3_t normal)343 void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
344 {
345 	float d;
346 	vec3_t n;
347 	float inv_denom;
348 
349 	inv_denom = 1.0F / DotProduct( normal, normal );
350 
351 	d = DotProduct( normal, p ) * inv_denom;
352 
353 	n[0] = normal[0] * inv_denom;
354 	n[1] = normal[1] * inv_denom;
355 	n[2] = normal[2] * inv_denom;
356 
357 	dst[0] = p[0] - d * n[0];
358 	dst[1] = p[1] - d * n[1];
359 	dst[2] = p[2] - d * n[2];
360 }
361 
362 /*
363 ** assumes "src" is normalized
364 */
PerpendicularVector(vec3_t dst,const vec3_t src)365 void PerpendicularVector( vec3_t dst, const vec3_t src )
366 {
367 	int	pos;
368 	int i;
369 	float minelem = 1.0F;
370 	vec3_t tempvec;
371 
372 	/*
373 	** find the smallest magnitude axially aligned vector
374 	*/
375 	for ( pos = 0, i = 0; i < 3; i++ )
376 	{
377 		if ( fabs( src[i] ) < minelem )
378 		{
379 			pos = i;
380 			minelem = fabs( src[i] );
381 		}
382 	}
383 	tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
384 	tempvec[pos] = 1.0F;
385 
386 	/*
387 	** project the point onto the plane defined by src
388 	*/
389 	ProjectPointOnPlane( dst, tempvec, src );
390 
391 	/*
392 	** normalize the result
393 	*/
394 	VectorNormalize( dst );
395 }
396 
397 
398 
399 /*
400 ================
401 R_ConcatRotations
402 ================
403 */
R_ConcatRotations(float in1[3][3],float in2[3][3],float out[3][3])404 void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
405 {
406 	out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
407 				in1[0][2] * in2[2][0];
408 	out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
409 				in1[0][2] * in2[2][1];
410 	out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
411 				in1[0][2] * in2[2][2];
412 	out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
413 				in1[1][2] * in2[2][0];
414 	out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
415 				in1[1][2] * in2[2][1];
416 	out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
417 				in1[1][2] * in2[2][2];
418 	out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
419 				in1[2][2] * in2[2][0];
420 	out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
421 				in1[2][2] * in2[2][1];
422 	out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
423 				in1[2][2] * in2[2][2];
424 }
425 
426 
427 /*
428 ================
429 R_ConcatTransforms
430 ================
431 */
R_ConcatTransforms(float in1[3][4],float in2[3][4],float out[3][4])432 void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
433 {
434 	out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
435 				in1[0][2] * in2[2][0];
436 	out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
437 				in1[0][2] * in2[2][1];
438 	out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
439 				in1[0][2] * in2[2][2];
440 	out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
441 				in1[0][2] * in2[2][3] + in1[0][3];
442 	out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
443 				in1[1][2] * in2[2][0];
444 	out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
445 				in1[1][2] * in2[2][1];
446 	out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
447 				in1[1][2] * in2[2][2];
448 	out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
449 				in1[1][2] * in2[2][3] + in1[1][3];
450 	out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
451 				in1[2][2] * in2[2][0];
452 	out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
453 				in1[2][2] * in2[2][1];
454 	out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
455 				in1[2][2] * in2[2][2];
456 	out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
457 				in1[2][2] * in2[2][3] + in1[2][3];
458 }
459 
460 
461 //============================================================================
462 
463 
Q_fabs(float f)464 float Q_fabs( float f ) {
465 	uint32 tmp = *( uint32 * )&f;
466 	tmp &= 0x7FFFFFFF;
467 	return *( float * )&tmp;
468 }
469 
470 #if id386 && ( defined _MSC_VER )
471 #pragma warning( disable:4035 )
Q_ftol(float f)472 __declspec( naked ) long Q_ftol( float f )
473 {
474 	static int tmp;
475 	__asm fld dword ptr [esp+4]
476 	__asm fistp tmp
477 	__asm mov eax, tmp
478 	__asm ret
479 }
480 #pragma warning( default:4035 )
481 #endif
482 
483 /*
484 ===============
485 LerpAngle
486 
487 ===============
488 */
LerpAngle(float a2,float a1,float frac)489 float LerpAngle (float a2, float a1, float frac)
490 {
491 	if (a1 - a2 > 180)
492 		a1 -= 360;
493 	if (a1 - a2 < -180)
494 		a1 += 360;
495 	return a2 + frac * (a1 - a2);
496 }
497 
498 
anglemod(float a)499 float	anglemod(float a)
500 {
501 	a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535);
502 	return a;
503 }
504 
505 // this is the slow, general version
BoxOnPlaneSide2(vec3_t emins,vec3_t emaxs,struct cplane_s * p)506 int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
507 {
508 	int		i;
509 	float	dist1, dist2;
510 	int		sides;
511 	vec3_t	corners[2];
512 
513 	for (i=0 ; i<3 ; i++)
514 	{
515 		if (p->normal[i] < 0)
516 		{
517 			corners[0][i] = emins[i];
518 			corners[1][i] = emaxs[i];
519 		}
520 		else
521 		{
522 			corners[1][i] = emins[i];
523 			corners[0][i] = emaxs[i];
524 		}
525 	}
526 	dist1 = DotProduct (p->normal, corners[0]) - p->dist;
527 	dist2 = DotProduct (p->normal, corners[1]) - p->dist;
528 	sides = 0;
529 	if (dist1 >= 0)
530 		sides = 1;
531 	if (dist2 < 0)
532 		sides |= 2;
533 
534 	return sides;
535 }
536 
537 /*
538 ==================
539 BoxOnPlaneSide
540 
541 Returns 1, 2, or 1 + 2
542 ==================
543 */
544 #if !id386 || !defined _MSC_VER
BoxOnPlaneSide(vec3_t emins,vec3_t emaxs,cplane_t * p)545 int BoxOnPlaneSide( vec3_t emins, vec3_t emaxs, cplane_t *p )
546 {
547 	float	dist1, dist2;
548 	int		sides;
549 
550 // fast axial cases
551 	if (p->type < 3)
552 	{
553 		if (p->dist <= emins[p->type])
554 			return 1;
555 		if (p->dist >= emaxs[p->type])
556 			return 2;
557 		return 3;
558 	}
559 
560 // general case
561 	switch (p->signbits)
562 	{
563 	case 0:
564 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
565 dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
566 		break;
567 	case 1:
568 dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
569 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
570 		break;
571 	case 2:
572 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
573 dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
574 		break;
575 	case 3:
576 dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
577 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
578 		break;
579 	case 4:
580 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
581 dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
582 		break;
583 	case 5:
584 dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
585 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
586 		break;
587 	case 6:
588 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
589 dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
590 		break;
591 	case 7:
592 dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
593 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
594 		break;
595 	default:
596 		dist1 = dist2 = 0;		// shut up compiler
597 		break;
598 	}
599 
600 	sides = 0;
601 	if (dist1 >= p->dist)
602 		sides = 1;
603 	if (dist2 < p->dist)
604 		sides |= 2;
605 
606 	return sides;
607 }
608 #else
609 #pragma warning( disable: 4035 )
610 
BoxOnPlaneSide(vec3_t emins,vec3_t emaxs,cplane_t * p)611 __declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, cplane_t *p)
612 {
613 	static int bops_initialized;
614 	static int Ljmptab[8];
615 
616 	__asm {
617 
618 		push ebx
619 
620 		cmp bops_initialized, 1
621 		je  initialized
622 		mov bops_initialized, 1
623 
624 		mov Ljmptab[0*4], offset Lcase0
625 		mov Ljmptab[1*4], offset Lcase1
626 		mov Ljmptab[2*4], offset Lcase2
627 		mov Ljmptab[3*4], offset Lcase3
628 		mov Ljmptab[4*4], offset Lcase4
629 		mov Ljmptab[5*4], offset Lcase5
630 		mov Ljmptab[6*4], offset Lcase6
631 		mov Ljmptab[7*4], offset Lcase7
632 
633 initialized:
634 
635 		mov edx,ds:dword ptr[4+12+esp]
636 		mov ecx,ds:dword ptr[4+4+esp]
637 		xor eax,eax
638 		mov ebx,ds:dword ptr[4+8+esp]
639 		mov al,ds:byte ptr[17+edx]
640 		cmp al,8
641 		jge Lerror
642 		fld ds:dword ptr[0+edx]
643 		fld st(0)
644 		jmp dword ptr[Ljmptab+eax*4]
645 Lcase0:
646 		fmul ds:dword ptr[ebx]
647 		fld ds:dword ptr[0+4+edx]
648 		fxch st(2)
649 		fmul ds:dword ptr[ecx]
650 		fxch st(2)
651 		fld st(0)
652 		fmul ds:dword ptr[4+ebx]
653 		fld ds:dword ptr[0+8+edx]
654 		fxch st(2)
655 		fmul ds:dword ptr[4+ecx]
656 		fxch st(2)
657 		fld st(0)
658 		fmul ds:dword ptr[8+ebx]
659 		fxch st(5)
660 		faddp st(3),st(0)
661 		fmul ds:dword ptr[8+ecx]
662 		fxch st(1)
663 		faddp st(3),st(0)
664 		fxch st(3)
665 		faddp st(2),st(0)
666 		jmp LSetSides
667 Lcase1:
668 		fmul ds:dword ptr[ecx]
669 		fld ds:dword ptr[0+4+edx]
670 		fxch st(2)
671 		fmul ds:dword ptr[ebx]
672 		fxch st(2)
673 		fld st(0)
674 		fmul ds:dword ptr[4+ebx]
675 		fld ds:dword ptr[0+8+edx]
676 		fxch st(2)
677 		fmul ds:dword ptr[4+ecx]
678 		fxch st(2)
679 		fld st(0)
680 		fmul ds:dword ptr[8+ebx]
681 		fxch st(5)
682 		faddp st(3),st(0)
683 		fmul ds:dword ptr[8+ecx]
684 		fxch st(1)
685 		faddp st(3),st(0)
686 		fxch st(3)
687 		faddp st(2),st(0)
688 		jmp LSetSides
689 Lcase2:
690 		fmul ds:dword ptr[ebx]
691 		fld ds:dword ptr[0+4+edx]
692 		fxch st(2)
693 		fmul ds:dword ptr[ecx]
694 		fxch st(2)
695 		fld st(0)
696 		fmul ds:dword ptr[4+ecx]
697 		fld ds:dword ptr[0+8+edx]
698 		fxch st(2)
699 		fmul ds:dword ptr[4+ebx]
700 		fxch st(2)
701 		fld st(0)
702 		fmul ds:dword ptr[8+ebx]
703 		fxch st(5)
704 		faddp st(3),st(0)
705 		fmul ds:dword ptr[8+ecx]
706 		fxch st(1)
707 		faddp st(3),st(0)
708 		fxch st(3)
709 		faddp st(2),st(0)
710 		jmp LSetSides
711 Lcase3:
712 		fmul ds:dword ptr[ecx]
713 		fld ds:dword ptr[0+4+edx]
714 		fxch st(2)
715 		fmul ds:dword ptr[ebx]
716 		fxch st(2)
717 		fld st(0)
718 		fmul ds:dword ptr[4+ecx]
719 		fld ds:dword ptr[0+8+edx]
720 		fxch st(2)
721 		fmul ds:dword ptr[4+ebx]
722 		fxch st(2)
723 		fld st(0)
724 		fmul ds:dword ptr[8+ebx]
725 		fxch st(5)
726 		faddp st(3),st(0)
727 		fmul ds:dword ptr[8+ecx]
728 		fxch st(1)
729 		faddp st(3),st(0)
730 		fxch st(3)
731 		faddp st(2),st(0)
732 		jmp LSetSides
733 Lcase4:
734 		fmul ds:dword ptr[ebx]
735 		fld ds:dword ptr[0+4+edx]
736 		fxch st(2)
737 		fmul ds:dword ptr[ecx]
738 		fxch st(2)
739 		fld st(0)
740 		fmul ds:dword ptr[4+ebx]
741 		fld ds:dword ptr[0+8+edx]
742 		fxch st(2)
743 		fmul ds:dword ptr[4+ecx]
744 		fxch st(2)
745 		fld st(0)
746 		fmul ds:dword ptr[8+ecx]
747 		fxch st(5)
748 		faddp st(3),st(0)
749 		fmul ds:dword ptr[8+ebx]
750 		fxch st(1)
751 		faddp st(3),st(0)
752 		fxch st(3)
753 		faddp st(2),st(0)
754 		jmp LSetSides
755 Lcase5:
756 		fmul ds:dword ptr[ecx]
757 		fld ds:dword ptr[0+4+edx]
758 		fxch st(2)
759 		fmul ds:dword ptr[ebx]
760 		fxch st(2)
761 		fld st(0)
762 		fmul ds:dword ptr[4+ebx]
763 		fld ds:dword ptr[0+8+edx]
764 		fxch st(2)
765 		fmul ds:dword ptr[4+ecx]
766 		fxch st(2)
767 		fld st(0)
768 		fmul ds:dword ptr[8+ecx]
769 		fxch st(5)
770 		faddp st(3),st(0)
771 		fmul ds:dword ptr[8+ebx]
772 		fxch st(1)
773 		faddp st(3),st(0)
774 		fxch st(3)
775 		faddp st(2),st(0)
776 		jmp LSetSides
777 Lcase6:
778 		fmul ds:dword ptr[ebx]
779 		fld ds:dword ptr[0+4+edx]
780 		fxch st(2)
781 		fmul ds:dword ptr[ecx]
782 		fxch st(2)
783 		fld st(0)
784 		fmul ds:dword ptr[4+ecx]
785 		fld ds:dword ptr[0+8+edx]
786 		fxch st(2)
787 		fmul ds:dword ptr[4+ebx]
788 		fxch st(2)
789 		fld st(0)
790 		fmul ds:dword ptr[8+ecx]
791 		fxch st(5)
792 		faddp st(3),st(0)
793 		fmul ds:dword ptr[8+ebx]
794 		fxch st(1)
795 		faddp st(3),st(0)
796 		fxch st(3)
797 		faddp st(2),st(0)
798 		jmp LSetSides
799 Lcase7:
800 		fmul ds:dword ptr[ecx]
801 		fld ds:dword ptr[0+4+edx]
802 		fxch st(2)
803 		fmul ds:dword ptr[ebx]
804 		fxch st(2)
805 		fld st(0)
806 		fmul ds:dword ptr[4+ecx]
807 		fld ds:dword ptr[0+8+edx]
808 		fxch st(2)
809 		fmul ds:dword ptr[4+ebx]
810 		fxch st(2)
811 		fld st(0)
812 		fmul ds:dword ptr[8+ecx]
813 		fxch st(5)
814 		faddp st(3),st(0)
815 		fmul ds:dword ptr[8+ebx]
816 		fxch st(1)
817 		faddp st(3),st(0)
818 		fxch st(3)
819 		faddp st(2),st(0)
820 LSetSides:
821 		faddp st(2),st(0)
822 		fcomp ds:dword ptr[12+edx]
823 		xor ecx,ecx
824 		fnstsw ax
825 		fcomp ds:dword ptr[12+edx]
826 		and ah,1
827 		xor ah,1
828 		add cl,ah
829 		fnstsw ax
830 		and ah,1
831 		add ah,ah
832 		add cl,ah
833 		pop ebx
834 		mov eax,ecx
835 		ret
836 Lerror:
837 		int 3
838 	}
839 }
840 #pragma warning( default: 4035 )
841 #endif
842 
ClearBounds(vec3_t mins,vec3_t maxs)843 void ClearBounds (vec3_t mins, vec3_t maxs)
844 {
845 	mins[0] = mins[1] = mins[2] = 99999;
846 	maxs[0] = maxs[1] = maxs[2] = -99999;
847 }
848 
AddPointToBounds(const vec3_t v,vec3_t mins,vec3_t maxs)849 void AddPointToBounds (const vec3_t v, vec3_t mins, vec3_t maxs)
850 {
851 	int		i;
852 	vec_t	val;
853 
854 	for (i=0 ; i<3 ; i++)
855 	{
856 		val = v[i];
857 		if (val < mins[i])
858 			mins[i] = val;
859 		if (val > maxs[i])
860 			maxs[i] = val;
861 	}
862 }
863 
UnionBounds(vec3_t a[2],vec3_t b[2],vec3_t c[2])864 void UnionBounds( vec3_t a[2], vec3_t b[2], vec3_t c[2] ) {
865 	c[0][0] = b[0][0] < a[0][0] ? b[0][0] : a[0][0];
866 	c[0][1] = b[0][1] < a[0][1] ? b[0][1] : a[0][1];
867 	c[0][2] = b[0][2] < a[0][2] ? b[0][2] : a[0][2];
868 
869 	c[1][0] = b[1][0] > a[1][0] ? b[1][0] : a[1][0];
870 	c[1][1] = b[1][1] > a[1][1] ? b[1][1] : a[1][1];
871 	c[1][2] = b[1][2] > a[1][2] ? b[1][2] : a[1][2];
872 }
873 
VectorNormalize(vec3_t v)874 vec_t VectorNormalize (vec3_t v)
875 {
876 	float	length, ilength;
877 
878 	length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
879 	length = sqrt (length);		// FIXME
880 
881 	if (length)
882 	{
883 		ilength = 1/length;
884 		v[0] *= ilength;
885 		v[1] *= ilength;
886 		v[2] *= ilength;
887 	}
888 
889 	return length;
890 
891 }
892 
VectorNormalize2(vec3_t v,vec3_t out)893 vec_t VectorNormalize2 (vec3_t v, vec3_t out)
894 {
895 	float	length, ilength;
896 
897 	length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
898 	length = sqrt (length);		// FIXME
899 
900 	if (length)
901 	{
902 		ilength = 1/length;
903 		out[0] = v[0]*ilength;
904 		out[1] = v[1]*ilength;
905 		out[2] = v[2]*ilength;
906 	}
907 
908 	return length;
909 
910 }
911 
912 /*
913 =================
914 RadiusFromBounds
915 =================
916 */
RadiusFromBounds(const vec3_t mins,const vec3_t maxs)917 vec_t RadiusFromBounds (const vec3_t mins, const vec3_t maxs)
918 {
919 	int		i;
920 	vec3_t	corner;
921 	vec_t a, b;
922 
923 	for (i=0 ; i<3 ; i++)
924 	{
925 		a = fabs(mins[i]);
926 		b = fabs(maxs[i]);
927 		corner[i] = a > b ? a : b;
928 	}
929 
930 	return VectorLength (corner);
931 }
932 
933 #if 0
934 void _VectorMA( vec3_t veca, float scale, vec3_t vecb, vec3_t vecc )
935 {
936 	vecc[0] = veca[0] + scale*vecb[0];
937 	vecc[1] = veca[1] + scale*vecb[1];
938 	vecc[2] = veca[2] + scale*vecb[2];
939 }
940 
941 
942 vec_t _DotProduct (vec3_t v1, vec3_t v2)
943 {
944 	return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
945 }
946 
947 void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out)
948 {
949 	out[0] = veca[0]-vecb[0];
950 	out[1] = veca[1]-vecb[1];
951 	out[2] = veca[2]-vecb[2];
952 }
953 
954 void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out)
955 {
956 	out[0] = veca[0]+vecb[0];
957 	out[1] = veca[1]+vecb[1];
958 	out[2] = veca[2]+vecb[2];
959 }
960 
961 void _VectorCopy (vec3_t in, vec3_t out)
962 {
963 	out[0] = in[0];
964 	out[1] = in[1];
965 	out[2] = in[2];
966 }
967 
968 void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
969 {
970 	cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
971 	cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
972 	cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
973 }
974 
975 double sqrt(double x);
976 
977 vec_t VectorLength(vec3_t v)
978 {
979 	int		i;
980 	float	length;
981 
982 	length = 0;
983 	for (i=0 ; i< 3 ; i++)
984 		length += v[i]*v[i];
985 	length = sqrt (length);		// FIXME
986 
987 	return length;
988 }
989 
990 void _VectorNegate (vec3_t v)
991 {
992 	v[0] = -v[0];
993 	v[1] = -v[1];
994 	v[2] = -v[2];
995 }
996 
997 void _VectorScale (vec3_t in, vec_t scale, vec3_t out)
998 {
999 	out[0] = in[0]*scale;
1000 	out[1] = in[1]*scale;
1001 	out[2] = in[2]*scale;
1002 }
1003 #endif
1004 
Q_log2(int val)1005 int Q_log2(int val)
1006 {
1007 	int answer=0;
1008 	while (val>>=1)
1009 		answer++;
1010 	return answer;
1011 }
1012 
1013 /*
1014 ===============
1015 Q_CeilPowerOfTwo
1016 ===============
1017 */
Q_CeilPowerOfTwo(int value)1018 int Q_CeilPowerOfTwo( int value ) {
1019 	int i;
1020 
1021 	for( i = 1; i < value; i <<= 1 )
1022 		;
1023 
1024 	return i;
1025 }
1026 
1027 
1028 /*
1029 ====================
1030 Com_CalcFov
1031 ====================
1032 */
Com_CalcFov(float fov_x,float width,float height)1033 float Com_CalcFov( float fov_x, float width, float height ) {
1034 	float	a;
1035 	float	x;
1036 
1037 	if( fov_x < 1 || fov_x > 179 )
1038 		Com_Error( ERR_DROP, "Com_CalcFov: bad fov: %f", fov_x );
1039 
1040 	x = width / tan( fov_x / 360 * M_PI );
1041 
1042 	a = atan( height / x );
1043 	a = a * 360/ M_PI;
1044 
1045 	return a;
1046 }
1047 
SetPlaneType(cplane_t * plane)1048 void SetPlaneType( cplane_t *plane ) {
1049 	vec_t *normal = plane->normal;
1050 
1051 	if( normal[0] == 1 ) {
1052 		plane->type = PLANE_X;
1053 		return;
1054 	}
1055 	if( normal[1] == 1 ) {
1056 		plane->type = PLANE_Y;
1057 		return;
1058 	}
1059 	if( normal[2] == 1 ) {
1060 		plane->type = PLANE_Z;
1061 		return;
1062 	}
1063 
1064 	plane->type = PLANE_NON_AXIAL;
1065 }
1066 
SetPlaneSignbits(cplane_t * plane)1067 void SetPlaneSignbits( cplane_t *plane ) {
1068     int bits = 0;
1069 
1070     if( plane->normal[0] < 0 ) {
1071         bits |= 1;
1072     }
1073     if( plane->normal[1] < 0 ) {
1074         bits |= 2;
1075     }
1076     if( plane->normal[2] < 0 ) {
1077         bits |= 4;
1078     }
1079     plane->signbits = bits;
1080 }
1081 
1082 
1083 
1084 //====================================================================================
1085 
1086 /*
1087 ============
1088 COM_SkipPath
1089 ============
1090 */
COM_SkipPath(const char * pathname)1091 char *COM_SkipPath( const char *pathname ) {
1092 	char	*last;
1093 
1094 	if( !pathname ) {
1095 		Com_Error( ERR_FATAL, "COM_SkipPath: NULL" );
1096 	}
1097 
1098 	last = (char *)pathname;
1099 	while( *pathname ) {
1100 		if( *pathname == '/' )
1101 			last = (char *)pathname + 1;
1102 		pathname++;
1103 	}
1104 	return last;
1105 }
1106 
1107 /*
1108 ============
1109 COM_StripExtension
1110 ============
1111 */
COM_StripExtension(const char * in,char * out,int outSize)1112 void COM_StripExtension( const char *in, char *out, int outSize ) {
1113 	char *s;
1114 
1115 	Q_strncpyz( out, in, outSize );
1116 
1117 	s = out + strlen( out );
1118 
1119 	while( s != out ) {
1120 		if( *s == '/' ) {
1121 			break;
1122 		}
1123 		if( *s == '.' ) {
1124 			*s = 0;
1125 			break;
1126 		}
1127 		s--;
1128 	}
1129 }
1130 
1131 /*
1132 ============
1133 COM_FileExtension
1134 ============
1135 */
COM_FileExtension(const char * in)1136 char *COM_FileExtension( const char *in ) {
1137 	const char *s;
1138 	const char *last;
1139 
1140 	if( !in ) {
1141 		Com_Error( ERR_FATAL, "COM_FileExtension: NULL" );
1142 	}
1143 
1144 	s = in + strlen( in );
1145 	last = s;
1146 
1147 	while( s != in ) {
1148 		if( *s == '/' ) {
1149 			break;
1150 		}
1151 		if( *s == '.' ) {
1152 			return (char *)s;
1153 		}
1154 		s--;
1155 	}
1156 
1157 	return (char *)last;
1158 }
1159 
1160 /*
1161 ============
1162 COM_FileBase
1163 ============
1164 */
COM_FileBase(char * in,char * out)1165 void COM_FileBase (char *in, char *out)
1166 {
1167 	char *s, *s2;
1168 
1169 	s = in + strlen(in) - 1;
1170 
1171 	while (s != in && *s != '.')
1172 		s--;
1173 
1174 	for (s2 = s ; s2 != in && *s2 != '/' ; s2--)
1175 	;
1176 
1177 	if (s-s2 < 2)
1178 		out[0] = 0;
1179 	else
1180 	{
1181 		s--;
1182 		strncpy (out,s2+1, s-s2);
1183 		out[s-s2] = 0;
1184 	}
1185 }
1186 
1187 /*
1188 ============
1189 COM_FilePath
1190 
1191 Returns the path up to, but not including the last /
1192 ============
1193 */
COM_FilePath(const char * in,char * out,int outSize)1194 void COM_FilePath( const char *in, char *out, int outSize ) {
1195 	char *s;
1196 
1197 	Q_strncpyz( out, in, outSize );
1198 
1199 	s = out + strlen( out );
1200 
1201 	while( s != out && *s != '/' )
1202 		s--;
1203 
1204 	*s = 0;
1205 }
1206 
1207 
1208 /*
1209 ==================
1210 COM_DefaultExtension
1211 ==================
1212 */
COM_DefaultExtension(char * path,const char * extension,int pathSize)1213 void COM_DefaultExtension( char *path, const char *extension, int pathSize ) {
1214 	char    *src;
1215 //
1216 // if path doesn't have a .EXT, append extension
1217 // (extension should include the .)
1218 //
1219 	if( *path ) {
1220 		src = path + strlen( path ) - 1;
1221 
1222 		while( *src != '/' && src != path ) {
1223 			if( *src == '.' )
1224 				return;                 // it has an extension
1225 			src--;
1226 		}
1227 	}
1228 
1229 	Q_strcat( path, pathSize, extension );
1230 }
1231 
1232 /*
1233 ==================
1234 COM_IsNumeric
1235 
1236 Returns true if the given string is valid representation
1237 of floating point or integer number.
1238 ==================
1239 */
COM_IsNumeric(const char * string)1240 qboolean COM_IsNumeric( const char *string ) {
1241 	int c;
1242 
1243 	if( !string ) {
1244 		return qfalse;
1245 	}
1246 
1247 	if( !*string ) {
1248 		return qfalse;
1249 	}
1250 
1251 	do {
1252 		c = *string++;
1253 		if( Q_isdigit( c ) ) {
1254 			continue;
1255 		}
1256 		if( c != '-' && c != '.' && c != ' ' ) {
1257 			return qfalse;
1258 		}
1259 	} while( *string );
1260 
1261 	return qtrue;
1262 
1263 }
1264 
1265 /* Parses hexadecimal number until it encounters
1266  * illegible symbol or end of string.
1267  * Does not check for overflow.
1268  */
COM_ParseHex(const char * string)1269 uint32 COM_ParseHex( const char *string ) {
1270 	int ch;
1271 	uint32 result, digit;
1272 
1273 	result = 0;
1274 	while( *string ) {
1275 		ch = *string++;
1276 		if( ch >= '0' && ch <= '9' ) {
1277 			digit = ch - '0';
1278 		} else if( ch >= 'a' && ch <= 'f' ) {
1279 			digit = ch - 'a' + 10;
1280 		} else if( ch >= 'A' && ch <= 'F' ) {
1281 			digit = ch - 'A' + 10;
1282 		} else {
1283 			break;
1284 		}
1285 
1286 		result = digit | ( result << 4 );
1287 	}
1288 
1289 	return result;
1290 
1291 }
1292 
1293 /*
1294 =================
1295 SortStrcmp
1296 =================
1297 */
SortStrcmp(const void * p1,const void * p2)1298 int SortStrcmp( const void *p1, const void *p2 ) {
1299 	const char *s1 = *(const char **)p1;
1300 	const char *s2 = *(const char **)p2;
1301 
1302 	return strcmp( s1, s2 );
1303 }
1304 
1305 /*
1306 =================
1307 Com_WildCmp
1308 
1309 Wildcard compare.
1310 Returns non-zero if matches, zero otherwise.
1311 =================
1312 */
Com_WildCmp(const char * filter,const char * string,qboolean ignoreCase)1313 int Com_WildCmp( const char *filter, const char *string, qboolean ignoreCase ) {
1314 	switch( *filter ) {
1315 	case '\0':
1316 		return !*string;
1317 
1318 	case '*':
1319 		return Com_WildCmp( filter + 1, string, ignoreCase ) || (*string && Com_WildCmp( filter, string + 1, ignoreCase ));
1320 
1321 	case '?':
1322 		return *string && Com_WildCmp( filter + 1, string + 1, ignoreCase );
1323 
1324 	default:
1325 		return ((*filter == *string) || (ignoreCase && (Q_toupper( *filter ) == Q_toupper( *string )))) && Com_WildCmp( filter + 1, string + 1, ignoreCase );
1326 	}
1327 }
1328 
1329 /*
1330 ================
1331 Com_HashString
1332 ================
1333 */
Com_HashString(const char * string,int hashSize)1334 uint32 Com_HashString( const char *string, int hashSize ) {
1335 	uint32 hash;
1336 	uint32 c;
1337 
1338 	hash = 0;
1339 	while( *string ) {
1340 		c = *string++;
1341 		hash = 127 * hash + c;
1342 	}
1343 
1344 	hash = ( hash >> 20 ) ^ ( hash >> 10 ) ^ hash;
1345 	return hash & ( hashSize - 1 );
1346 
1347 }
1348 
1349 /*
1350 ================
1351 Com_HashPath
1352 ================
1353 */
Com_HashPath(const char * string,int hashSize)1354 uint32 Com_HashPath( const char *string, int hashSize ) {
1355 	uint32 hash;
1356 	uint32 c;
1357 
1358 	hash = 0;
1359 	while( *string ) {
1360 		c = *string++;
1361 		if( c == '\\' ) {
1362 			c = '/';
1363 		}
1364 		hash = 127 * hash + c;
1365 	}
1366 
1367 	hash = ( hash >> 20 ) ^ ( hash >> 10 ) ^ hash;
1368 	return hash & ( hashSize - 1 );
1369 
1370 }
1371 
1372 /*
1373 ================
1374 Com_ReplaceSeparators
1375 ================
1376 */
Com_ReplaceSeparators(char * s,int separator)1377 char *Com_ReplaceSeparators( char *s, int separator ) {
1378 	char *p;
1379 
1380 	p = s;
1381 	while( *p ) {
1382 		if( *p == '/' || *p == '\\' ) {
1383 			*p = separator;
1384 		}
1385 		p++;
1386 	}
1387 
1388 	return s;
1389 }
1390 
1391 /*
1392 ================
1393 Q_DrawStrlen
1394 ================
1395 */
Q_DrawStrlen(const char * string)1396 int Q_DrawStrlen( const char *string ) {
1397 	int length;
1398 
1399 	length = 0;
1400 	while( *string ) {
1401 		if( Q_IsColorString( string ) ) {
1402 			string++;
1403 		} else {
1404 			length++;
1405 		}
1406 		string++;
1407 	}
1408 
1409 	return length;
1410 }
1411 
1412 /*
1413 ================
1414 Q_DrawStrlenTo
1415 ================
1416 */
Q_DrawStrlenTo(const char * string,int maxChars)1417 int Q_DrawStrlenTo( const char *string, int maxChars ) {
1418 	int length;
1419 
1420 	if( maxChars < 1 ) {
1421 		maxChars = MAX_STRING_CHARS;
1422 	}
1423 
1424 	length = 0;
1425 	while( *string && maxChars-- ) {
1426 		if( Q_IsColorString( string ) ) {
1427 			string++;
1428 		} else {
1429 			length++;
1430 		}
1431 		string++;
1432 	}
1433 
1434 	return length;
1435 }
1436 
1437 /*
1438 ================
1439 Q_CleanColorStr
1440 
1441 Removes color escape codes, high-bit and unprintable characters.
1442 Return number of characters written, not including the NULL character.
1443 ================
1444 */
Q_CleanColorStr(const char * string,char * buffer,int bufferSize)1445 int Q_CleanColorStr( const char *string, char *buffer, int bufferSize ) {
1446 	byte *last, *src, *dst;
1447 
1448 	if( bufferSize < 1 ) {
1449 		Com_Error( ERR_FATAL, "Q_CleanStr: bufferSize < 1" );
1450 	}
1451 
1452 	src = ( byte * )string;
1453 	dst = ( byte * )buffer;
1454 	last = ( byte * )buffer + bufferSize - 1;
1455 	while( *src && dst != last ) {
1456 		if( Q_IsColorString( src ) ) {
1457 			src += 2;
1458 			continue;
1459 		}
1460 		if( *src < 32 || *src > 127 ) {
1461 			src++;
1462 			continue;
1463 		}
1464 		*dst++ = *src++;
1465 	}
1466 
1467 	*dst = 0;
1468 
1469 	return ( int )( dst - ( byte * )buffer );
1470 }
1471 
1472 /*
1473 ================
1474 Q_CleanStr
1475 
1476 Removes high-bit and unprintable characters.
1477 Return number of characters written, not including the NULL character.
1478 ================
1479 */
Q_CleanStr(const char * string,char * buffer,int bufferSize)1480 int Q_CleanStr( const char *string, char *buffer, int bufferSize ) {
1481 	byte *last, *src, *dst;
1482 
1483 	if( bufferSize < 1 ) {
1484 		Com_Error( ERR_FATAL, "Q_CleanStr: bufferSize < 1" );
1485 	}
1486 
1487 	src = ( byte * )string;
1488 	dst = ( byte * )buffer;
1489 	last = ( byte * )buffer + bufferSize - 1;
1490 	while( *src && dst != last ) {
1491 		if( *src < 32 || *src > 127 ) {
1492 			src++;
1493 			continue;
1494 		}
1495 		*dst++ = *src++;
1496 	}
1497 
1498 	*dst = 0;
1499 
1500 	return ( int )( dst - ( byte * )buffer );
1501 }
1502 
1503 /*
1504 ================
1505 Q_IsWhiteSpace
1506 ================
1507 */
Q_IsWhiteSpace(const char * string)1508 qboolean Q_IsWhiteSpace( const char *string ) {
1509 	while( *string ) {
1510 		if( ( *string & 127 ) > 32 ) {
1511 			return qfalse;
1512 		}
1513 		string++;
1514 	}
1515 
1516 	return qtrue;
1517 }
1518 
1519 /*
1520 ================
1521 Q_FormatString
1522 
1523 replaces some common escape codes and unprintable characters
1524 ================
1525 */
Q_FormatString(const char * string)1526 char *Q_FormatString( const char *string ) {
1527 	static const char *hexchars = "0123456789ABCDEF";
1528 	static char buffer[MAX_STRING_CHARS];
1529 	char	*dst;
1530 	int		c;
1531 
1532 	dst = buffer;
1533 	while( *string ) {
1534 		c = *string++;
1535 
1536 		switch( c ) {
1537 		case '\t':
1538 			*dst++ = '\\';
1539 			*dst++ = 't';
1540 			break;
1541 		case '\b':
1542 			*dst++ = '\\';
1543 			*dst++ = 'b';
1544 			break;
1545 		case '\r':
1546 			*dst++ = '\\';
1547 			*dst++ = 'r';
1548 			break;
1549 		case '\n':
1550 			*dst++ = '\\';
1551 			*dst++ = 'n';
1552 			break;
1553 		case '\\':
1554 			*dst++ = '\\';
1555 			*dst++ = '\\';
1556 			break;
1557 		case '\"':
1558 			*dst++ = '\\';
1559 			*dst++ = '\"';
1560 			break;
1561 		default:
1562 			if( c < 32 || c > 127 ) {
1563 				*dst++ = '\\';
1564 				*dst++ = 'x';
1565 				*dst++ = hexchars[c << 4];
1566 				*dst++ = hexchars[c & 15];
1567 			} else {
1568 				*dst++ = c;
1569 			}
1570 			break;
1571 		}
1572 
1573 		if( dst - buffer >= MAX_STRING_CHARS - 4 ) {
1574 			break;
1575 		}
1576 	}
1577 
1578 	*dst = 0;
1579 
1580 	return buffer;
1581 }
1582 
1583 /*
1584 ================
1585 Q_UnescapeString
1586 ================
1587 */
Q_UnescapeString(const char * string)1588 char *Q_UnescapeString( const char *string ) {
1589 	static char buffer[MAX_STRING_CHARS];
1590 	char	*dst, *last;
1591 	int		c;
1592 
1593 	dst = buffer;
1594 	last = buffer + MAX_STRING_CHARS - 1;
1595 	while( *string && dst != last ) {
1596 		c = *string++;
1597 
1598 		if( c != '\\' ) {
1599 			*dst++ = c;
1600 			continue;
1601 		}
1602 
1603 		c = *string++;
1604 		if( c == 0 ) {
1605 			break;
1606 		}
1607 		switch( c ) {
1608 		case 't':
1609 			c = '\t';
1610 			break;
1611 		case 'b':
1612 			c = '\b';
1613 			break;
1614 		case 'r':
1615 			c = '\r';
1616 			break;
1617 		case 'n':
1618 			c = '\n';
1619 			break;
1620 		case '\\':
1621 			c = '\\';
1622 			break;
1623 		default:
1624 			break;
1625 		}
1626 
1627 		*dst++ = c;
1628 	}
1629 
1630 	*dst = 0;
1631 
1632 	return buffer;
1633 
1634 }
1635 
1636 /*
1637 ================
1638 Com_LocalTime
1639 ================
1640 */
Com_LocalTime(qtime_t * qtime)1641 void Com_LocalTime( qtime_t *qtime ) {
1642 #ifndef _WIN32_WCE
1643 	time_t clock;
1644 	struct tm	*localTime;
1645 
1646 	time( &clock );
1647 	localTime = localtime( &clock );
1648 
1649 	*qtime = *localTime;
1650 #else
1651 	memset( qtime, 0, sizeof( *qtime ) );
1652 #endif
1653 }
1654 
1655 /*
1656 ============================================================================
1657 
1658 					BYTE ORDER FUNCTIONS
1659 
1660 ============================================================================
1661 */
1662 
ShortSwap(short l)1663 short ShortSwap( short l ) {
1664 	byte    b1, b2;
1665 
1666 	b1 = l & 255;
1667 	b2 = ( l >> 8 ) & 255;
1668 
1669 	return ( b1 << 8 ) + b2;
1670 }
1671 
LongSwap(int l)1672 int LongSwap( int l ) {
1673 	byte    b1, b2, b3, b4;
1674 
1675 	b1 = l & 255;
1676 	b2 = ( l >>  8 ) & 255;
1677 	b3 = ( l >> 16 ) & 255;
1678 	b4 = ( l >> 24 ) & 255;
1679 
1680 	return ( ( int )b1 << 24 ) + ( ( int )b2 << 16 ) + ( ( int ) b3 << 8 ) + b4;
1681 }
1682 
FloatSwap(float f)1683 float FloatSwap( float f ) {
1684 	union {
1685 		float	f;
1686 		byte	b[4];
1687 	} dat1, dat2;
1688 
1689 
1690 	dat1.f = f;
1691 	dat2.b[0] = dat1.b[3];
1692 	dat2.b[1] = dat1.b[2];
1693 	dat2.b[2] = dat1.b[1];
1694 	dat2.b[3] = dat1.b[0];
1695 	return dat2.f;
1696 }
1697 
1698 
1699 
1700 /*
1701 ============
1702 va
1703 
1704 does a varargs printf into a temp buffer, so I don't need to have
1705 varargs versions of all text functions.
1706 FIXME: make this buffer size safe someday
1707 ============
1708 */
va(const char * format,...)1709 char *va( const char *format, ... ) {
1710 	va_list		argptr;
1711 	static char		buffers[2][0x2800];
1712 	static int		index;
1713 
1714 	index ^= 1;
1715 
1716 	va_start( argptr, format );
1717 	Q_vsnprintf( buffers[index], sizeof( buffers[0] ), format, argptr );
1718 	va_end( argptr );
1719 
1720 	return buffers[index];
1721 }
1722 
1723 
1724 static char		com_token[MAX_TOKEN_CHARS];
1725 
1726 /*
1727 ==============
1728 COM_Parse
1729 
1730 Parse a token out of a string
1731 ==============
1732 */
COM_Parse(const char ** data_p)1733 char *COM_Parse( const char **data_p ) {
1734 	int		c;
1735 	int		len;
1736 	const char	*data;
1737 
1738 	data = *data_p;
1739 	len = 0;
1740 	com_token[0] = 0;
1741 
1742 	if( !data ) {
1743 		*data_p = NULL;
1744 		return com_token;
1745 	}
1746 
1747 // skip whitespace
1748 skipwhite:
1749 	while( ( c = *data ) <= ' ' ) {
1750 		if( c == 0 ) {
1751 			*data_p = NULL;
1752 			return com_token;
1753 		}
1754 		data++;
1755 	}
1756 
1757 // skip // comments
1758 	if( c == '/' && data[1] == '/' ) {
1759 		while( *data && *data != '\n' )
1760 			data++;
1761 		goto skipwhite;
1762 	}
1763 
1764 // skip /* */ comments
1765 	if( c == '/' && data[1] == '*' ) {
1766 		data += 2;
1767 		while( *data ) {
1768 			if( data[0] == '*' && data[1] == '/' ) {
1769 				data += 2;
1770 				break;
1771 			}
1772 			data++;
1773 		}
1774 		goto skipwhite;
1775 	}
1776 
1777 // handle quoted strings specially
1778 	if( c == '\"' ) {
1779 		data++;
1780 		while( 1 ) {
1781 			c = *data++;
1782 			if( c == '\"' || !c ) {
1783 				goto finish;
1784 			}
1785 
1786 			if( len < MAX_TOKEN_CHARS - 1 ) {
1787 				com_token[len] = c;
1788 				len++;
1789 			}
1790 		}
1791 	}
1792 
1793 // parse a regular word
1794 	do {
1795 		if( len < MAX_TOKEN_CHARS - 1 ) {
1796 			com_token[len] = c;
1797 			len++;
1798 		}
1799 		data++;
1800 		c = *data;
1801 	} while( c > 32 );
1802 
1803 finish:
1804 	com_token[len] = 0;
1805 
1806 	*data_p = data;
1807 	return com_token;
1808 }
1809 
1810 
1811 /*
1812 ===============
1813 Com_PageInMemory
1814 
1815 ===============
1816 */
1817 int	paged_total;
1818 
Com_PageInMemory(byte * buffer,int size)1819 void Com_PageInMemory (byte *buffer, int size)
1820 {
1821 	int		i;
1822 
1823 	for (i=size-1 ; i>0 ; i-=4096)
1824 		paged_total += buffer[i];
1825 }
1826 
1827 
1828 
1829 /*
1830 ============================================================================
1831 
1832 					LIBRARY REPLACEMENT FUNCTIONS
1833 
1834 ============================================================================
1835 */
1836 
1837 /* quake2 deals only with C locale and uses replacements
1838  * for libc locale-dependent string functions */
Q_tolower(int c)1839 int Q_tolower( int c ) {
1840 	if( Q_isupper( c ) ) {
1841 		c += ( 'a' - 'A' );
1842 	}
1843 
1844 	return c;
1845 }
1846 
Q_toupper(int c)1847 int Q_toupper( int c ) {
1848 	if( Q_islower( c ) ) {
1849 		c -= ( 'a' - 'A' );
1850 	}
1851 
1852 	return c;
1853 }
1854 
Q_strlwr(char * s)1855 char *Q_strlwr( char *s ) {
1856 	char *p = s;
1857 
1858 	while( *p ) {
1859 		*p = Q_tolower( *p );
1860 		p++;
1861 	}
1862 
1863 	return s;
1864 }
1865 
Q_strupr(char * s)1866 char *Q_strupr( char *s ) {
1867 	char *p = s;
1868 
1869 	while( *p ) {
1870 		*p = Q_toupper( *p );
1871 		p++;
1872 	}
1873 
1874 	return s;
1875 }
1876 
Q_strncasecmp(const char * s1,const char * s2,int n)1877 int Q_strncasecmp( const char *s1, const char *s2, int n ) {
1878 	int		c1, c2;
1879 
1880 	do {
1881 		c1 = *s1++;
1882 		c2 = *s2++;
1883 
1884 		if( !n-- )
1885 			return 0;		/* strings are equal until end point */
1886 
1887 		if( c1 != c2 ) {
1888 			if( c1 >= 'a' && c1 <= 'z' )
1889 				c1 -= ( 'a' - 'A' );
1890 			if( c2 >= 'a' && c2 <= 'z' )
1891 				c2 -= ( 'a' - 'A' );
1892 			if( c1 < c2 )
1893 				return -1;
1894 			if( c1 > c2 )
1895 				return 1;		/* strings not equal */
1896 		}
1897 	} while( c1 );
1898 
1899 	return 0;		/* strings are equal */
1900 }
1901 
Q_strcasecmp(const char * s1,const char * s2)1902 int Q_strcasecmp( const char *s1, const char *s2 ) {
1903 	int		c1, c2;
1904 
1905 	do {
1906 		c1 = *s1++;
1907 		c2 = *s2++;
1908 
1909 		if( c1 != c2 ) {
1910 			if( c1 >= 'a' && c1 <= 'z' )
1911 				c1 -= ( 'a' - 'A' );
1912 			if( c2 >= 'a' && c2 <= 'z' )
1913 				c2 -= ( 'a' - 'A' );
1914 			if( c1 < c2 )
1915 				return -1;
1916 			if( c1 > c2 )
1917 				return 1;		/* strings not equal */
1918 		}
1919 	} while( c1 );
1920 
1921 	return 0;		/* strings are equal */
1922 }
1923 
1924 /*
1925 ===============
1926 Q_strncpyz
1927 ===============
1928 */
Q_strncpyz(char * dest,const char * src,int destsize)1929 void Q_strncpyz( char *dest, const char *src, int destsize ) {
1930 #ifdef _DEBUG
1931 	if( destsize < 1 ) {
1932 		Com_Error( ERR_FATAL, "Q_strncpyz: destsize < 1" );
1933 	}
1934 	if( !dest ) {
1935 		Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
1936 	}
1937 	if( !src ) {
1938 		Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
1939 	}
1940 #endif
1941 
1942 	strncpy( dest, src, destsize - 1 );
1943 	dest[destsize - 1] = 0;
1944 }
1945 
1946 /*
1947 ===============
1948 Q_strcat
1949 ===============
1950 */
Q_strcat(char * dest,int destsize,const char * src)1951 void Q_strcat( char *dest, int destsize, const char *src ) {
1952 	int len;
1953 
1954 #ifdef _DEBUG
1955 	if( !dest ) {
1956 		Com_Error( ERR_FATAL, "Q_strcat: NULL dest" );
1957 	}
1958 #endif
1959 
1960 	len = strlen( dest );
1961 	if( len >= destsize ) {
1962 		Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
1963 	}
1964 
1965 	Q_strncpyz( dest + len, src, destsize - len );
1966 }
1967 
1968 /*
1969 ===============
1970 Q_vsnprintf
1971 
1972 safe multiplatfrom implementation of vsnprintf
1973 handles overflows correctly
1974 
1975 returns number of chars written, not including NULL-terminator
1976 ===============
1977 */
Q_vsnprintf(char * dest,int destsize,const char * fmt,va_list argptr)1978 int Q_vsnprintf( char *dest, int destsize, const char *fmt, va_list argptr ) {
1979 	int ret;
1980 
1981 #ifdef _WIN32
1982 	ret = _vsnprintf( dest, destsize - 1, fmt, argptr );
1983 	if( ret < 0 || ret > destsize - 1 ) {
1984 		/* truncated, non-terminated */
1985 		dest[destsize - 1] = 0;
1986 		Com_WPrintf( "Q_vsnprintf: overflow of %i in %i\n", ret, destsize );
1987 		ret = destsize - 1;
1988 	} else if( ret == destsize - 1 ) {
1989 		/* correct, non-terminated */
1990 		dest[destsize - 1] = 0;
1991 	}
1992 #else
1993 	/* !!!TODO: investigate libc vsnprintf semantics */
1994 	ret = vsnprintf( dest, destsize, fmt, argptr );
1995 #endif
1996 
1997 	return ret;
1998 }
1999 
2000 /*
2001 ===============
2002 Com_sprintf
2003 ===============
2004 */
Com_sprintf(char * dest,int destsize,const char * fmt,...)2005 int Com_sprintf( char *dest, int destsize, const char *fmt, ... ) {
2006 	va_list		argptr;
2007 	int			ret;
2008 
2009 	va_start( argptr, fmt );
2010 	ret = Q_vsnprintf( dest, destsize, fmt, argptr );
2011 	va_end( argptr );
2012 
2013 	return ret;
2014 }
2015 
2016 /*
2017 =====================================================================
2018 
2019   INFO STRINGS
2020 
2021 =====================================================================
2022 */
2023 
2024 /*
2025 ===============
2026 Info_ValueForKey
2027 
2028 Searches the string for the given
2029 key and returns the associated value, or an empty string.
2030 ===============
2031 */
Info_ValueForKey(const char * s,const char * key)2032 char *Info_ValueForKey( const char *s, const char *key ) {
2033 	char	pkey[MAX_INFO_STRING];
2034 	static	char value[4][MAX_INFO_STRING];	// use 4 buffers so compares
2035 								// work without stomping on each other
2036 	static	int	valueindex;
2037 	char	*o;
2038 
2039 	valueindex++;
2040 	if( *s == '\\' )
2041 		s++;
2042 	while( 1 ) {
2043 		o = pkey;
2044 		while( *s != '\\' ) {
2045 			if( !*s )
2046 				return "";
2047 			*o++ = *s++;
2048 		}
2049 		*o = 0;
2050 		s++;
2051 
2052 		o = value[valueindex & 3];
2053 		while( *s != '\\' && *s ) {
2054 			*o++ = *s++;
2055 		}
2056 		*o = 0;
2057 
2058 		if( !strcmp( key, pkey ) )
2059 			return value[valueindex & 3];
2060 
2061 		if( !*s )
2062 			return "";
2063 		s++;
2064 	}
2065 
2066 	return "";
2067 }
2068 
2069 /*
2070 ==================
2071 Info_RemoveKey
2072 ==================
2073 */
Info_RemoveKey(char * s,const char * key)2074 void Info_RemoveKey( char *s, const char *key ) {
2075 	char	*start;
2076 	char	pkey[MAX_INFO_STRING];
2077 	char	value[MAX_INFO_STRING];
2078 	char	*o;
2079 
2080 	if( strchr( key, '\\' ) ) {
2081 		return;
2082 	}
2083 
2084 	while( 1 ) {
2085 		start = s;
2086 		if( *s == '\\' )
2087 			s++;
2088 		o = pkey;
2089 		while( *s != '\\' ) {
2090 			if( !*s )
2091 				return;
2092 			*o++ = *s++;
2093 		}
2094 		*o = 0;
2095 		s++;
2096 
2097 		o = value;
2098 		while( *s != '\\' && *s ) {
2099 			if( !*s )
2100 				return;
2101 			*o++ = *s++;
2102 		}
2103 		*o = 0;
2104 
2105 		if( !strcmp( key, pkey ) ) {
2106 			strcpy( start, s );	// remove this part
2107 			return;
2108 		}
2109 
2110 		if( !*s )
2111 			return;
2112 	}
2113 
2114 }
2115 
2116 
2117 /*
2118 ==================
2119 Info_Validate
2120 
2121 Some characters are illegal in info strings because they
2122 can mess up the server's parsing.
2123 Also checks the length of keys/values and the whole string.
2124 ==================
2125 */
Info_Validate(const char * s)2126 qboolean Info_Validate( const char *s ) {
2127 	const char *start;
2128 	int		len;
2129 
2130 	start = s;
2131 	while( 1 ) {
2132 		//
2133 		// validate key
2134 		//
2135 		if( *s == '\\' ) {
2136 			s++;
2137 		}
2138 		if( !*s ) {
2139 			return qfalse;	// missing key
2140 		}
2141 		len = 0;
2142 		while( *s != '\\' ) {
2143 			if( *s == '\"' || *s == ';' ) {
2144 				return qfalse;	// illegal characters
2145 			}
2146 			if( len == MAX_INFO_KEY - 1 ) {
2147 				return qfalse;	// oversize key
2148 			}
2149 			s++; len++;
2150 			if( !*s ) {
2151 				return qfalse;	// missing value
2152 			}
2153 		}
2154 
2155 		//
2156 		// validate value
2157 		//
2158 		s++;
2159 		if( !*s ) {
2160 			return qfalse;	// missing value
2161 		}
2162 		len = 0;
2163 		while( *s != '\\' ) {
2164 			if( *s == '\"' || *s == ';' ) {
2165 				return qfalse;	// illegal characters
2166 			}
2167 			if( len == MAX_INFO_VALUE - 1 ) {
2168 				return qfalse;	// oversize value
2169 			}
2170 			s++; len++;
2171 			if( !*s ) {
2172 				if( s - start > MAX_INFO_STRING ) {
2173 					return qfalse;
2174 				}
2175 				return qtrue;	// end of string
2176 			}
2177 		}
2178 	}
2179 
2180 	return qfalse; // quiet compiler warning
2181 }
2182 
2183 /*
2184 ============
2185 Info_ValidateSubstring
2186 ============
2187 */
Info_ValidateSubstring(const char * s)2188 qboolean Info_ValidateSubstring( const char *s ) {
2189 	const char *start;
2190 
2191 	start = s;
2192 	while( *s ) {
2193 		if( *s == '\\' || *s == '\"' || *s == ';' ) {
2194 			return qfalse;
2195 		}
2196 		s++;
2197 	}
2198 	if( s - start > MAX_QPATH ) {
2199 		return qfalse;
2200 	}
2201 	return qtrue;
2202 }
2203 
2204 /*
2205 ==================
2206 Info_SetValueForKey
2207 ==================
2208 */
Info_SetValueForKey(char * s,const char * key,const char * value)2209 void Info_SetValueForKey( char *s, const char *key, const char *value ) {
2210 	char	newi[MAX_INFO_STRING], *v;
2211 	int		c;
2212 
2213 	if( strchr( key, '\\' ) || strchr( value, '\\' ) ) {
2214 		Com_Printf( "Can't use keys or values with a \\\n" );
2215 		return;
2216 	}
2217 
2218 	if( strchr( key, ';' ) ) {
2219 		Com_Printf( "Can't use keys or values with a semicolon\n" );
2220 		return;
2221 	}
2222 
2223 	if( strchr( key, '\"' ) || strchr( value, '\"' ) ) {
2224 		Com_Printf ("Can't use keys or values with a \"\n");
2225 		return;
2226 	}
2227 
2228 	if( strlen( key ) > MAX_INFO_KEY - 1 || strlen( value ) > MAX_INFO_VALUE - 1 ) {
2229 		Com_Printf( "Keys and values must be < %i characters.\n", MAX_INFO_KEY );
2230 		return;
2231 	}
2232 	Info_RemoveKey( s, key );
2233 	if( !value[0] ) {
2234 		return;
2235 	}
2236 
2237 	Com_sprintf( newi, sizeof( newi ), "\\%s\\%s", key, value );
2238 
2239 	if( strlen( newi ) + strlen( s ) > MAX_INFO_STRING - 1 ) {
2240 		Com_Printf( "Info string length exceeded\n" );
2241 		return;
2242 	}
2243 
2244 	// only copy ascii values
2245 	s += strlen( s );
2246 	v = newi;
2247 	while( *v ) {
2248 		c = *v++;
2249 		c &= 127;		// strip high bits
2250 		if( c >= 32 && c < 127 )
2251 			*s++ = c;
2252 	}
2253 	*s = 0;
2254 }
2255 
2256 /*
2257 ==================
2258 Info_AttemptSetValueForKey
2259 ==================
2260 */
Info_AttemptSetValueForKey(char * s,const char * key,const char * value)2261 qboolean Info_AttemptSetValueForKey( char *s, const char *key, const char *value ) {
2262 	char	newi[MAX_INFO_STRING], *v;
2263 	int		c;
2264 
2265 	if( !Info_ValidateSubstring( key ) ) {
2266 		return qfalse;
2267 	}
2268 	if( !Info_ValidateSubstring( value ) ) {
2269 		return qfalse;
2270 	}
2271 
2272 	Info_RemoveKey( s, key );
2273 	if( !value[0] ) {
2274 		return qtrue;
2275 	}
2276 
2277 	Com_sprintf( newi, sizeof( newi ), "\\%s\\%s", key, value );
2278 
2279 	if( strlen( newi ) + strlen( s ) > MAX_INFO_STRING - 1 ) {
2280 		return qfalse;
2281 	}
2282 
2283 	// only copy ascii values
2284 	s += strlen( s );
2285 	v = newi;
2286 	while( *v ) {
2287 		c = *v++;
2288 		c &= 127;		// strip high bits
2289 		if( c >= 32 && c < 127 )
2290 			*s++ = c;
2291 	}
2292 	*s = 0;
2293 
2294 	return qtrue;
2295 }
2296 
2297 /*
2298 ==================
2299 Info_NextPair
2300 ==================
2301 */
Info_NextPair(const char ** string,char * key,char * value)2302 void Info_NextPair( const char **string, char *key, char *value ) {
2303 	char	*o;
2304 	const char	*s;
2305 
2306 	*value = *key = 0;
2307 
2308 	s = *string;
2309 	if( !s ) {
2310 		return;
2311 	}
2312 
2313 	if( *s == '\\' )
2314 		s++;
2315 
2316 	if( !*s ) {
2317 		*string = NULL;
2318 		return;
2319 	}
2320 
2321 	o = key;
2322 	while( *s && *s != '\\' ) {
2323 		*o++ = *s++;
2324 	}
2325 
2326 	*o = 0;
2327 
2328 	if( !*s ) {
2329 		*string = NULL;
2330 		return;
2331 	}
2332 
2333 	o = value;
2334 	s++;
2335 	while( *s && *s != '\\' ) {
2336 		*o++ = *s++;
2337 	}
2338 	*o = 0;
2339 
2340 	if( *s ) {
2341 		s++;
2342 	}
2343 
2344 	*string = s;
2345 
2346 }
2347 
2348 /*
2349 ==================
2350 Info_Print
2351 ==================
2352 */
Info_Print(const char * infostring)2353 void Info_Print( const char *infostring ) {
2354 	char	key[MAX_INFO_STRING];
2355 	char	value[MAX_INFO_STRING];
2356 
2357 	while( infostring ) {
2358 		Info_NextPair( &infostring, key, value );
2359 
2360 		if( !key[0] ) {
2361 			break;
2362 		}
2363 
2364 		if( value[0] ) {
2365 			Com_Printf( "%-20s %s\n", key, value );
2366 		} else {
2367 			Com_Printf( "%-20s <MISSING VALUE>\n", key );
2368 		}
2369 	}
2370 }
2371 
2372 
2373 
2374 
2375