common.c revision 9fd67c44777b350dc56f3e70c88963b0d966ffc7
1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, 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 <ctype.h> 23 24#ifdef SERVERONLY 25#include "qwsvdef.h" 26#else 27#include "quakedef.h" 28#endif 29 30#define MAX_NUM_ARGVS 50 31#define NUM_SAFE_ARGVS 6 32 33usercmd_t nullcmd; // guarenteed to be zero 34 35static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1]; 36static char *argvdummy = " "; 37 38static char *safeargvs[NUM_SAFE_ARGVS] = 39 {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse"}; 40 41cvar_t registered = {"registered","0"}; 42 43qboolean com_modified; // set true if using non-id files 44 45int static_registered = 1; // only for startup check, then set 46 47qboolean msg_suppress_1 = 0; 48 49void COM_InitFilesystem (void); 50void COM_Path_f (void); 51 52 53// if a packfile directory differs from this, it is assumed to be hacked 54#define PAK0_COUNT 339 55#define PAK0_CRC 52883 56 57qboolean standard_quake = true, rogue, hipnotic; 58 59char gamedirfile[MAX_OSPATH]; 60 61// this graphic needs to be in the pak file to use registered features 62unsigned short pop[] = 63{ 64 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 65,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000 66,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000 67,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600 68,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563 69,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564 70,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564 71,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563 72,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500 73,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200 74,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000 75,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000 76,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000 77,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000 78,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000 79,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000 80}; 81 82/* 83 84 85All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources. 86 87The "base directory" is the path to the directory holding the quake.exe and all game directories. The sys_* files pass this to host_init in quakeparms_t->basedir. This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory. The base directory is 88only used during filesystem initialization. 89 90The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to. This can be overridden with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't. 91 92The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines. If there is a cache directory 93specified, when a file is found by the normal search path, it will be mirrored 94into the cache directory, then opened there. 95 96*/ 97 98//============================================================================ 99 100 101// ClearLink is used for new headnodes 102void ClearLink (link_t *l) 103{ 104 l->prev = l->next = l; 105} 106 107void RemoveLink (link_t *l) 108{ 109 l->next->prev = l->prev; 110 l->prev->next = l->next; 111} 112 113void InsertLinkBefore (link_t *l, link_t *before) 114{ 115 l->next = before; 116 l->prev = before->prev; 117 l->prev->next = l; 118 l->next->prev = l; 119} 120void InsertLinkAfter (link_t *l, link_t *after) 121{ 122 l->next = after->next; 123 l->prev = after; 124 l->prev->next = l; 125 l->next->prev = l; 126} 127 128/* 129============================================================================ 130 131 LIBRARY REPLACEMENT FUNCTIONS 132 133============================================================================ 134*/ 135 136#if 0 137void Q_memset (void *dest, int fill, int count) 138{ 139 int i; 140 141 if ( (((long)dest | count) & 3) == 0) 142 { 143 count >>= 2; 144 fill = fill | (fill<<8) | (fill<<16) | (fill<<24); 145 for (i=0 ; i<count ; i++) 146 ((int *)dest)[i] = fill; 147 } 148 else 149 for (i=0 ; i<count ; i++) 150 ((byte *)dest)[i] = fill; 151} 152 153void Q_memcpy (void *dest, void *src, int count) 154{ 155 int i; 156 157 if (( ( (long)dest | (long)src | count) & 3) == 0 ) 158 { 159 count>>=2; 160 for (i=0 ; i<count ; i++) 161 ((int *)dest)[i] = ((int *)src)[i]; 162 } 163 else 164 for (i=0 ; i<count ; i++) 165 ((byte *)dest)[i] = ((byte *)src)[i]; 166} 167 168int Q_memcmp (void *m1, void *m2, int count) 169{ 170 while(count) 171 { 172 count--; 173 if (((byte *)m1)[count] != ((byte *)m2)[count]) 174 return -1; 175 } 176 return 0; 177} 178 179void Q_strcpy (char *dest, char *src) 180{ 181 while (*src) 182 { 183 *dest++ = *src++; 184 } 185 *dest++ = 0; 186} 187 188void Q_strncpy (char *dest, char *src, int count) 189{ 190 while (*src && count--) 191 { 192 *dest++ = *src++; 193 } 194 if (count) 195 *dest++ = 0; 196} 197 198int Q_strlen (char *str) 199{ 200 int count; 201 202 count = 0; 203 while (str[count]) 204 count++; 205 206 return count; 207} 208 209char *Q_strrchr(char *s, char c) 210{ 211 int len = Q_strlen(s); 212 s += len; 213 while (len--) 214 if (*--s == c) return s; 215 return 0; 216} 217 218void Q_strcat (char *dest, char *src) 219{ 220 dest += Q_strlen(dest); 221 Q_strcpy (dest, src); 222} 223 224int Q_strcmp (char *s1, char *s2) 225{ 226 while (1) 227 { 228 if (*s1 != *s2) 229 return -1; // strings not equal 230 if (!*s1) 231 return 0; // strings are equal 232 s1++; 233 s2++; 234 } 235 236 return -1; 237} 238 239int Q_strncmp (char *s1, char *s2, int count) 240{ 241 while (1) 242 { 243 if (!count--) 244 return 0; 245 if (*s1 != *s2) 246 return -1; // strings not equal 247 if (!*s1) 248 return 0; // strings are equal 249 s1++; 250 s2++; 251 } 252 253 return -1; 254} 255 256int Q_strncasecmp (char *s1, char *s2, int n) 257{ 258 int c1, c2; 259 260 while (1) 261 { 262 c1 = *s1++; 263 c2 = *s2++; 264 265 if (!n--) 266 return 0; // strings are equal until end point 267 268 if (c1 != c2) 269 { 270 if (c1 >= 'a' && c1 <= 'z') 271 c1 -= ('a' - 'A'); 272 if (c2 >= 'a' && c2 <= 'z') 273 c2 -= ('a' - 'A'); 274 if (c1 != c2) 275 return -1; // strings not equal 276 } 277 if (!c1) 278 return 0; // strings are equal 279// s1++; 280// s2++; 281 } 282 283 return -1; 284} 285 286int Q_strcasecmp (char *s1, char *s2) 287{ 288 return Q_strncasecmp (s1, s2, 99999); 289} 290 291#endif 292 293int Q_atoi (char *str) 294{ 295 int val; 296 int sign; 297 int c; 298 299 if (*str == '-') 300 { 301 sign = -1; 302 str++; 303 } 304 else 305 sign = 1; 306 307 val = 0; 308 309// 310// check for hex 311// 312 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) 313 { 314 str += 2; 315 while (1) 316 { 317 c = *str++; 318 if (c >= '0' && c <= '9') 319 val = (val<<4) + c - '0'; 320 else if (c >= 'a' && c <= 'f') 321 val = (val<<4) + c - 'a' + 10; 322 else if (c >= 'A' && c <= 'F') 323 val = (val<<4) + c - 'A' + 10; 324 else 325 return val*sign; 326 } 327 } 328 329// 330// check for character 331// 332 if (str[0] == '\'') 333 { 334 return sign * str[1]; 335 } 336 337// 338// assume decimal 339// 340 while (1) 341 { 342 c = *str++; 343 if (c <'0' || c > '9') 344 return val*sign; 345 val = val*10 + c - '0'; 346 } 347 348 return 0; 349} 350 351 352float Q_atof (char *str) 353{ 354 double val; 355 int sign; 356 int c; 357 int decimal, total; 358 359 if (*str == '-') 360 { 361 sign = -1; 362 str++; 363 } 364 else 365 sign = 1; 366 367 val = 0; 368 369// 370// check for hex 371// 372 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) 373 { 374 str += 2; 375 while (1) 376 { 377 c = *str++; 378 if (c >= '0' && c <= '9') 379 val = (val*16) + c - '0'; 380 else if (c >= 'a' && c <= 'f') 381 val = (val*16) + c - 'a' + 10; 382 else if (c >= 'A' && c <= 'F') 383 val = (val*16) + c - 'A' + 10; 384 else 385 return val*sign; 386 } 387 } 388 389// 390// check for character 391// 392 if (str[0] == '\'') 393 { 394 return sign * str[1]; 395 } 396 397// 398// assume decimal 399// 400 decimal = -1; 401 total = 0; 402 while (1) 403 { 404 c = *str++; 405 if (c == '.') 406 { 407 decimal = total; 408 continue; 409 } 410 if (c <'0' || c > '9') 411 break; 412 val = val*10 + c - '0'; 413 total++; 414 } 415 416 if (decimal == -1) 417 return val*sign; 418 while (total > decimal) 419 { 420 val /= 10; 421 total--; 422 } 423 424 return val*sign; 425} 426 427/* 428============================================================================ 429 430 BYTE ORDER FUNCTIONS 431 432============================================================================ 433*/ 434 435qboolean bigendien; 436 437short (*BigShort) (short l); 438short (*LittleShort) (short l); 439int (*BigLong) (int l); 440int (*LittleLong) (int l); 441float (*BigFloat) (float l); 442float (*LittleFloat) (float l); 443 444short ShortSwap (short l) 445{ 446 byte b1,b2; 447 448 b1 = l&255; 449 b2 = (l>>8)&255; 450 451 return (b1<<8) + b2; 452} 453 454short ShortNoSwap (short l) 455{ 456 return l; 457} 458 459int LongSwap (int l) 460{ 461 byte b1,b2,b3,b4; 462 463 b1 = l&255; 464 b2 = (l>>8)&255; 465 b3 = (l>>16)&255; 466 b4 = (l>>24)&255; 467 468 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; 469} 470 471int LongNoSwap (int l) 472{ 473 return l; 474} 475 476float FloatSwap (float f) 477{ 478 union 479 { 480 float f; 481 byte b[4]; 482 } dat1, dat2; 483 484 485 dat1.f = f; 486 dat2.b[0] = dat1.b[3]; 487 dat2.b[1] = dat1.b[2]; 488 dat2.b[2] = dat1.b[1]; 489 dat2.b[3] = dat1.b[0]; 490 return dat2.f; 491} 492 493float FloatNoSwap (float f) 494{ 495 return f; 496} 497 498/* 499============================================================================== 500 501 MESSAGE IO FUNCTIONS 502 503Handles byte ordering and avoids alignment errors 504============================================================================== 505*/ 506 507// 508// writing functions 509// 510 511void MSG_WriteChar (sizebuf_t *sb, int c) 512{ 513 byte *buf; 514 515#ifdef PARANOID 516 if (c < -128 || c > 127) 517 Sys_Error ("MSG_WriteChar: range error"); 518#endif 519 520 buf = SZ_GetSpace (sb, 1); 521 buf[0] = c; 522} 523 524void MSG_WriteByte (sizebuf_t *sb, int c) 525{ 526 byte *buf; 527 528#ifdef PARANOID 529 if (c < 0 || c > 255) 530 Sys_Error ("MSG_WriteByte: range error"); 531#endif 532 533 buf = SZ_GetSpace (sb, 1); 534 buf[0] = c; 535} 536 537void MSG_WriteShort (sizebuf_t *sb, int c) 538{ 539 byte *buf; 540 541#ifdef PARANOID 542 if (c < ((short)0x8000) || c > (short)0x7fff) 543 Sys_Error ("MSG_WriteShort: range error"); 544#endif 545 546 buf = SZ_GetSpace (sb, 2); 547 buf[0] = c&0xff; 548 buf[1] = c>>8; 549} 550 551void MSG_WriteLong (sizebuf_t *sb, int c) 552{ 553 byte *buf; 554 555 buf = SZ_GetSpace (sb, 4); 556 buf[0] = c&0xff; 557 buf[1] = (c>>8)&0xff; 558 buf[2] = (c>>16)&0xff; 559 buf[3] = c>>24; 560} 561 562void MSG_WriteFloat (sizebuf_t *sb, float f) 563{ 564 union 565 { 566 float f; 567 int l; 568 } dat; 569 570 571 dat.f = f; 572 dat.l = LittleLong (dat.l); 573 574 SZ_Write (sb, &dat.l, 4); 575} 576 577void MSG_WriteString (sizebuf_t *sb, char *s) 578{ 579 if (!s) 580 SZ_Write (sb, "", 1); 581 else 582 SZ_Write (sb, s, Q_strlen(s)+1); 583} 584 585void MSG_WriteCoord (sizebuf_t *sb, float f) 586{ 587 MSG_WriteShort (sb, (int)(f*8)); 588} 589 590void MSG_WriteAngle (sizebuf_t *sb, float f) 591{ 592 MSG_WriteByte (sb, (int)(f*256/360) & 255); 593} 594 595void MSG_WriteAngle16 (sizebuf_t *sb, float f) 596{ 597 MSG_WriteShort (sb, (int)(f*65536/360) & 65535); 598} 599 600void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd) 601{ 602 int bits; 603 604// 605// send the movement message 606// 607 bits = 0; 608 if (cmd->angles[0] != from->angles[0]) 609 bits |= CM_ANGLE1; 610 if (cmd->angles[1] != from->angles[1]) 611 bits |= CM_ANGLE2; 612 if (cmd->angles[2] != from->angles[2]) 613 bits |= CM_ANGLE3; 614 if (cmd->forwardmove != from->forwardmove) 615 bits |= CM_FORWARD; 616 if (cmd->sidemove != from->sidemove) 617 bits |= CM_SIDE; 618 if (cmd->upmove != from->upmove) 619 bits |= CM_UP; 620 if (cmd->buttons != from->buttons) 621 bits |= CM_BUTTONS; 622 if (cmd->impulse != from->impulse) 623 bits |= CM_IMPULSE; 624 625 MSG_WriteByte (buf, bits); 626 627 if (bits & CM_ANGLE1) 628 MSG_WriteAngle16 (buf, cmd->angles[0]); 629 if (bits & CM_ANGLE2) 630 MSG_WriteAngle16 (buf, cmd->angles[1]); 631 if (bits & CM_ANGLE3) 632 MSG_WriteAngle16 (buf, cmd->angles[2]); 633 634 if (bits & CM_FORWARD) 635 MSG_WriteShort (buf, cmd->forwardmove); 636 if (bits & CM_SIDE) 637 MSG_WriteShort (buf, cmd->sidemove); 638 if (bits & CM_UP) 639 MSG_WriteShort (buf, cmd->upmove); 640 641 if (bits & CM_BUTTONS) 642 MSG_WriteByte (buf, cmd->buttons); 643 if (bits & CM_IMPULSE) 644 MSG_WriteByte (buf, cmd->impulse); 645 MSG_WriteByte (buf, cmd->msec); 646} 647 648 649// 650// reading functions 651// 652int msg_readcount; 653qboolean msg_badread; 654 655void MSG_BeginReading (void) 656{ 657 msg_readcount = 0; 658 msg_badread = false; 659} 660 661int MSG_GetReadCount(void) 662{ 663 return msg_readcount; 664} 665 666// returns -1 and sets msg_badread if no more characters are available 667int MSG_ReadChar (void) 668{ 669 int c; 670 671 if (msg_readcount+1 > net_message.cursize) 672 { 673 msg_badread = true; 674 return -1; 675 } 676 677 c = (signed char)net_message.data[msg_readcount]; 678 msg_readcount++; 679 680 return c; 681} 682 683int MSG_ReadByte (void) 684{ 685 int c; 686 687 if (msg_readcount+1 > net_message.cursize) 688 { 689 msg_badread = true; 690 return -1; 691 } 692 693 c = (unsigned char)net_message.data[msg_readcount]; 694 msg_readcount++; 695 696 return c; 697} 698 699int MSG_ReadShort (void) 700{ 701 int c; 702 703 if (msg_readcount+2 > net_message.cursize) 704 { 705 msg_badread = true; 706 return -1; 707 } 708 709 c = (short)(net_message.data[msg_readcount] 710 + (net_message.data[msg_readcount+1]<<8)); 711 712 msg_readcount += 2; 713 714 return c; 715} 716 717int MSG_ReadLong (void) 718{ 719 int c; 720 721 if (msg_readcount+4 > net_message.cursize) 722 { 723 msg_badread = true; 724 return -1; 725 } 726 727 c = net_message.data[msg_readcount] 728 + (net_message.data[msg_readcount+1]<<8) 729 + (net_message.data[msg_readcount+2]<<16) 730 + (net_message.data[msg_readcount+3]<<24); 731 732 msg_readcount += 4; 733 734 return c; 735} 736 737float MSG_ReadFloat (void) 738{ 739 union 740 { 741 byte b[4]; 742 float f; 743 int l; 744 } dat; 745 746 dat.b[0] = net_message.data[msg_readcount]; 747 dat.b[1] = net_message.data[msg_readcount+1]; 748 dat.b[2] = net_message.data[msg_readcount+2]; 749 dat.b[3] = net_message.data[msg_readcount+3]; 750 msg_readcount += 4; 751 752 dat.l = LittleLong (dat.l); 753 754 return dat.f; 755} 756 757char *MSG_ReadString (void) 758{ 759 static char string[2048]; 760 int l,c; 761 762 l = 0; 763 do 764 { 765 c = MSG_ReadChar (); 766 if (c == -1 || c == 0) 767 break; 768 string[l] = c; 769 l++; 770 } while (l < sizeof(string)-1); 771 772 string[l] = 0; 773 774 return string; 775} 776 777char *MSG_ReadStringLine (void) 778{ 779 static char string[2048]; 780 int l,c; 781 782 l = 0; 783 do 784 { 785 c = MSG_ReadChar (); 786 if (c == -1 || c == 0 || c == '\n') 787 break; 788 string[l] = c; 789 l++; 790 } while (l < sizeof(string)-1); 791 792 string[l] = 0; 793 794 return string; 795} 796 797float MSG_ReadCoord (void) 798{ 799 return MSG_ReadShort() * (1.0/8); 800} 801 802float MSG_ReadAngle (void) 803{ 804 return MSG_ReadChar() * (360.0/256); 805} 806 807float MSG_ReadAngle16 (void) 808{ 809 return MSG_ReadShort() * (360.0/65536); 810} 811 812void MSG_ReadDeltaUsercmd (usercmd_t *from, usercmd_t *move) 813{ 814 int bits; 815 816 memcpy (move, from, sizeof(*move)); 817 818 bits = MSG_ReadByte (); 819 820// read current angles 821 if (bits & CM_ANGLE1) 822 move->angles[0] = MSG_ReadAngle16 (); 823 if (bits & CM_ANGLE2) 824 move->angles[1] = MSG_ReadAngle16 (); 825 if (bits & CM_ANGLE3) 826 move->angles[2] = MSG_ReadAngle16 (); 827 828// read movement 829 if (bits & CM_FORWARD) 830 move->forwardmove = MSG_ReadShort (); 831 if (bits & CM_SIDE) 832 move->sidemove = MSG_ReadShort (); 833 if (bits & CM_UP) 834 move->upmove = MSG_ReadShort (); 835 836// read buttons 837 if (bits & CM_BUTTONS) 838 move->buttons = MSG_ReadByte (); 839 840 if (bits & CM_IMPULSE) 841 move->impulse = MSG_ReadByte (); 842 843// read time to run command 844 move->msec = MSG_ReadByte (); 845} 846 847 848//=========================================================================== 849 850void SZ_Clear (sizebuf_t *buf) 851{ 852 buf->cursize = 0; 853 buf->overflowed = false; 854} 855 856void *SZ_GetSpace (sizebuf_t *buf, int length) 857{ 858 void *data; 859 860 if (buf->cursize + length > buf->maxsize) 861 { 862 if (!buf->allowoverflow) 863 Sys_Error ("SZ_GetSpace: overflow without allowoverflow set (%d)", buf->maxsize); 864 865 if (length > buf->maxsize) 866 Sys_Error ("SZ_GetSpace: %i is > full buffer size", length); 867 868 Sys_Printf ("SZ_GetSpace: overflow\n"); // because Con_Printf may be redirected 869 SZ_Clear (buf); 870 buf->overflowed = true; 871 } 872 873 data = buf->data + buf->cursize; 874 buf->cursize += length; 875 876 return data; 877} 878 879void SZ_Write (sizebuf_t *buf, void *data, int length) 880{ 881 Q_memcpy (SZ_GetSpace(buf,length),data,length); 882} 883 884void SZ_Print (sizebuf_t *buf, char *data) 885{ 886 int len; 887 888 len = Q_strlen(data)+1; 889 890 if (!buf->cursize || buf->data[buf->cursize-1]) 891 Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0 892 else 893 Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0 894} 895 896 897//============================================================================ 898 899 900/* 901============ 902COM_SkipPath 903============ 904*/ 905char *COM_SkipPath (char *pathname) 906{ 907 char *last; 908 909 last = pathname; 910 while (*pathname) 911 { 912 if (*pathname=='/') 913 last = pathname+1; 914 pathname++; 915 } 916 return last; 917} 918 919/* 920============ 921COM_StripExtension 922============ 923*/ 924void COM_StripExtension (char *in, char *out) 925{ 926 while (*in && *in != '.') 927 *out++ = *in++; 928 *out = 0; 929} 930 931/* 932============ 933COM_FileExtension 934============ 935*/ 936char *COM_FileExtension (char *in) 937{ 938 static char exten[8]; 939 int i; 940 941 while (*in && *in != '.') 942 in++; 943 if (!*in) 944 return ""; 945 in++; 946 for (i=0 ; i<7 && *in ; i++,in++) 947 exten[i] = *in; 948 exten[i] = 0; 949 return exten; 950} 951 952/* 953============ 954COM_FileBase 955============ 956*/ 957void COM_FileBase (char *in, char *out) 958{ 959 char *s, *s2; 960 961 s = in + strlen(in) - 1; 962 963 while (s != in && *s != '.') 964 s--; 965 966 for (s2 = s ; *s2 && *s2 != '/' ; s2--) 967 ; 968 969 if (s-s2 < 2) 970 strcpy (out,"?model?"); 971 else 972 { 973 s--; 974 strncpy (out,s2+1, s-s2); 975 out[s-s2] = 0; 976 } 977} 978 979 980/* 981================== 982COM_DefaultExtension 983================== 984*/ 985void COM_DefaultExtension (char *path, char *extension) 986{ 987 char *src; 988// 989// if path doesn't have a .EXT, append extension 990// (extension should include the .) 991// 992 src = path + strlen(path) - 1; 993 994 while (*src != '/' && src != path) 995 { 996 if (*src == '.') 997 return; // it has an extension 998 src--; 999 } 1000 1001 strcat (path, extension); 1002} 1003 1004//============================================================================ 1005 1006char com_token[1024]; 1007int com_argc; 1008char **com_argv; 1009 1010 1011/* 1012============== 1013COM_Parse 1014 1015Parse a token out of a string 1016============== 1017*/ 1018char *COM_Parse (char *data) 1019{ 1020 int c; 1021 int len; 1022 1023 len = 0; 1024 com_token[0] = 0; 1025 1026 if (!data) 1027 return NULL; 1028 1029// skip whitespace 1030skipwhite: 1031 while ( (c = *data) <= ' ') 1032 { 1033 if (c == 0) 1034 return NULL; // end of file; 1035 data++; 1036 } 1037 1038// skip // comments 1039 if (c=='/' && data[1] == '/') 1040 { 1041 while (*data && *data != '\n') 1042 data++; 1043 goto skipwhite; 1044 } 1045 1046 1047// handle quoted strings specially 1048 if (c == '\"') 1049 { 1050 data++; 1051 while (1) 1052 { 1053 c = *data++; 1054 if (c=='\"' || !c) 1055 { 1056 com_token[len] = 0; 1057 return data; 1058 } 1059 com_token[len] = c; 1060 len++; 1061 } 1062 } 1063 1064// parse a regular word 1065 do 1066 { 1067 com_token[len] = c; 1068 data++; 1069 len++; 1070 c = *data; 1071 } while (c>32); 1072 1073 com_token[len] = 0; 1074 return data; 1075} 1076 1077 1078/* 1079================ 1080COM_CheckParm 1081 1082Returns the position (1 to argc-1) in the program's argument list 1083where the given parameter apears, or 0 if not present 1084================ 1085*/ 1086int COM_CheckParm (char *parm) 1087{ 1088 int i; 1089 1090 for (i=1 ; i<com_argc ; i++) 1091 { 1092 if (!com_argv[i]) 1093 continue; // NEXTSTEP sometimes clears appkit vars. 1094 if (!Q_strcmp (parm,com_argv[i])) 1095 return i; 1096 } 1097 1098 return 0; 1099} 1100 1101/* 1102================ 1103COM_CheckRegistered 1104 1105Looks for the pop.txt file and verifies it. 1106Sets the "registered" cvar. 1107Immediately exits out if an alternate game was attempted to be started without 1108being registered. 1109================ 1110*/ 1111void COM_CheckRegistered (void) 1112{ 1113 FILE *h; 1114 unsigned short check[128]; 1115 int i; 1116 1117 COM_FOpenFile("gfx/pop.lmp", &h); 1118 static_registered = 0; 1119 1120 if (!h) 1121 { 1122 Con_Printf ("Playing shareware version.\n"); 1123#ifndef SERVERONLY 1124// FIXME DEBUG -- only temporary 1125 if (com_modified) 1126 Sys_Error ("You must have the registered version to play QuakeWorld"); 1127#endif 1128 return; 1129 } 1130 1131 fread (check, 1, sizeof(check), h); 1132 fclose (h); 1133 1134 for (i=0 ; i<128 ; i++) 1135 if (pop[i] != (unsigned short)BigShort (check[i])) 1136 Sys_Error ("Corrupted data file."); 1137 1138 Cvar_Set ("registered", "1"); 1139 static_registered = 1; 1140 Con_Printf ("Playing registered version.\n"); 1141} 1142 1143 1144 1145/* 1146================ 1147COM_InitArgv 1148================ 1149*/ 1150void COM_InitArgv (int argc, char **argv) 1151{ 1152 qboolean safe; 1153 int i; 1154 1155 safe = false; 1156 1157 for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ; 1158 com_argc++) 1159 { 1160 largv[com_argc] = argv[com_argc]; 1161 if (!Q_strcmp ("-safe", argv[com_argc])) 1162 safe = true; 1163 } 1164 1165 if (safe) 1166 { 1167 // force all the safe-mode switches. Note that we reserved extra space in 1168 // case we need to add these, so we don't need an overflow check 1169 for (i=0 ; i<NUM_SAFE_ARGVS ; i++) 1170 { 1171 largv[com_argc] = safeargvs[i]; 1172 com_argc++; 1173 } 1174 } 1175 1176 largv[com_argc] = argvdummy; 1177 com_argv = largv; 1178} 1179 1180/* 1181================ 1182COM_AddParm 1183 1184Adds the given string at the end of the current argument list 1185================ 1186*/ 1187void COM_AddParm (char *parm) 1188{ 1189 largv[com_argc++] = parm; 1190} 1191 1192 1193/* 1194================ 1195COM_Init 1196================ 1197*/ 1198void COM_Init (void) 1199{ 1200 byte swaptest[2] = {1,0}; 1201 1202// set the byte swapping variables in a portable manner 1203 if ( *(short *)swaptest == 1) 1204 { 1205 bigendien = false; 1206 BigShort = ShortSwap; 1207 LittleShort = ShortNoSwap; 1208 BigLong = LongSwap; 1209 LittleLong = LongNoSwap; 1210 BigFloat = FloatSwap; 1211 LittleFloat = FloatNoSwap; 1212 } 1213 else 1214 { 1215 bigendien = true; 1216 BigShort = ShortNoSwap; 1217 LittleShort = ShortSwap; 1218 BigLong = LongNoSwap; 1219 LittleLong = LongSwap; 1220 BigFloat = FloatNoSwap; 1221 LittleFloat = FloatSwap; 1222 } 1223 1224 Cvar_RegisterVariable (®istered); 1225 Cmd_AddCommand ("path", COM_Path_f); 1226 1227 COM_InitFilesystem (); 1228 COM_CheckRegistered (); 1229} 1230 1231 1232/* 1233============ 1234va 1235 1236does a varargs printf into a temp buffer, so I don't need to have 1237varargs versions of all text functions. 1238FIXME: make this buffer size safe someday 1239============ 1240*/ 1241char *va(char *format, ...) 1242{ 1243 va_list argptr; 1244 static char string[1024]; 1245 1246 va_start (argptr, format); 1247 vsprintf (string, format,argptr); 1248 va_end (argptr); 1249 1250 return string; 1251} 1252 1253 1254/// just for debugging 1255int memsearch (byte *start, int count, int search) 1256{ 1257 int i; 1258 1259 for (i=0 ; i<count ; i++) 1260 if (start[i] == search) 1261 return i; 1262 return -1; 1263} 1264 1265/* 1266============================================================================= 1267 1268QUAKE FILESYSTEM 1269 1270============================================================================= 1271*/ 1272 1273int com_filesize; 1274 1275 1276// 1277// in memory 1278// 1279 1280typedef struct 1281{ 1282 char name[MAX_QPATH]; 1283 int filepos, filelen; 1284} packfile_t; 1285 1286typedef struct pack_s 1287{ 1288 char filename[MAX_OSPATH]; 1289 FILE *handle; 1290 int numfiles; 1291 packfile_t *files; 1292} pack_t; 1293 1294// 1295// on disk 1296// 1297typedef struct 1298{ 1299 char name[56]; 1300 int filepos, filelen; 1301} dpackfile_t; 1302 1303typedef struct 1304{ 1305 char id[4]; 1306 int dirofs; 1307 int dirlen; 1308} dpackheader_t; 1309 1310#define MAX_FILES_IN_PACK 2048 1311 1312char com_gamedir[MAX_OSPATH]; 1313char com_basedir[MAX_OSPATH]; 1314 1315typedef struct searchpath_s 1316{ 1317 char filename[MAX_OSPATH]; 1318 pack_t *pack; // only one of filename / pack will be used 1319 struct searchpath_s *next; 1320} searchpath_t; 1321 1322searchpath_t *com_searchpaths; 1323searchpath_t *com_base_searchpaths; // without gamedirs 1324 1325/* 1326================ 1327COM_filelength 1328================ 1329*/ 1330int COM_filelength (FILE *f) 1331{ 1332 int pos; 1333 int end; 1334 1335 pos = ftell (f); 1336 fseek (f, 0, SEEK_END); 1337 end = ftell (f); 1338 fseek (f, pos, SEEK_SET); 1339 1340 return end; 1341} 1342 1343int COM_FileOpenRead (char *path, FILE **hndl) 1344{ 1345 FILE *f; 1346 1347 f = fopen(path, "rb"); 1348 if (!f) 1349 { 1350 *hndl = NULL; 1351 return -1; 1352 } 1353 *hndl = f; 1354 1355 return COM_filelength(f); 1356} 1357 1358/* 1359============ 1360COM_Path_f 1361 1362============ 1363*/ 1364void COM_Path_f (void) 1365{ 1366 searchpath_t *s; 1367 1368 Con_Printf ("Current search path:\n"); 1369 for (s=com_searchpaths ; s ; s=s->next) 1370 { 1371 if (s == com_base_searchpaths) 1372 Con_Printf ("----------\n"); 1373 if (s->pack) 1374 Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles); 1375 else 1376 Con_Printf ("%s\n", s->filename); 1377 } 1378} 1379 1380/* 1381============ 1382COM_WriteFile 1383 1384The filename will be prefixed by the current game directory 1385============ 1386*/ 1387void COM_WriteFile (char *filename, void *data, int len) 1388{ 1389 FILE *f; 1390 char name[MAX_OSPATH]; 1391 1392 sprintf (name, "%s/%s", com_gamedir, filename); 1393 1394 f = fopen (name, "wb"); 1395 if (!f) { 1396 Sys_mkdir(com_gamedir); 1397 f = fopen (name, "wb"); 1398 if (!f) 1399 Sys_Error ("Error opening %s", filename); 1400 } 1401 1402 Sys_Printf ("COM_WriteFile: %s\n", name); 1403 fwrite (data, 1, len, f); 1404 fclose (f); 1405} 1406 1407 1408/* 1409============ 1410COM_CreatePath 1411 1412Only used for CopyFile and download 1413============ 1414*/ 1415void COM_CreatePath (char *path) 1416{ 1417 char *ofs; 1418 1419 for (ofs = path+1 ; *ofs ; ofs++) 1420 { 1421 if (*ofs == '/') 1422 { // create the directory 1423 *ofs = 0; 1424 Sys_mkdir (path); 1425 *ofs = '/'; 1426 } 1427 } 1428} 1429 1430 1431/* 1432=========== 1433COM_CopyFile 1434 1435Copies a file over from the net to the local cache, creating any directories 1436needed. This is for the convenience of developers using ISDN from home. 1437=========== 1438*/ 1439void COM_CopyFile (char *netpath, char *cachepath) 1440{ 1441 FILE *in, *out; 1442 int remaining, count; 1443 char buf[4096]; 1444 1445 remaining = COM_FileOpenRead (netpath, &in); 1446 COM_CreatePath (cachepath); // create directories up to the cache file 1447 out = fopen(cachepath, "wb"); 1448 if (!out) 1449 Sys_Error ("Error opening %s", cachepath); 1450 1451 while (remaining) 1452 { 1453 if (remaining < sizeof(buf)) 1454 count = remaining; 1455 else 1456 count = sizeof(buf); 1457 fread (buf, 1, count, in); 1458 fwrite (buf, 1, count, out); 1459 remaining -= count; 1460 } 1461 1462 fclose (in); 1463 fclose (out); 1464} 1465 1466/* 1467=========== 1468COM_FindFile 1469 1470Finds the file in the search path. 1471Sets com_filesize and one of handle or file 1472=========== 1473*/ 1474int file_from_pak; // global indicating file came from pack file ZOID 1475 1476int COM_FOpenFile (char *filename, FILE **file) 1477{ 1478 searchpath_t *search; 1479 char netpath[MAX_OSPATH]; 1480 pack_t *pak; 1481 int i; 1482 int findtime; 1483 1484 file_from_pak = 0; 1485 1486// 1487// search through the path, one element at a time 1488// 1489 for (search = com_searchpaths ; search ; search = search->next) 1490 { 1491 // is the element a pak file? 1492 if (search->pack) 1493 { 1494 // look through all the pak file elements 1495 pak = search->pack; 1496 for (i=0 ; i<pak->numfiles ; i++) 1497 if (!strcmp (pak->files[i].name, filename)) 1498 { // found it! 1499 Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename); 1500 // open a new file on the pakfile 1501 *file = fopen (pak->filename, "rb"); 1502 if (!*file) 1503 Sys_Error ("Couldn't reopen %s", pak->filename); 1504 fseek (*file, pak->files[i].filepos, SEEK_SET); 1505 com_filesize = pak->files[i].filelen; 1506 file_from_pak = 1; 1507 return com_filesize; 1508 } 1509 } 1510 else 1511 { 1512 // check a file in the directory tree 1513 if (!static_registered) 1514 { // if not a registered version, don't ever go beyond base 1515 if ( strchr (filename, '/') || strchr (filename,'\\')) 1516 continue; 1517 } 1518 1519 sprintf (netpath, "%s/%s",search->filename, filename); 1520 1521 findtime = Sys_FileTime (netpath); 1522 if (findtime == -1) 1523 continue; 1524 1525 Sys_Printf ("FindFile: %s\n",netpath); 1526 1527 *file = fopen (netpath, "rb"); 1528 return COM_filelength (*file); 1529 } 1530 1531 } 1532 1533 Sys_Printf ("FindFile: can't find %s\n", filename); 1534 1535 *file = NULL; 1536 com_filesize = -1; 1537 return -1; 1538} 1539 1540/* 1541============ 1542COM_LoadFile 1543 1544Filename are reletive to the quake directory. 1545Allways appends a 0 byte to the loaded data. 1546============ 1547*/ 1548cache_user_t *loadcache; 1549byte *loadbuf; 1550int loadsize; 1551byte *COM_LoadFile (char *path, int usehunk) 1552{ 1553 FILE *h; 1554 byte *buf; 1555 char base[32]; 1556 int len; 1557 1558 buf = NULL; // quiet compiler warning 1559 1560// look for it in the filesystem or pack files 1561 len = com_filesize = COM_FOpenFile (path, &h); 1562 if (!h) 1563 return NULL; 1564 1565// extract the filename base name for hunk tag 1566 COM_FileBase (path, base); 1567 1568 if (usehunk == 1) 1569 buf = Hunk_AllocName (len+1, base); 1570 else if (usehunk == 2) 1571 buf = Hunk_TempAlloc (len+1); 1572 else if (usehunk == 0) 1573 buf = Z_Malloc (len+1); 1574 else if (usehunk == 3) 1575 buf = Cache_Alloc (loadcache, len+1, base); 1576 else if (usehunk == 4) 1577 { 1578 if (len+1 > loadsize) 1579 buf = Hunk_TempAlloc (len+1); 1580 else 1581 buf = loadbuf; 1582 } 1583 else 1584 Sys_Error ("COM_LoadFile: bad usehunk"); 1585 1586 if (!buf) 1587 Sys_Error ("COM_LoadFile: not enough space for %s", path); 1588 1589 ((byte *)buf)[len] = 0; 1590#ifndef SERVERONLY 1591 Draw_BeginDisc (); 1592#endif 1593 fread (buf, 1, len, h); 1594 fclose (h); 1595#ifndef SERVERONLY 1596 Draw_EndDisc (); 1597#endif 1598 1599 return buf; 1600} 1601 1602byte *COM_LoadHunkFile (char *path) 1603{ 1604 return COM_LoadFile (path, 1); 1605} 1606 1607byte *COM_LoadTempFile (char *path) 1608{ 1609 return COM_LoadFile (path, 2); 1610} 1611 1612void COM_LoadCacheFile (char *path, struct cache_user_s *cu) 1613{ 1614 loadcache = cu; 1615 COM_LoadFile (path, 3); 1616} 1617 1618// uses temp hunk if larger than bufsize 1619byte *COM_LoadStackFile (char *path, void *buffer, int bufsize) 1620{ 1621 byte *buf; 1622 1623 loadbuf = (byte *)buffer; 1624 loadsize = bufsize; 1625 buf = COM_LoadFile (path, 4); 1626 1627 return buf; 1628} 1629 1630/* 1631================= 1632COM_LoadPackFile 1633 1634Takes an explicit (not game tree related) path to a pak file. 1635 1636Loads the header and directory, adding the files at the beginning 1637of the list so they override previous pack files. 1638================= 1639*/ 1640pack_t *COM_LoadPackFile (char *packfile) 1641{ 1642 dpackheader_t header; 1643 int i; 1644 packfile_t *newfiles; 1645 int numpackfiles; 1646 pack_t *pack; 1647 FILE *packhandle; 1648 dpackfile_t info[MAX_FILES_IN_PACK]; 1649 unsigned short crc; 1650 1651 if (COM_FileOpenRead (packfile, &packhandle) == -1) 1652 return NULL; 1653 1654 fread (&header, 1, sizeof(header), packhandle); 1655 if (header.id[0] != 'P' || header.id[1] != 'A' 1656 || header.id[2] != 'C' || header.id[3] != 'K') 1657 Sys_Error ("%s is not a packfile", packfile); 1658 header.dirofs = LittleLong (header.dirofs); 1659 header.dirlen = LittleLong (header.dirlen); 1660 1661 numpackfiles = header.dirlen / sizeof(dpackfile_t); 1662 1663 if (numpackfiles > MAX_FILES_IN_PACK) 1664 Sys_Error ("%s has %i files", packfile, numpackfiles); 1665 1666 if (numpackfiles != PAK0_COUNT) 1667 com_modified = true; // not the original file 1668 1669 newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t)); 1670 1671 fseek (packhandle, header.dirofs, SEEK_SET); 1672 fread (&info, 1, header.dirlen, packhandle); 1673 1674// crc the directory to check for modifications 1675 crc = CRC_Block((byte *)info, header.dirlen); 1676 1677// CRC_Init (&crc); 1678// for (i=0 ; i<header.dirlen ; i++) 1679// CRC_ProcessByte (&crc, ((byte *)info)[i]); 1680 if (crc != PAK0_CRC) 1681 com_modified = true; 1682 1683// parse the directory 1684 for (i=0 ; i<numpackfiles ; i++) 1685 { 1686 strcpy (newfiles[i].name, info[i].name); 1687 newfiles[i].filepos = LittleLong(info[i].filepos); 1688 newfiles[i].filelen = LittleLong(info[i].filelen); 1689 } 1690 1691 pack = Z_Malloc (sizeof (pack_t)); 1692 strcpy (pack->filename, packfile); 1693 pack->handle = packhandle; 1694 pack->numfiles = numpackfiles; 1695 pack->files = newfiles; 1696 1697 Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles); 1698 return pack; 1699} 1700 1701 1702/* 1703================ 1704COM_AddGameDirectory 1705 1706Sets com_gamedir, adds the directory to the head of the path, 1707then loads and adds pak1.pak pak2.pak ... 1708================ 1709*/ 1710void COM_AddGameDirectory (char *dir) 1711{ 1712 int i; 1713 searchpath_t *search; 1714 pack_t *pak; 1715 char pakfile[MAX_OSPATH]; 1716 char *p; 1717 1718 if ((p = strrchr(dir, '/')) != NULL) 1719 strcpy(gamedirfile, ++p); 1720 else 1721 strcpy(gamedirfile, p); 1722 strcpy (com_gamedir, dir); 1723 1724// 1725// add the directory to the search path 1726// 1727 search = Hunk_Alloc (sizeof(searchpath_t)); 1728 strcpy (search->filename, dir); 1729 search->next = com_searchpaths; 1730 com_searchpaths = search; 1731 1732// 1733// add any pak files in the format pak0.pak pak1.pak, ... 1734// 1735 for (i=0 ; ; i++) 1736 { 1737 sprintf (pakfile, "%s/pak%i.pak", dir, i); 1738 pak = COM_LoadPackFile (pakfile); 1739 if (!pak) 1740 break; 1741 search = Hunk_Alloc (sizeof(searchpath_t)); 1742 search->pack = pak; 1743 search->next = com_searchpaths; 1744 com_searchpaths = search; 1745 } 1746 1747} 1748 1749/* 1750================ 1751COM_Gamedir 1752 1753Sets the gamedir and path to a different directory. 1754================ 1755*/ 1756void COM_Gamedir (char *dir) 1757{ 1758 searchpath_t *search, *next; 1759 int i; 1760 pack_t *pak; 1761 char pakfile[MAX_OSPATH]; 1762 1763 if (strstr(dir, "..") || strstr(dir, "/") 1764 || strstr(dir, "\\") || strstr(dir, ":") ) 1765 { 1766 Con_Printf ("Gamedir should be a single filename, not a path\n"); 1767 return; 1768 } 1769 1770 if (!strcmp(gamedirfile, dir)) 1771 return; // still the same 1772 strcpy (gamedirfile, dir); 1773 1774 // 1775 // free up any current game dir info 1776 // 1777 while (com_searchpaths != com_base_searchpaths) 1778 { 1779 if (com_searchpaths->pack) 1780 { 1781 fclose (com_searchpaths->pack->handle); 1782 Z_Free (com_searchpaths->pack->files); 1783 Z_Free (com_searchpaths->pack); 1784 } 1785 next = com_searchpaths->next; 1786 Z_Free (com_searchpaths); 1787 com_searchpaths = next; 1788 } 1789 1790 // 1791 // flush all data, so it will be forced to reload 1792 // 1793 Cache_Flush (); 1794 1795 if (!strcmp(dir,"id1") || !strcmp(dir, "qw")) 1796 return; 1797 1798 sprintf (com_gamedir, "%s/%s", com_basedir, dir); 1799 1800 // 1801 // add the directory to the search path 1802 // 1803 search = Z_Malloc (sizeof(searchpath_t)); 1804 strcpy (search->filename, com_gamedir); 1805 search->next = com_searchpaths; 1806 com_searchpaths = search; 1807 1808 // 1809 // add any pak files in the format pak0.pak pak1.pak, ... 1810 // 1811 for (i=0 ; ; i++) 1812 { 1813 sprintf (pakfile, "%s/pak%i.pak", com_gamedir, i); 1814 pak = COM_LoadPackFile (pakfile); 1815 if (!pak) 1816 break; 1817 search = Z_Malloc (sizeof(searchpath_t)); 1818 search->pack = pak; 1819 search->next = com_searchpaths; 1820 com_searchpaths = search; 1821 } 1822} 1823 1824/* 1825================ 1826COM_InitFilesystem 1827================ 1828*/ 1829void COM_InitFilesystem (void) 1830{ 1831 int i; 1832 1833// 1834// -basedir <path> 1835// Overrides the system supplied base directory (under id1) 1836// 1837 i = COM_CheckParm ("-basedir"); 1838 if (i && i < com_argc-1) 1839 strcpy (com_basedir, com_argv[i+1]); 1840 else 1841 strcpy (com_basedir, host_parms.basedir); 1842 1843// 1844// start up with id1 by default 1845// 1846 COM_AddGameDirectory (va("%s/id1", com_basedir) ); 1847 COM_AddGameDirectory (va("%s/qw", com_basedir) ); 1848 1849 // any set gamedirs will be freed up to here 1850 com_base_searchpaths = com_searchpaths; 1851} 1852 1853 1854 1855/* 1856===================================================================== 1857 1858 INFO STRINGS 1859 1860===================================================================== 1861*/ 1862 1863/* 1864=============== 1865Info_ValueForKey 1866 1867Searches the string for the given 1868key and returns the associated value, or an empty string. 1869=============== 1870*/ 1871char *Info_ValueForKey (char *s, char *key) 1872{ 1873 char pkey[512]; 1874 static char value[4][512]; // use two buffers so compares 1875 // work without stomping on each other 1876 static int valueindex; 1877 char *o; 1878 1879 valueindex = (valueindex + 1) % 4; 1880 if (*s == '\\') 1881 s++; 1882 while (1) 1883 { 1884 o = pkey; 1885 while (*s != '\\') 1886 { 1887 if (!*s) 1888 return ""; 1889 *o++ = *s++; 1890 } 1891 *o = 0; 1892 s++; 1893 1894 o = value[valueindex]; 1895 1896 while (*s != '\\' && *s) 1897 { 1898 if (!*s) 1899 return ""; 1900 *o++ = *s++; 1901 } 1902 *o = 0; 1903 1904 if (!strcmp (key, pkey) ) 1905 return value[valueindex]; 1906 1907 if (!*s) 1908 return ""; 1909 s++; 1910 } 1911} 1912 1913void Info_RemoveKey (char *s, char *key) 1914{ 1915 char *start; 1916 char pkey[512]; 1917 char value[512]; 1918 char *o; 1919 1920 if (strstr (key, "\\")) 1921 { 1922 Con_Printf ("Can't use a key with a \\\n"); 1923 return; 1924 } 1925 1926 while (1) 1927 { 1928 start = s; 1929 if (*s == '\\') 1930 s++; 1931 o = pkey; 1932 while (*s != '\\') 1933 { 1934 if (!*s) 1935 return; 1936 *o++ = *s++; 1937 } 1938 *o = 0; 1939 s++; 1940 1941 o = value; 1942 while (*s != '\\' && *s) 1943 { 1944 if (!*s) 1945 return; 1946 *o++ = *s++; 1947 } 1948 *o = 0; 1949 1950 if (!strcmp (key, pkey) ) 1951 { 1952 strcpy (start, s); // remove this part 1953 return; 1954 } 1955 1956 if (!*s) 1957 return; 1958 } 1959 1960} 1961 1962void Info_RemovePrefixedKeys (char *start, char prefix) 1963{ 1964 char *s; 1965 char pkey[512]; 1966 char value[512]; 1967 char *o; 1968 1969 s = start; 1970 1971 while (1) 1972 { 1973 if (*s == '\\') 1974 s++; 1975 o = pkey; 1976 while (*s != '\\') 1977 { 1978 if (!*s) 1979 return; 1980 *o++ = *s++; 1981 } 1982 *o = 0; 1983 s++; 1984 1985 o = value; 1986 while (*s != '\\' && *s) 1987 { 1988 if (!*s) 1989 return; 1990 *o++ = *s++; 1991 } 1992 *o = 0; 1993 1994 if (pkey[0] == prefix) 1995 { 1996 Info_RemoveKey (start, pkey); 1997 s = start; 1998 } 1999 2000 if (!*s) 2001 return; 2002 } 2003 2004} 2005 2006 2007void Info_SetValueForStarKey (char *s, char *key, char *value, int maxsize) 2008{ 2009 char new[1024], *v; 2010 int c; 2011#ifdef SERVERONLY 2012 extern cvar_t sv_highchars; 2013#endif 2014 2015 if (strstr (key, "\\") || strstr (value, "\\") ) 2016 { 2017 Con_Printf ("Can't use keys or values with a \\\n"); 2018 return; 2019 } 2020 2021 if (strstr (key, "\"") || strstr (value, "\"") ) 2022 { 2023 Con_Printf ("Can't use keys or values with a \"\n"); 2024 return; 2025 } 2026 2027 if (strlen(key) > 63 || strlen(value) > 63) 2028 { 2029 Con_Printf ("Keys and values must be < 64 characters.\n"); 2030 return; 2031 } 2032 2033 // this next line is kinda trippy 2034 if (*(v = Info_ValueForKey(s, key))) { 2035 // key exists, make sure we have enough room for new value, if we don't, 2036 // don't change it! 2037 if (strlen(value) - strlen(v) + strlen(s) > maxsize) { 2038 Con_Printf ("Info string length exceeded\n"); 2039 return; 2040 } 2041 } 2042 Info_RemoveKey (s, key); 2043 if (!value || !strlen(value)) 2044 return; 2045 2046 sprintf (new, "\\%s\\%s", key, value); 2047 2048 if ((int)(strlen(new) + strlen(s)) > maxsize) 2049 { 2050 Con_Printf ("Info string length exceeded\n"); 2051 return; 2052 } 2053 2054 // only copy ascii values 2055 s += strlen(s); 2056 v = new; 2057 while (*v) 2058 { 2059 c = (unsigned char)*v++; 2060#ifndef SERVERONLY 2061 // client only allows highbits on name 2062 if (stricmp(key, "name") != 0) { 2063 c &= 127; 2064 if (c < 32 || c > 127) 2065 continue; 2066 // auto lowercase team 2067 if (stricmp(key, "team") == 0) 2068 c = tolower(c); 2069 } 2070#else 2071 if (!sv_highchars.value) { 2072 c &= 127; 2073 if (c < 32 || c > 127) 2074 continue; 2075 } 2076#endif 2077// c &= 127; // strip high bits 2078 if (c > 13) // && c < 127) 2079 *s++ = c; 2080 } 2081 *s = 0; 2082} 2083 2084void Info_SetValueForKey (char *s, char *key, char *value, int maxsize) 2085{ 2086 if (key[0] == '*') 2087 { 2088 Con_Printf ("Can't set * keys\n"); 2089 return; 2090 } 2091 2092 Info_SetValueForStarKey (s, key, value, maxsize); 2093} 2094 2095void Info_Print (char *s) 2096{ 2097 char key[512]; 2098 char value[512]; 2099 char *o; 2100 int l; 2101 2102 if (*s == '\\') 2103 s++; 2104 while (*s) 2105 { 2106 o = key; 2107 while (*s && *s != '\\') 2108 *o++ = *s++; 2109 2110 l = o - key; 2111 if (l < 20) 2112 { 2113 memset (o, ' ', 20-l); 2114 key[20] = 0; 2115 } 2116 else 2117 *o = 0; 2118 Con_Printf ("%s", key); 2119 2120 if (!*s) 2121 { 2122 Con_Printf ("MISSING VALUE\n"); 2123 return; 2124 } 2125 2126 o = value; 2127 s++; 2128 while (*s && *s != '\\') 2129 *o++ = *s++; 2130 *o = 0; 2131 2132 if (*s) 2133 s++; 2134 Con_Printf ("%s\n", value); 2135 } 2136} 2137 2138static byte chktbl[1024 + 4] = { 21390x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01, 21400x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a, 21410x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58, 21420xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3, 21430x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b, 21440x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36, 21450x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8, 21460x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27, 21470xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd, 21480xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63, 21490xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2, 21500x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d, 21510xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65, 21520x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f, 21530xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f, 21540x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42, 21550xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59, 21560xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9, 21570x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69, 21580xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba, 21590x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85, 21600xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4, 21610x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8, 21620xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa, 21630xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05, 21640x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7, 21650xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a, 21660x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb, 21670xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b, 21680x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d, 21690xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce, 21700x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3, 2171 2172// map checksum goes here 21730x00,0x00,0x00,0x00 2174}; 2175 2176static byte chkbuf[16 + 60 + 4]; 2177 2178static unsigned last_mapchecksum = 0; 2179 2180#if 0 2181/* 2182==================== 2183COM_BlockSequenceCheckByte 2184 2185For proxy protecting 2186==================== 2187*/ 2188byte COM_BlockSequenceCheckByte (byte *base, int length, int sequence, unsigned mapchecksum) 2189{ 2190 int checksum; 2191 byte *p; 2192 2193 if (last_mapchecksum != mapchecksum) { 2194 last_mapchecksum = mapchecksum; 2195 chktbl[1024] = (mapchecksum & 0xff000000) >> 24; 2196 chktbl[1025] = (mapchecksum & 0x00ff0000) >> 16; 2197 chktbl[1026] = (mapchecksum & 0x0000ff00) >> 8; 2198 chktbl[1027] = (mapchecksum & 0x000000ff); 2199 2200 Com_BlockFullChecksum (chktbl, sizeof(chktbl), chkbuf); 2201 } 2202 2203 p = chktbl + (sequence % (sizeof(chktbl) - 8)); 2204 2205 if (length > 60) 2206 length = 60; 2207 memcpy (chkbuf + 16, base, length); 2208 2209 length += 16; 2210 2211 chkbuf[length] = (sequence & 0xff) ^ p[0]; 2212 chkbuf[length+1] = p[1]; 2213 chkbuf[length+2] = ((sequence>>8) & 0xff) ^ p[2]; 2214 chkbuf[length+3] = p[3]; 2215 2216 length += 4; 2217 2218 checksum = LittleLong(Com_BlockChecksum (chkbuf, length)); 2219 2220 checksum &= 0xff; 2221 2222 return checksum; 2223} 2224#endif 2225 2226/* 2227==================== 2228COM_BlockSequenceCRCByte 2229 2230For proxy protecting 2231==================== 2232*/ 2233byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence) 2234{ 2235 unsigned short crc; 2236 byte *p; 2237 byte chkb[60 + 4]; 2238 2239 p = chktbl + (sequence % (sizeof(chktbl) - 8)); 2240 2241 if (length > 60) 2242 length = 60; 2243 memcpy (chkb, base, length); 2244 2245 chkb[length] = (sequence & 0xff) ^ p[0]; 2246 chkb[length+1] = p[1]; 2247 chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2]; 2248 chkb[length+3] = p[3]; 2249 2250 length += 4; 2251 2252 crc = CRC_Block(chkb, length); 2253 2254 crc &= 0xff; 2255 2256 return crc; 2257} 2258 2259// char *date = "Oct 24 1996"; 2260static char *date = __DATE__ ; 2261static char *mon[12] = 2262{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 2263static char mond[12] = 2264{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 2265 2266// returns days since Oct 24 1996 2267int build_number( void ) 2268{ 2269 int m = 0; 2270 int d = 0; 2271 int y = 0; 2272 static int b = 0; 2273 2274 if (b != 0) 2275 return b; 2276 2277 for (m = 0; m < 11; m++) 2278 { 2279 if (Q_strncasecmp( &date[0], mon[m], 3 ) == 0) 2280 break; 2281 d += mond[m]; 2282 } 2283 2284 d += atoi( &date[4] ) - 1; 2285 2286 y = atoi( &date[7] ) - 1900; 2287 2288 b = d + (int)((y - 1) * 365.25); 2289 2290 if (((y % 4) == 0) && m > 1) 2291 { 2292 b += 1; 2293 } 2294 2295 b -= 35778; // Dec 16 1998 2296 2297 return b; 2298} 2299 2300