1 /*
2 Copyright (C) 1996-1997 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 // common.c -- misc functions used in client and server
21
22 #include "qwsvdef.h"
23
24 usercmd_t nullcmd; // guarenteed to be zero
25
26 static char *largv[MAX_NUM_ARGVS + 1];
27
28 //============================================================================
29
30
31
32 /*
33 ==============================================================================
34
35 MESSAGE IO FUNCTIONS
36
37 Handles byte ordering and avoids alignment errors
38 ==============================================================================
39 */
40
41 #ifdef FTE_PEXT_FLOATCOORDS
42
43 int msg_coordsize = 2; // 2 or 4.
44 int msg_anglesize = 1; // 1 or 2.
45
MSG_FromCoord(coorddata c,int bytes)46 float MSG_FromCoord(coorddata c, int bytes)
47 {
48 switch(bytes)
49 {
50 case 2: //encode 1/8th precision, giving -4096 to 4096 map sizes
51 return LittleShort(c.b2)/8.0f;
52 case 4:
53 return LittleFloat(c.f);
54 default:
55 Sys_Error("MSG_FromCoord: not a sane size");
56 return 0;
57 }
58 }
59
MSG_ToCoord(float f,int bytes)60 coorddata MSG_ToCoord(float f, int bytes) //return value should be treated as (char*)&ret;
61 {
62 coorddata r;
63 switch(bytes)
64 {
65 case 2:
66 r.b4 = 0;
67 if (f >= 0)
68 r.b2 = LittleShort((short)(f*8+0.5f));
69 else
70 r.b2 = LittleShort((short)(f*8-0.5f));
71 break;
72 case 4:
73 r.f = LittleFloat(f);
74 break;
75 default:
76 Sys_Error("MSG_ToCoord: not a sane size");
77 r.b4 = 0;
78 }
79
80 return r;
81 }
82
MSG_ToAngle(float f,int bytes)83 coorddata MSG_ToAngle(float f, int bytes) //return value is NOT byteswapped.
84 {
85 coorddata r;
86 switch(bytes)
87 {
88 case 1:
89 r.b4 = 0;
90 if (f >= 0)
91 r.b[0] = (int)(f*(256.0f/360.0f) + 0.5f) & 255;
92 else
93 r.b[0] = (int)(f*(256.0f/360.0f) - 0.5f) & 255;
94 break;
95 case 2:
96 r.b4 = 0;
97 if (f >= 0)
98 r.b2 = LittleShort((int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
99 else
100 r.b2 = LittleShort((int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
101 break;
102 // case 4:
103 // r.f = LittleFloat(f);
104 // break;
105 default:
106 Sys_Error("MSG_ToAngle: not a sane size");
107 r.b4 = 0;
108 }
109
110 return r;
111 }
112
113 #endif
114
115 // writing functions
116
MSG_WriteChar(sizebuf_t * sb,const int c)117 void MSG_WriteChar (sizebuf_t *sb, const int c)
118 {
119 byte *buf;
120
121 #ifdef PARANOID
122 if (c < -128 || c > 127)
123 Sys_Error ("MSG_WriteChar: range error");
124 #endif
125
126 buf = (byte *) SZ_GetSpace (sb, 1);
127 buf[0] = c;
128 }
129
MSG_WriteByte(sizebuf_t * sb,const int c)130 void MSG_WriteByte (sizebuf_t *sb, const int c)
131 {
132 byte *buf;
133
134 #ifdef PARANOID
135 if (c < 0 || c > 255)
136 Sys_Error ("MSG_WriteByte: range error");
137 #endif
138
139 buf = (byte *) SZ_GetSpace (sb, 1);
140 buf[0] = c;
141 }
142
MSG_WriteShort(sizebuf_t * sb,const int c)143 void MSG_WriteShort (sizebuf_t *sb, const int c)
144 {
145 byte *buf;
146
147 #ifdef PARANOID
148 if (c < ((short)0x8000) || c > (short)0x7fff)
149 Sys_Error ("MSG_WriteShort: range error");
150 #endif
151
152 buf = (byte *) SZ_GetSpace (sb, 2);
153 buf[0] = c&0xff;
154 buf[1] = c>>8;
155 }
156
MSG_WriteLong(sizebuf_t * sb,const int c)157 void MSG_WriteLong (sizebuf_t *sb, const int c)
158 {
159 byte *buf;
160
161 buf = (byte *) SZ_GetSpace (sb, 4);
162 buf[0] = c&0xff;
163 buf[1] = (c>>8)&0xff;
164 buf[2] = (c>>16)&0xff;
165 buf[3] = c>>24;
166 }
167
MSG_WriteFloat(sizebuf_t * sb,const float f)168 void MSG_WriteFloat (sizebuf_t *sb, const float f)
169 {
170 union
171 {
172 float f;
173 int l;
174 } dat;
175
176
177 dat.f = f;
178 dat.l = LittleLong (dat.l);
179
180 SZ_Write (sb, &dat.l, 4);
181 }
182
MSG_WriteString(sizebuf_t * sb,const char * s)183 void MSG_WriteString (sizebuf_t *sb, const char *s)
184 {
185 if (!s || !*s)
186 SZ_Write (sb, "", 1);
187 else
188 SZ_Write (sb, s, strlen(s)+1);
189 }
190
MSG_WriteCoord(sizebuf_t * sb,const float f)191 void MSG_WriteCoord (sizebuf_t *sb, const float f)
192 {
193 #ifdef FTE_PEXT_FLOATCOORDS
194 coorddata i = MSG_ToCoord(f, msg_coordsize);
195 SZ_Write (sb, (void*)&i, msg_coordsize);
196 #else
197 MSG_WriteShort (sb, (int)(f * 8));
198 #endif
199 }
200
MSG_WriteLongCoord(sizebuf_t * sb,float f)201 void MSG_WriteLongCoord(sizebuf_t* sb, float f)
202 {
203 f = LittleFloat(f);
204
205 SZ_Write (sb, (void*)&f, sizeof(f));
206 }
207
MSG_WriteAngle(sizebuf_t * sb,const float f)208 void MSG_WriteAngle (sizebuf_t *sb, const float f)
209 {
210 #ifdef FTE_PEXT_FLOATCOORDS
211 if (msg_anglesize == 2)
212 MSG_WriteAngle16(sb, f);
213 // else if (msg_anglesize==4)
214 // MSG_WriteFloat(sb, f);
215 else
216 #endif
217 MSG_WriteByte (sb, Q_rint(f * 256.0 / 360.0) & 255);
218 }
219
MSG_WriteAngle16(sizebuf_t * sb,const float f)220 void MSG_WriteAngle16 (sizebuf_t *sb, const float f)
221 {
222 MSG_WriteShort (sb, Q_rint(f*65536.0/360.0) & 65535);
223 }
224
MSG_WriteDeltaUsercmd(sizebuf_t * buf,const usercmd_t * from,const usercmd_t * cmd,unsigned int mvdsv_extensions)225 void MSG_WriteDeltaUsercmd (sizebuf_t *buf, const usercmd_t *from, const usercmd_t *cmd, unsigned int mvdsv_extensions)
226 {
227 int bits;
228
229 // send the movement message
230 bits = 0;
231 if (cmd->angles[0] != from->angles[0])
232 bits |= CM_ANGLE1;
233 if (cmd->angles[1] != from->angles[1])
234 bits |= CM_ANGLE2;
235 if (cmd->angles[2] != from->angles[2])
236 bits |= CM_ANGLE3;
237 if (cmd->forwardmove != from->forwardmove)
238 bits |= CM_FORWARD;
239 if (cmd->sidemove != from->sidemove)
240 bits |= CM_SIDE;
241 if (cmd->upmove != from->upmove)
242 bits |= CM_UP;
243 if (cmd->buttons != from->buttons)
244 bits |= CM_BUTTONS;
245 if (cmd->impulse != from->impulse)
246 bits |= CM_IMPULSE;
247
248 MSG_WriteByte (buf, bits);
249
250 if (bits & CM_ANGLE1)
251 MSG_WriteAngle16 (buf, cmd->angles[0]);
252 if (bits & CM_ANGLE2)
253 MSG_WriteAngle16 (buf, cmd->angles[1]);
254 if (bits & CM_ANGLE3)
255 MSG_WriteAngle16 (buf, cmd->angles[2]);
256
257 if (bits & CM_FORWARD)
258 MSG_WriteShort (buf, cmd->forwardmove);
259 if (bits & CM_SIDE)
260 MSG_WriteShort (buf, cmd->sidemove);
261 if (bits & CM_UP)
262 MSG_WriteShort (buf, cmd->upmove);
263
264 if (bits & CM_BUTTONS)
265 MSG_WriteByte (buf, cmd->buttons);
266 if (bits & CM_IMPULSE)
267 MSG_WriteByte (buf, cmd->impulse);
268
269 MSG_WriteByte (buf, cmd->msec);
270 }
271
272
273 // reading functions
274
275 int msg_readcount;
276 qbool msg_badread;
277
MSG_BeginReading(void)278 void MSG_BeginReading (void)
279 {
280 msg_readcount = 0;
281 msg_badread = false;
282 }
283
MSG_GetReadCount(void)284 int MSG_GetReadCount (void)
285 {
286 return msg_readcount;
287 }
288
289 // returns -1 and sets msg_badread if no more characters are available
MSG_ReadChar(void)290 int MSG_ReadChar (void)
291 {
292 int c;
293
294 if (msg_readcount + 1 > net_message.cursize)
295 {
296 msg_badread = true;
297 return -1;
298 }
299
300 c = (signed char) net_message.data[msg_readcount];
301 msg_readcount++;
302
303 return c;
304 }
305
MSG_ReadByte(void)306 int MSG_ReadByte (void)
307 {
308 int c;
309
310 if (msg_readcount + 1 > net_message.cursize)
311 {
312 msg_badread = true;
313 return -1;
314 }
315
316 c = (unsigned char) net_message.data[msg_readcount];
317 msg_readcount++;
318
319 return c;
320 }
321
MSG_ReadShort(void)322 int MSG_ReadShort (void)
323 {
324 int c;
325
326 if (msg_readcount + 2 > net_message.cursize)
327 {
328 msg_badread = true;
329 return -1;
330 }
331
332 c = (short) (net_message.data[msg_readcount]
333 + (net_message.data[msg_readcount+1]<<8));
334
335 msg_readcount += 2;
336
337 return c;
338 }
339
MSG_ReadLong(void)340 int MSG_ReadLong (void)
341 {
342 int c;
343
344 if (msg_readcount + 4 > net_message.cursize)
345 {
346 msg_badread = true;
347 return -1;
348 }
349
350 c = net_message.data[msg_readcount]
351 + (net_message.data[msg_readcount+1]<<8)
352 + (net_message.data[msg_readcount+2]<<16)
353 + (net_message.data[msg_readcount+3]<<24);
354
355 msg_readcount += 4;
356
357 return c;
358 }
359
MSG_ReadFloat(void)360 float MSG_ReadFloat (void)
361 {
362 union
363 {
364 byte b[4];
365 float f;
366 int l;
367 } dat;
368
369 dat.b[0] = net_message.data[msg_readcount];
370 dat.b[1] = net_message.data[msg_readcount+1];
371 dat.b[2] = net_message.data[msg_readcount+2];
372 dat.b[3] = net_message.data[msg_readcount+3];
373 msg_readcount += 4;
374
375 dat.l = LittleLong (dat.l);
376
377 return dat.f;
378 }
379
MSG_ReadString(void)380 char *MSG_ReadString (void)
381 {
382 static char string[2048];
383 int c;
384 size_t l = 0;
385
386 do
387 {
388 c = MSG_ReadByte ();
389
390 if (c == 255) // skip these to avoid security problems
391 continue; // with old clients and servers
392
393 if (c == -1 || c == 0)
394 break;
395
396 string[l] = c;
397 l++;
398 } while (l < sizeof (string) - 1);
399
400 string[l] = 0;
401
402 return string;
403 }
404
MSG_ReadStringLine(void)405 char *MSG_ReadStringLine (void)
406 {
407 static char string[2048];
408 int c;
409 size_t l = 0;
410
411 do
412 {
413 c = MSG_ReadByte ();
414
415 if (c == 255)
416 continue;
417
418 if (c == -1 || c == 0 || c == '\n')
419 break;
420
421 string[l] = c;
422 l++;
423 } while (l < sizeof (string) - 1);
424
425 string[l] = 0;
426
427 return string;
428 }
429
MSG_ReadCoord(void)430 float MSG_ReadCoord (void)
431 {
432 #ifdef FTE_PEXT_FLOATCOORDS
433
434 coorddata c = {0};
435 MSG_ReadData(&c, msg_coordsize);
436 return MSG_FromCoord(c, msg_coordsize);
437
438 #else // FTE_PEXT_FLOATCOORDS
439
440 return MSG_ReadShort() * (1.0 / 8);
441
442 #endif // FTE_PEXT_FLOATCOORDS
443 }
444
MSG_ReadAngle16(void)445 float MSG_ReadAngle16 (void)
446 {
447 return MSG_ReadShort () * (360.0 / 65536);
448 }
449
MSG_ReadAngle(void)450 float MSG_ReadAngle (void)
451 {
452 #ifdef FTE_PEXT_FLOATCOORDS
453
454 switch(msg_anglesize)
455 {
456 case 1:
457 return MSG_ReadChar() * (360.0/256);
458 case 2:
459 return MSG_ReadAngle16();
460 // case 4:
461 // return MSG_ReadFloat();
462 default:
463 Sys_Error("MSG_ReadAngle: Bad angle size\n");
464 return 0;
465 }
466
467 #else // FTE_PEXT_FLOATCOORDS
468
469 return MSG_ReadChar() * (360.0 / 256);
470
471 #endif // FTE_PEXT_FLOATCOORDS
472 }
473
MSG_ReadDeltaUsercmd(const usercmd_t * from,usercmd_t * move)474 void MSG_ReadDeltaUsercmd (const usercmd_t *from, usercmd_t *move)
475 {
476 int bits;
477
478 memcpy (move, from, sizeof(*move));
479
480 bits = MSG_ReadByte ();
481
482 // read current angles
483 if (bits & CM_ANGLE1)
484 move->angles[0] = MSG_ReadAngle16 ();
485 if (bits & CM_ANGLE2)
486 move->angles[1] = MSG_ReadAngle16 ();
487 if (bits & CM_ANGLE3)
488 move->angles[2] = MSG_ReadAngle16 ();
489
490 // read movement
491 if (bits & CM_FORWARD)
492 move->forwardmove = MSG_ReadShort ();
493 if (bits & CM_SIDE)
494 move->sidemove = MSG_ReadShort ();
495 if (bits & CM_UP)
496 move->upmove = MSG_ReadShort ();
497
498 // read buttons
499 if (bits & CM_BUTTONS)
500 move->buttons = MSG_ReadByte ();
501
502 if (bits & CM_IMPULSE)
503 move->impulse = MSG_ReadByte ();
504
505 // read time to run command
506 move->msec = MSG_ReadByte ();
507 }
508
MSG_ReadData(void * data,int len)509 void MSG_ReadData (void *data, int len)
510 {
511 int i;
512
513 for (i = 0 ; i < len ; i++)
514 ((byte *)data)[i] = MSG_ReadByte ();
515 }
516
MSG_ReadSkip(int bytes)517 void MSG_ReadSkip(int bytes)
518 {
519 for ( ; !msg_badread && bytes > 0; bytes--)
520 {
521 MSG_ReadByte ();
522 }
523 }
524
525 //===========================================================================
526
SZ_InitEx(sizebuf_t * buf,byte * data,const int length,qbool allowoverflow)527 void SZ_InitEx (sizebuf_t *buf, byte *data, const int length, qbool allowoverflow)
528 {
529 memset (buf, 0, sizeof (*buf));
530 buf->data = data;
531 buf->maxsize = length;
532 buf->allowoverflow = allowoverflow;
533 }
534
SZ_Init(sizebuf_t * buf,byte * data,const int length)535 void SZ_Init (sizebuf_t *buf, byte *data, const int length)
536 {
537 SZ_InitEx (buf, data, length, false);
538 }
539
SZ_Clear(sizebuf_t * buf)540 void SZ_Clear (sizebuf_t *buf)
541 {
542 buf->cursize = 0;
543 buf->overflowed = false;
544 }
545
SZ_GetSpace(sizebuf_t * buf,const int length)546 void *SZ_GetSpace (sizebuf_t *buf, const int length)
547 {
548 void *data;
549
550 if (buf->cursize + length > buf->maxsize)
551 {
552 if (!buf->allowoverflow)
553 Sys_Error ("SZ_GetSpace: overflow without allowoverflow set (%d/%d/%d)",
554 buf->cursize, length, buf->maxsize);
555
556 if (length > buf->maxsize)
557 Sys_Error ("SZ_GetSpace: %d/%d is > full buffer size",
558 length, buf->maxsize);
559
560 // because Con_Printf may be redirected
561 Sys_Printf ("SZ_GetSpace: overflow: cur = %d, len = %d, max = %d\n",
562 buf->cursize, length, buf->maxsize);
563 SZ_Clear (buf);
564 buf->overflowed = true;
565 }
566
567 data = buf->data + buf->cursize;
568 buf->cursize += length;
569
570 return data;
571 }
572
SZ_Write(sizebuf_t * buf,const void * data,int length)573 void SZ_Write (sizebuf_t *buf, const void *data, int length)
574 {
575 byte* dest = SZ_GetSpace(buf, length);
576
577 memcpy(dest, data, length);
578 }
579
SZ_Print(sizebuf_t * buf,const char * data)580 void SZ_Print (sizebuf_t *buf, const char *data)
581 {
582 int len = strlen(data) + 1;
583
584 // Remove trailing '\0'
585 if (buf->cursize && !buf->data[buf->cursize - 1]) {
586 --buf->cursize;
587 }
588
589 SZ_Write(buf, data, len);
590 }
591
592
593 //============================================================================
594
595 #define TOKENSIZE sizeof(com_token)
596 char com_token[TOKENSIZE];
597 int com_argc;
598 char **com_argv;
599
600 com_tokentype_t com_tokentype;
601
602 /*
603 ==============
604 COM_Parse
605
606 Parse a token out of a string
607 ==============
608 */
COM_Parse(const char * data)609 const char *COM_Parse (const char *data)
610 {
611 unsigned char c;
612 int len;
613
614 len = 0;
615 com_token[0] = 0;
616
617 if (!data)
618 return NULL;
619
620 // skip whitespace
621 while (true)
622 {
623 while ((c = *data) == ' ' || c == '\t' || c == '\r' || c == '\n')
624 data++;
625
626 if (c == 0)
627 return NULL; // end of file;
628
629 // skip // comments
630 if (c=='/' && data[1] == '/')
631 {
632 while (*data && *data != '\n')
633 data++;
634 }
635 else
636 break;
637 }
638
639 // handle quoted strings specially
640 if (c == '\"')
641 {
642 data++;
643 while (1)
644 {
645 c = *data++;
646 if (c == '\"' || !c)
647 {
648 com_token[len] = 0;
649
650 if (!c)
651 data--;
652
653 return data;
654 }
655
656 if (len < MAX_COM_TOKEN - 1)
657 {
658 com_token[len] = c;
659 len++;
660 }
661 }
662 }
663
664 // parse a regular word
665 do
666 {
667 if (len < MAX_COM_TOKEN-1)
668 {
669 com_token[len] = c;
670 len++;
671 }
672 data++;
673 c = *data;
674 }
675 while (c && c != ' ' && c != '\t' && c != '\n' && c != '\r');
676
677 com_token[len] = 0;
678 return data;
679 }
680
681 #define DEFAULT_PUNCTUATION "(,{})(\':;=!><&|+"
COM_ParseToken(const char * data,const char * punctuation)682 char *COM_ParseToken (const char *data, const char *punctuation)
683 {
684 int c;
685 int len;
686
687 if (!punctuation)
688 punctuation = DEFAULT_PUNCTUATION;
689
690 len = 0;
691 com_token[0] = 0;
692
693 if (!data)
694 {
695 com_tokentype = TTP_UNKNOWN;
696 return NULL;
697 }
698
699 // skip whitespace
700 skipwhite:
701 while ((c = *(unsigned char *) data) <= ' ')
702 {
703 if (c == 0)
704 {
705 com_tokentype = TTP_UNKNOWN;
706 return NULL; // end of file;
707 }
708
709 data++;
710 }
711
712 // skip // comments
713 if (c == '/')
714 {
715 if (data[1] == '/')
716 {
717 while (*data && *data != '\n')
718 data++;
719
720 goto skipwhite;
721 }
722 else if (data[1] == '*')
723 {
724 data += 2;
725
726 while (*data && (*data != '*' || data[1] != '/'))
727 data++;
728
729 data += 2;
730 goto skipwhite;
731 }
732 }
733
734
735 // handle quoted strings specially
736 if (c == '\"')
737 {
738 com_tokentype = TTP_STRING;
739 data++;
740 while (1)
741 {
742 if (len >= TOKENSIZE - 1)
743 {
744 com_token[len] = '\0';
745 return (char*) data;
746 }
747
748 c = *data++;
749
750 if (c=='\"' || !c)
751 {
752 com_token[len] = 0;
753 return (char*) data;
754 }
755
756 com_token[len] = c;
757 len++;
758 }
759 }
760
761 com_tokentype = TTP_UNKNOWN;
762
763 // parse single characters
764 if (strchr (punctuation, c))
765 {
766 com_token[len] = c;
767 len++;
768 com_token[len] = 0;
769 return (char*) (data + 1);
770 }
771
772 // parse a regular word
773 do
774 {
775 if (len >= TOKENSIZE - 1)
776 break;
777
778 com_token[len] = c;
779 data++;
780 len++;
781 c = *data;
782 if (strchr (punctuation, c))
783 break;
784
785 } while (c > 32);
786
787 com_token[len] = 0;
788 return (char*) data;
789 }
790
791 /*
792 ================
793 COM_InitArgv
794
795 ================
796 */
COM_InitArgv(int argc,char ** argv)797 void COM_InitArgv (int argc, char **argv)
798 {
799 for (com_argc = 0; (com_argc < MAX_NUM_ARGVS) && (com_argc < argc); com_argc++)
800 {
801 largv[com_argc] = (argv[com_argc]) ? argv[com_argc] : "";
802 }
803
804 largv[com_argc] = "";
805 com_argv = largv;
806 }
807
808 /*
809 ================
810 COM_CheckParm
811
812 Returns the position (1 to argc-1) in the program's argument list
813 where the given parameter appears, or 0 if not present
814 ================
815 */
COM_CheckParm(const char * parm)816 int COM_CheckParm (const char *parm)
817 {
818 int i;
819
820 for (i = 1; i < com_argc; i++)
821 {
822 if (!strcmp (parm,com_argv[i]))
823 return i;
824 }
825
826 return 0;
827 }
828
COM_Argc(void)829 int COM_Argc (void)
830 {
831 return com_argc;
832 }
833
COM_Argv(int arg)834 char *COM_Argv (int arg)
835 {
836 if (arg < 0 || arg >= com_argc)
837 return "";
838 return com_argv[arg];
839 }
840
841 /*
842 =====================================================================
843
844 INFO STRINGS
845
846 =====================================================================
847 */
848
849 /*
850 ===============
851 Info_ValueForKey
852
853 Searches the string for the given
854 key and returns the associated value, or an empty string.
855 ===============
856 */
Info_ValueForKey(char * s,const char * key)857 char *Info_ValueForKey (char *s, const char *key)
858 {
859 char pkey[512];
860 static char value[4][512]; // use two buffers so compares
861 // work without stomping on each other
862 static int valueindex;
863 char *o;
864
865 valueindex = (valueindex + 1) % 4;
866 if (*s == '\\')
867 s++;
868 while (1)
869 {
870 o = pkey;
871 while (*s != '\\')
872 {
873 if (!*s || o >= pkey + sizeof(pkey) - 1)
874 return "";
875 *o++ = *s++;
876 }
877 *o = 0;
878 s++;
879
880 o = value[valueindex];
881
882 while (*s != '\\' && *s)
883 {
884 if (!*s || o >= value[valueindex] + sizeof(value[valueindex]) - 1)
885 return "";
886 *o++ = *s++;
887 }
888 *o = 0;
889
890 if (!strncmp (key, pkey, sizeof(pkey)) )
891 return value[valueindex];
892
893 if (!*s)
894 return "";
895 s++;
896 }
897 }
898
899 /*
900
901 // WARNING: non standard behavior for Info_* function, this function may return NULL
902 while other functions always return at least ""
903
904 char *Info_KeyNameForKeyNum (char *s, int key)
905 {
906 static char pkey[4][512]; // use two buffers so compares
907 // work without stomping on each other
908 static int keyindex;
909 char *o;
910
911 keyindex = (keyindex + 1) % 4;
912 if (*s == '\\')
913 s++;
914
915 // ?
916 if (key < 1)
917 return NULL;
918
919 while (1)
920 {
921 key--;
922
923 // get key name
924 o = pkey[keyindex];
925 while (*s != '\\')
926 {
927 if (!*s || o >= pkey[keyindex] + sizeof(pkey[keyindex]) - 1)
928 return NULL;
929 *o++ = *s++;
930 }
931 *o = 0;
932 s++;
933
934 // skip key value
935 while (*s != '\\' && *s) s++;
936
937 if (!key)
938 return pkey[keyindex];
939
940 if (!*s)
941 return NULL;
942 s++;
943 }
944 }
945
946 */
947
948
Info_RemoveKey(char * s,const char * key)949 void Info_RemoveKey (char *s, const char *key)
950 {
951 char *start;
952 char pkey[512];
953 char value[512];
954 char *o;
955
956 if (strstr (key, "\\"))
957 {
958 Con_Printf ("Can't use a key with a \\\n");
959 return;
960 }
961
962 while (1)
963 {
964 start = s;
965 if (*s == '\\')
966 s++;
967 o = pkey;
968 while (*s != '\\')
969 {
970 if (!*s || o >= pkey + sizeof(pkey) - 1)
971 return;
972 *o++ = *s++;
973 }
974 *o = 0;
975 s++;
976
977 o = value;
978 while (*s != '\\' && *s)
979 {
980 if (!*s || o >= value + sizeof(value) - 1)
981 return;
982 *o++ = *s++;
983 }
984 *o = 0;
985
986 if (!strncmp (key, pkey, sizeof(pkey)) )
987 {
988 memmove (start, s, strlen(s) + 1); // remove this part
989 return;
990 }
991
992 if (!*s)
993 return;
994 }
995
996 }
997
Info_RemovePrefixedKeys(char * start,char prefix)998 void Info_RemovePrefixedKeys (char *start, char prefix)
999 {
1000 char *s;
1001 char pkey[512];
1002 char value[512];
1003 char *o;
1004
1005 s = start;
1006
1007 while (1)
1008 {
1009 if (*s == '\\')
1010 s++;
1011 o = pkey;
1012 while (*s != '\\')
1013 {
1014 if (!*s || o >= pkey + sizeof(pkey) - 1)
1015 return;
1016 *o++ = *s++;
1017 }
1018 *o = 0;
1019 s++;
1020
1021 o = value;
1022 while (*s != '\\' && *s)
1023 {
1024 if (!*s || o >= value + sizeof(value) - 1)
1025 return;
1026 *o++ = *s++;
1027 }
1028 *o = 0;
1029
1030 if (pkey[0] == prefix)
1031 {
1032 Info_RemoveKey (start, pkey);
1033 s = start;
1034 }
1035
1036 if (!*s)
1037 return;
1038 }
1039
1040 }
1041
1042
Info_SetValueForStarKey(char * s,const char * key,const char * value,unsigned int maxsize)1043 void Info_SetValueForStarKey (char *s, const char *key, const char *value, unsigned int maxsize)
1044 {
1045 char _new[1024], *v;
1046 int c;
1047 // extern cvar_t sv_highchars;
1048
1049 if (strstr (key, "\\") || strstr (value, "\\") )
1050 {
1051 Con_Printf ("Can't use keys or values with a \\\n");
1052 return;
1053 }
1054
1055 if (strstr (key, "\"") || strstr (value, "\"") )
1056 {
1057 Con_Printf ("Can't use keys or values with a \"\n");
1058 return;
1059 }
1060
1061 if (strlen(key) >= MAX_KEY_STRING || strlen(value) >= MAX_KEY_STRING)
1062 {
1063 Con_Printf ("Keys and values must be < %d characters.\n", MAX_KEY_STRING);
1064 return;
1065 }
1066
1067 // this next line is kinda trippy
1068 if (*(v = Info_ValueForKey(s, key)))
1069 {
1070 // key exists, make sure we have enough room for new value, if we don't,
1071 // don't change it!
1072 if (strlen(value) - strlen(v) + strlen(s) >= maxsize)
1073 {
1074 Con_Printf ("Info string length exceeded (change: key = '%s', old value = '%s', new value = '%s', strlen info = '%d', maxsize = '%d')\nFull info string: '%s'\n",
1075 key, v, value, strlen(s), maxsize, s);
1076 return;
1077 }
1078 }
1079 Info_RemoveKey (s, key);
1080 if (!value || !strlen(value))
1081 return;
1082
1083 snprintf (_new, sizeof(_new), "\\%s\\%s", key, value);
1084
1085 if (strlen(_new) + strlen(s) >= maxsize)
1086 {
1087 Con_Printf ("Info string length exceeded (add: key = '%s', value = '%s', strlen info = '%d', maxsize = '%d')\nFull info string: '%s'\n",
1088 key, value, strlen(s), maxsize, s);
1089 return;
1090 }
1091
1092 // only copy ascii values
1093 s += strlen(s);
1094 v = _new;
1095 while (*v)
1096 {
1097 c = (unsigned char)*v++;
1098 /*
1099 if (!(int)sv_highchars.value)
1100 {
1101 c &= 127;
1102 if (c < 32 || c > 127)
1103 continue;
1104 }
1105 */
1106 // c &= 127; // strip high bits
1107 if (c > 13) // && c < 127)
1108 *s++ = c;
1109 }
1110 *s = 0;
1111 }
1112
Info_SetValueForKey(char * s,const char * key,const char * value,unsigned int maxsize)1113 void Info_SetValueForKey (char *s, const char *key, const char *value, unsigned int maxsize)
1114 {
1115 if (key[0] == '*')
1116 {
1117 Con_Printf ("Can't set * keys\n");
1118 return;
1119 }
1120
1121 Info_SetValueForStarKey (s, key, value, maxsize);
1122 }
1123
Info_Print(char * s)1124 void Info_Print (char *s)
1125 {
1126 char key[512];
1127 char value[512];
1128 char *o;
1129 int l;
1130
1131 if (*s == '\\')
1132 s++;
1133 while (*s)
1134 {
1135 o = key;
1136 while (*s && *s != '\\')
1137 *o++ = *s++;
1138
1139 l = o - key;
1140 if (l < 20)
1141 {
1142 memset (o, ' ', 20-l);
1143 key[20] = 0;
1144 }
1145 else
1146 *o = 0;
1147 Con_Printf ("%s ", key);
1148
1149 if (!*s)
1150 {
1151 Con_Printf ("MISSING VALUE\n");
1152 return;
1153 }
1154
1155 o = value;
1156 s++;
1157 while (*s && *s != '\\')
1158 *o++ = *s++;
1159 *o = 0;
1160
1161 if (*s)
1162 s++;
1163 Con_Printf ("%s\n", value);
1164 }
1165 }
1166
Info_CopyStarKeys(const char * from,char * to,unsigned int maxsize)1167 void Info_CopyStarKeys (const char *from, char *to, unsigned int maxsize)
1168 {
1169 char key[512];
1170 char value[512];
1171 char *o;
1172
1173 if (*from == '\\')
1174 from++;
1175
1176 while (*from)
1177 {
1178 o = key;
1179 while (*from && *from != '\\')
1180 *o++ = *from++;
1181
1182 *o = 0;
1183
1184 o = value;
1185 from++;
1186 while (*from && *from != '\\')
1187 *o++ = *from++;
1188 *o = 0;
1189
1190 if (*from)
1191 from++;
1192 if (key[0] == '*')
1193 Info_SetValueForStarKey (to, key, value, maxsize);
1194 }
1195 }
1196
1197 //============================================================
1198 //
1199 // Alternative variant manipulation with info strings
1200 //
1201 //============================================================
1202
1203 // this is seems to be "better" than Com_HashKey()
Info_HashKey(const char * str)1204 static unsigned long Info_HashKey (const char *str)
1205 {
1206 unsigned long hash = 0;
1207 int c;
1208
1209 // the (c&~32) makes it case-insensitive
1210 // hash function known as sdbm, used in gawk
1211 while ((c = *str++))
1212 hash = (c &~ 32) + (hash << 6) + (hash << 16) - hash;
1213
1214 return hash;
1215 }
1216
1217 // used internally
_Info_Get(ctxinfo_t * ctx,const char * name)1218 static info_t *_Info_Get (ctxinfo_t *ctx, const char *name)
1219 {
1220 info_t *a;
1221 int key;
1222
1223 if (!ctx || !name || !name[0])
1224 return NULL;
1225
1226 key = Info_HashKey (name) % INFO_HASHPOOL_SIZE;
1227
1228 for (a = ctx->info_hash[key]; a; a = a->hash_next)
1229 if (!strcasecmp(name, a->name))
1230 return a;
1231
1232 return NULL;
1233 }
1234
Info_Get(ctxinfo_t * ctx,const char * name)1235 char *Info_Get(ctxinfo_t *ctx, const char *name)
1236 {
1237 static char value[4][512];
1238 static int valueindex = 0;
1239
1240 info_t *a = _Info_Get(ctx, name);
1241
1242 if ( a )
1243 {
1244 valueindex = (valueindex + 1) % 4;
1245
1246 strlcpy(value[valueindex], a->value, sizeof(value[0]));
1247
1248 return value[valueindex];
1249 }
1250 else
1251 {
1252 return "";
1253 }
1254 }
1255
Info_SetStar(ctxinfo_t * ctx,const char * name,const char * value)1256 qbool Info_SetStar (ctxinfo_t *ctx, const char *name, const char *value)
1257 {
1258 info_t *a;
1259 int key;
1260
1261 if (!value)
1262 value = "";
1263
1264 if (!ctx || !name || !name[0])
1265 return false;
1266
1267 // empty value, instead of set just remove it
1268 if (!value[0])
1269 {
1270 return Info_Remove(ctx, name);
1271 }
1272
1273 if (strchr(name, '\\') || strchr(value, '\\'))
1274 return false;
1275 if (strchr(name, 128 + '\\') || strchr(value, 128 + '\\'))
1276 return false;
1277 if (strchr(name, '"') || strchr(value, '"'))
1278 return false;
1279 if (strchr(name, '\r') || strchr(value, '\r')) // bad for print functions
1280 return false;
1281 if (strchr(name, '\n') || strchr(value, '\n')) // bad for print functions
1282 return false;
1283 if (strchr(name, '$') || strchr(value, '$')) // variable expansion may be exploited, escaping this
1284 return false;
1285 if (strchr(name, ';') || strchr(value, ';')) // interpreter may be haxed, escaping this
1286 return false;
1287
1288 if (strlen(name) >= MAX_KEY_STRING || strlen(value) >= MAX_KEY_STRING)
1289 return false; // too long name/value, its wrong
1290
1291 key = Info_HashKey(name) % INFO_HASHPOOL_SIZE;
1292
1293 // if already exists, reuse it
1294 for (a = ctx->info_hash[key]; a; a = a->hash_next)
1295 if (!strcasecmp(name, a->name))
1296 {
1297 Q_free (a->value);
1298 break;
1299 }
1300
1301 // not found, create new one
1302 if (!a)
1303 {
1304 if (ctx->cur >= ctx->max)
1305 return false; // too much infos
1306
1307 a = (info_t *) Q_malloc (sizeof(info_t));
1308 a->next = ctx->info_list;
1309 ctx->info_list = a;
1310 a->hash_next = ctx->info_hash[key];
1311 ctx->info_hash[key] = a;
1312
1313 ctx->cur++; // increase counter
1314
1315 // copy name
1316 a->name = Q_strdup (name);
1317 }
1318
1319 // copy value
1320 #if 0
1321 {
1322 // unfortunatelly evil users use non printable/control chars, so that does not work well
1323 a->value = Q_strdup (value);
1324 }
1325 #else
1326 {
1327 // skip some control chars, doh
1328 char v_buf[MAX_KEY_STRING] = {0}, *v = v_buf;
1329 int i;
1330
1331 for (i = 0; value[i]; i++) // len of 'value' should be less than MAX_KEY_STRING according to above checks
1332 {
1333 if ((unsigned char)value[i] > 13)
1334 *v++ = value[i];
1335 }
1336 *v = 0;
1337
1338 a->value = Q_strdup (v_buf);
1339 }
1340 #endif
1341
1342 // hrm, empty value, remove it then
1343 if (!a->value[0])
1344 {
1345 return Info_Remove(ctx, name);
1346 }
1347
1348 return true;
1349 }
1350
Info_Set(ctxinfo_t * ctx,const char * name,const char * value)1351 qbool Info_Set (ctxinfo_t *ctx, const char *name, const char *value)
1352 {
1353 if (!value)
1354 value = "";
1355
1356 if (!ctx || !name || !name[0])
1357 return false;
1358
1359 if (name[0] == '*')
1360 {
1361 Con_Printf ("Can't set * keys [%s]\n", name);
1362 return false;
1363 }
1364
1365 return Info_SetStar (ctx, name, value);
1366 }
1367
1368 // used internally
_Info_Free(info_t * a)1369 static void _Info_Free(info_t *a)
1370 {
1371 if (!a)
1372 return;
1373
1374 Q_free (a->name);
1375 Q_free (a->value);
1376 Q_free (a);
1377 }
1378
Info_Remove(ctxinfo_t * ctx,const char * name)1379 qbool Info_Remove (ctxinfo_t *ctx, const char *name)
1380 {
1381 info_t *a, *prev;
1382 int key;
1383
1384 if (!ctx || !name || !name[0])
1385 return false;
1386
1387 key = Info_HashKey (name) % INFO_HASHPOOL_SIZE;
1388
1389 prev = NULL;
1390 for (a = ctx->info_hash[key]; a; a = a->hash_next)
1391 {
1392 if (!strcasecmp(name, a->name))
1393 {
1394 // unlink from hash
1395 if (prev)
1396 prev->hash_next = a->hash_next;
1397 else
1398 ctx->info_hash[key] = a->hash_next;
1399 break;
1400 }
1401 prev = a;
1402 }
1403
1404 if (!a)
1405 return false; // not found
1406
1407 prev = NULL;
1408 for (a = ctx->info_list; a; a = a->next)
1409 {
1410 if (!strcasecmp(name, a->name))
1411 {
1412 // unlink from info list
1413 if (prev)
1414 prev->next = a->next;
1415 else
1416 ctx->info_list = a->next;
1417
1418 // free
1419 _Info_Free(a);
1420
1421 ctx->cur--; // decrease counter
1422
1423 return true;
1424 }
1425 prev = a;
1426 }
1427
1428 Sys_Error("Info_Remove: info list broken");
1429 return false; // shut up compiler
1430 }
1431
1432 // remove all infos
Info_RemoveAll(ctxinfo_t * ctx)1433 void Info_RemoveAll (ctxinfo_t *ctx)
1434 {
1435 info_t *a, *next;
1436
1437 if (!ctx)
1438 return;
1439
1440 for (a = ctx->info_list; a; a = next) {
1441 next = a->next;
1442
1443 // free
1444 _Info_Free(a);
1445 }
1446 ctx->info_list = NULL;
1447 ctx->cur = 0; // set counter to 0
1448
1449 // clear hash
1450 memset (ctx->info_hash, 0, sizeof(ctx->info_hash));
1451 }
1452
Info_Convert(ctxinfo_t * ctx,char * str)1453 qbool Info_Convert(ctxinfo_t *ctx, char *str)
1454 {
1455 char name[MAX_KEY_STRING], value[MAX_KEY_STRING], *start;
1456
1457 if (!ctx)
1458 return false;
1459
1460 for ( ; str && str[0]; )
1461 {
1462 if (!(str = strchr(str, '\\')))
1463 break;
1464
1465 start = str; // start of name
1466
1467 if (!(str = strchr(start + 1, '\\'))) // end of name
1468 break;
1469
1470 strlcpy(name, start + 1, min(str - start, (int)sizeof(name)));
1471
1472 start = str; // start of value
1473
1474 str = strchr(start + 1, '\\'); // end of value
1475
1476 strlcpy(value, start + 1, str ? min(str - start, (int)sizeof(value)) : (int)sizeof(value));
1477
1478 Info_SetStar(ctx, name, value);
1479 }
1480
1481 return true;
1482 }
1483
Info_ReverseConvert(ctxinfo_t * ctx,char * str,int size)1484 qbool Info_ReverseConvert(ctxinfo_t *ctx, char *str, int size)
1485 {
1486 info_t *a;
1487 int next_size;
1488
1489 if (!ctx)
1490 return false;
1491
1492 if (!str || size < 1)
1493 return false;
1494
1495 str[0] = 0;
1496
1497 for (a = ctx->info_list; a; a = a->next)
1498 {
1499 if (!a->value[0])
1500 continue; // empty
1501
1502 next_size = size - 2 - strlen(a->name) - strlen(a->value);
1503
1504 if (next_size < 1)
1505 {
1506 // sigh, next snprintf will not fit
1507 return false;
1508 }
1509
1510 snprintf(str, size, "\\%s\\%s", a->name, a->value);
1511 str += (size - next_size);
1512 size = next_size;
1513 }
1514
1515 return true;
1516 }
1517
Info_CopyStar(ctxinfo_t * ctx_from,ctxinfo_t * ctx_to)1518 qbool Info_CopyStar(ctxinfo_t *ctx_from, ctxinfo_t *ctx_to)
1519 {
1520 info_t *a;
1521
1522 if (!ctx_from || !ctx_to)
1523 return false;
1524
1525 if (ctx_from == ctx_to)
1526 return true; // hrm
1527
1528 for (a = ctx_from->info_list; a; a = a->next)
1529 {
1530 if (a->name[0] != '*')
1531 continue; // not a star key
1532
1533 // do we need check status of this function?
1534 Info_SetStar (ctx_to, a->name, a->value);
1535 }
1536
1537 return true;
1538 }
1539
Info_PrintList(ctxinfo_t * ctx)1540 void Info_PrintList(ctxinfo_t *ctx)
1541 {
1542 info_t *a;
1543 int cnt = 0;
1544
1545 if (!ctx)
1546 return;
1547
1548 for (a = ctx->info_list; a; a = a->next)
1549 {
1550 Con_Printf("%-20s %s\n", a->name, a->value);
1551 cnt++;
1552 }
1553
1554
1555 Con_DPrintf("%d infos\n", cnt);
1556 }
1557
1558 //============================================================================
1559
1560 static byte chktbl[1024] = {
1561 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
1562 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
1563 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
1564 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
1565 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
1566 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
1567 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
1568 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
1569 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
1570 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
1571 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
1572 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
1573 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
1574 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
1575 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
1576 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
1577 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
1578 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
1579 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
1580 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
1581 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
1582 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
1583 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
1584 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
1585 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
1586 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
1587 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
1588 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
1589 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
1590 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
1591 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
1592 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
1593 // Only the first 512 bytes of the table are initialized, the rest
1594 // is just zeros.
1595 // This is an idiocy in QW but we can't change this, or checksums
1596 // will not match.
1597 };
1598
1599 /*
1600 ====================
1601 COM_BlockSequenceCRCByte
1602
1603 For proxy protecting
1604 ====================
1605 */
COM_BlockSequenceCRCByte(byte * base,int length,int sequence)1606 byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence)
1607 {
1608 unsigned short crc;
1609 byte *p;
1610 byte chkb[60 + 4];
1611
1612 p = chktbl + ((unsigned int) sequence % (sizeof (chktbl) - 4));
1613
1614 if (length > 60)
1615 length = 60;
1616
1617 memcpy (chkb, base, length);
1618
1619 chkb[length] = (sequence & 0xff) ^ p[0];
1620 chkb[length+1] = p[1];
1621 chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
1622 chkb[length+3] = p[3];
1623
1624 length += 4;
1625
1626 crc = CRC_Block (chkb, length);
1627
1628 crc &= 0xff;
1629
1630 return crc;
1631 }
1632
1633 //============================================================================
1634
Q_glob_match_after_star(const char * pattern,const char * text)1635 static qbool Q_glob_match_after_star (const char *pattern, const char *text)
1636 {
1637 char c, c1;
1638 const char *p = pattern, *t = text;
1639
1640 while ((c = *p++) == '?' || c == '*')
1641 {
1642 if (c == '?' && *t++ == '\0')
1643 return false;
1644 }
1645
1646 if (c == '\0')
1647 return true;
1648
1649 for (c1 = ((c == '\\') ? *p : c); ; )
1650 {
1651 if (tolower(*t) == c1 && Q_glob_match (p - 1, t))
1652 return true;
1653
1654 if (*t++ == '\0')
1655 return false;
1656 }
1657 }
1658
1659 /*
1660 Match a pattern against a string.
1661 Based on Vic's Q_WildCmp, which is based on Linux glob_match.
1662 Works like glob_match, except that sets ([]) are not supported.
1663
1664 A match means the entire string TEXT is used up in matching.
1665
1666 In the pattern string, `*' matches any sequence of characters,
1667 `?' matches any character. Any other character in the pattern
1668 must be matched exactly.
1669
1670 To suppress the special syntactic significance of any of `*?\'
1671 and match the character exactly, precede it with a `\'.
1672 */
Q_glob_match(const char * pattern,const char * text)1673 qbool Q_glob_match (const char *pattern, const char *text)
1674 {
1675 char c;
1676
1677 while ((c = *pattern++) != '\0')
1678 {
1679 switch (c)
1680 {
1681 case '?':
1682 if (*text++ == '\0')
1683 return false;
1684 break;
1685 case '\\':
1686 if (tolower (*pattern++) != tolower (*text++))
1687 return false;
1688 break;
1689 case '*':
1690 return Q_glob_match_after_star (pattern, text);
1691 default:
1692 if (tolower (c) != tolower (*text++))
1693 return false;
1694 }
1695 }
1696
1697 return (*text == '\0');
1698 }
1699
1700 //============================================================================
1701
1702 /*
1703 ==========
1704 Com_HashKey
1705 ==========
1706 */
Com_HashKey(const char * name)1707 int Com_HashKey (const char *name)
1708 {
1709 int v;
1710 unsigned char c;
1711
1712 v = 0;
1713 while ( (c = *name++) != 0 )
1714 v += c &~ 32; // make it case insensitive
1715
1716 return v % 32;
1717 }
1718
1719 //============================================================================
1720
1721 static char q_normalize_chartbl[256];
1722 static qbool q_normalize_chartbl_init;
1723
Q_normalizetext_Init(void)1724 static void Q_normalizetext_Init (void)
1725 {
1726 int i;
1727
1728 for (i = 0; i < 32; i++)
1729 q_normalize_chartbl[i] = q_normalize_chartbl[i + 128] = '#';
1730 for (i = 32; i < 128; i++)
1731 q_normalize_chartbl[i] = q_normalize_chartbl[i + 128] = i;
1732
1733 // special cases
1734 q_normalize_chartbl[10] = 10;
1735 q_normalize_chartbl[13] = 13;
1736
1737 // dot
1738 q_normalize_chartbl[5 ] = q_normalize_chartbl[14 ] = q_normalize_chartbl[15 ] = q_normalize_chartbl[28 ] = q_normalize_chartbl[46 ] = '.';
1739 q_normalize_chartbl[5 + 128] = q_normalize_chartbl[14 + 128] = q_normalize_chartbl[15 + 128] = q_normalize_chartbl[28 + 128] = q_normalize_chartbl[46 + 128] = '.';
1740
1741 // numbers
1742 for (i = 18; i < 28; i++)
1743 q_normalize_chartbl[i] = q_normalize_chartbl[i + 128] = i + 30;
1744
1745 // brackets
1746 q_normalize_chartbl[16] = q_normalize_chartbl[16 + 128]= '[';
1747 q_normalize_chartbl[17] = q_normalize_chartbl[17 + 128] = ']';
1748 q_normalize_chartbl[29] = q_normalize_chartbl[29 + 128] = q_normalize_chartbl[128] = '(';
1749 q_normalize_chartbl[31] = q_normalize_chartbl[31 + 128] = q_normalize_chartbl[130] = ')';
1750
1751 // left arrow
1752 q_normalize_chartbl[127] = '>';
1753 // right arrow
1754 q_normalize_chartbl[141] = '<';
1755
1756 // '='
1757 q_normalize_chartbl[30] = q_normalize_chartbl[129] = q_normalize_chartbl[30 + 128] = '=';
1758
1759 q_normalize_chartbl_init = true;
1760 }
1761
1762 /*
1763 ==================
1764 Q_normalizetext
1765 returns readable extended quake names
1766 ==================
1767 */
Q_normalizetext(char * str)1768 char *Q_normalizetext (char *str)
1769 {
1770 unsigned char *i;
1771
1772 if (!q_normalize_chartbl_init)
1773 Q_normalizetext_Init();
1774
1775 for (i = (unsigned char*)str; *i; i++)
1776 *i = q_normalize_chartbl[*i];
1777 return str;
1778 }
1779
1780 /*
1781 ==================
1782 Q_redtext
1783 returns extended quake names
1784 ==================
1785 */
Q_redtext(unsigned char * str)1786 unsigned char *Q_redtext (unsigned char *str)
1787 {
1788 unsigned char *i;
1789 for (i = str; *i; i++)
1790 if (*i > 32 && *i < 128)
1791 *i |= 128;
1792 return str;
1793 }
1794 //<-
1795
1796 /*
1797 ==================
1798 Q_yelltext
1799 returns extended quake names (yellow numbers)
1800 ==================
1801 */
Q_yelltext(unsigned char * str)1802 unsigned char *Q_yelltext (unsigned char *str)
1803 {
1804 unsigned char *i;
1805 for (i = str; *i; i++)
1806 {
1807 if (*i >= '0' && *i <= '9')
1808 *i += 18 - '0';
1809 else if (*i > 32 && *i < 128)
1810 *i |= 128;
1811 else if (*i == 13)
1812 *i = ' ';
1813 }
1814 return str;
1815 }
1816
1817 //=====================================================================
1818
1819 // "GPL map" support. If we encounter a map with a known "GPL" CRC,
1820 // we fake the CRC so that, on the client side, the CRC of the original
1821 // map is transferred to the server, and on the server side, comparison
1822 // of clients' CRC is done against the orignal one
1823 typedef struct {
1824 const char *mapname;
1825 int original;
1826 int gpl;
1827 } csentry_t;
1828
1829 static csentry_t table[] = {
1830 // CRCs for AquaShark's "simpletextures" maps
1831 { "dm1", 0xc5c7dab3, 0x7d37618e },
1832 { "dm2", 0x65f63634, 0x7b337440 },
1833 { "dm3", 0x15e20df8, 0x912781ae },
1834 { "dm4", 0x9c6fe4bf, 0xc374df89 },
1835 { "dm5", 0xb02d48fd, 0x77ca7ce5 },
1836 { "dm6", 0x5208da2b, 0x200c8b5d },
1837 { "end", 0xbbd4b4a5, 0xf89b12ae }, // this is the version with the extra room
1838 { NULL, 0, 0 },
1839 };
1840
Com_TranslateMapChecksum(const char * mapname,int checksum)1841 int Com_TranslateMapChecksum (const char *mapname, int checksum)
1842 {
1843 csentry_t *p;
1844
1845 // Con_Printf ("Map checksum (%s): 0x%x\n", mapname, checksum);
1846
1847 for (p = table; p->mapname; p++)
1848 if (!strcmp(p->mapname, mapname)) {
1849 if (checksum == p->gpl)
1850 return p->original;
1851 else
1852 return checksum;
1853 }
1854
1855 return checksum;
1856 }
1857
COM_FileExists(char * path)1858 qbool COM_FileExists (char *path)
1859 {
1860 FILE *fexists = NULL;
1861
1862 // Try opening the file to see if it exists.
1863 fexists = fopen(path, "rb");
1864
1865 // The file exists.
1866 if (fexists)
1867 {
1868 // Make sure the file is closed.
1869 fclose (fexists);
1870 return true;
1871 }
1872
1873 return false;
1874 }
1875
Q_namecmp(const char * s1,const char * s2)1876 int Q_namecmp(const char* s1, const char* s2)
1877 {
1878 if (s1 == NULL && s2 == NULL)
1879 return 0;
1880
1881 if (s1 == NULL)
1882 return -1;
1883
1884 if (s2 == NULL)
1885 return 1;
1886
1887 while (*s1 || *s2) {
1888 if (tolower(*s1 & 0x7f) != tolower(*s2 & 0x7f)) {
1889 return tolower(*s1 & 0x7f) - tolower(*s2 & 0x7f);
1890 }
1891 s1++;
1892 s2++;
1893 }
1894
1895 return 0;
1896 }
1897