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 <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 33 usercmd_t nullcmd; // guarenteed to be zero 34 35 static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1]; 36 static char *argvdummy = " "; 37 38 static char *safeargvs[NUM_SAFE_ARGVS] = 39 {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse"}; 40 41 cvar_t registered = CVAR2("registered","0"); 42 43 qboolean com_modified; // set true if using non-id files 44 45 int static_registered = 1; // only for startup check, then set 46 47 qboolean msg_suppress_1 = 0; 48 49 void COM_InitFilesystem (void); 50 void 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 57 qboolean standard_quake = true, rogue, hipnotic; 58 59 char gamedirfile[MAX_OSPATH]; 60 61 // this graphic needs to be in the pak file to use registered features 62 unsigned 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 85 All 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 87 The "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 88 only used during filesystem initialization. 89 90 The "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 92 The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines. If there is a cache directory 93 specified, when a file is found by the normal search path, it will be mirrored 94 into the cache directory, then opened there. 95 96 */ 97 98 //============================================================================ 99 100 101 // ClearLink is used for new headnodes 102 void ClearLink (link_t *l) 103 { 104 l->prev = l->next = l; 105 } 106 107 void RemoveLink (link_t *l) 108 { 109 l->next->prev = l->prev; 110 l->prev->next = l->next; 111 } 112 113 void 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 } 120 void 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 137 void 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 153 void 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 168 int 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 179 void Q_strcpy (char *dest, char *src) 180 { 181 while (*src) 182 { 183 *dest++ = *src++; 184 } 185 *dest++ = 0; 186 } 187 188 void 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 198 int Q_strlen (char *str) 199 { 200 int count; 201 202 count = 0; 203 while (str[count]) 204 count++; 205 206 return count; 207 } 208 209 char *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 218 void Q_strcat (char *dest, char *src) 219 { 220 dest += Q_strlen(dest); 221 Q_strcpy (dest, src); 222 } 223 224 int 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 239 int 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 256 int 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 286 int Q_strcasecmp (char *s1, char *s2) 287 { 288 return Q_strncasecmp (s1, s2, 99999); 289 } 290 291 #endif 292 293 int 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 352 float 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 435 qboolean bigendien; 436 437 short (*BigShort) (short l); 438 short (*LittleShort) (short l); 439 int (*BigLong) (int l); 440 int (*LittleLong) (int l); 441 float (*BigFloat) (float l); 442 float (*LittleFloat) (float l); 443 444 short 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 454 short ShortNoSwap (short l) 455 { 456 return l; 457 } 458 459 int 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 471 int LongNoSwap (int l) 472 { 473 return l; 474 } 475 476 float 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 493 float FloatNoSwap (float f) 494 { 495 return f; 496 } 497 498 /* 499 ============================================================================== 500 501 MESSAGE IO FUNCTIONS 502 503 Handles byte ordering and avoids alignment errors 504 ============================================================================== 505 */ 506 507 // 508 // writing functions 509 // 510 511 void 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 524 void 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 537 void 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 551 void 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 562 void 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 577 void 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 585 void MSG_WriteCoord (sizebuf_t *sb, float f) 586 { 587 MSG_WriteShort (sb, (int)(f*8)); 588 } 589 590 void MSG_WriteAngle (sizebuf_t *sb, float f) 591 { 592 MSG_WriteByte (sb, (int)(f*256/360) & 255); 593 } 594 595 void MSG_WriteAngle16 (sizebuf_t *sb, float f) 596 { 597 MSG_WriteShort (sb, (int)(f*65536/360) & 65535); 598 } 599 600 void 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 // 652 int msg_readcount; 653 qboolean msg_badread; 654 655 void MSG_BeginReading (void) 656 { 657 msg_readcount = 0; 658 msg_badread = false; 659 } 660 661 int MSG_GetReadCount(void) 662 { 663 return msg_readcount; 664 } 665 666 // returns -1 and sets msg_badread if no more characters are available 667 int 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 683 int 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 699 int 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 717 int 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 737 float 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 757 char *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 < (int) sizeof(string)-1); 771 772 string[l] = 0; 773 774 return string; 775 } 776 777 char *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 < (int) sizeof(string)-1); 791 792 string[l] = 0; 793 794 return string; 795 } 796 797 float MSG_ReadCoord (void) 798 { 799 return MSG_ReadShort() * (1.0/8); 800 } 801 802 float MSG_ReadAngle (void) 803 { 804 return MSG_ReadChar() * (360.0/256); 805 } 806 807 float MSG_ReadAngle16 (void) 808 { 809 return MSG_ReadShort() * (360.0/65536); 810 } 811 812 void 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 850 void SZ_Clear (sizebuf_t *buf) 851 { 852 buf->cursize = 0; 853 buf->overflowed = false; 854 } 855 856 void *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 879 void SZ_Write (sizebuf_t *buf, void *data, int length) 880 { 881 Q_memcpy (SZ_GetSpace(buf,length),data,length); 882 } 883 884 void 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 ============ 902 COM_SkipPath 903 ============ 904 */ 905 char *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 ============ 921 COM_StripExtension 922 ============ 923 */ 924 void COM_StripExtension (char *in, char *out) 925 { 926 while (*in && *in != '.') 927 *out++ = *in++; 928 *out = 0; 929 } 930 931 /* 932 ============ 933 COM_FileExtension 934 ============ 935 */ 936 char *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 ============ 954 COM_FileBase 955 ============ 956 */ 957 void 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 ================== 982 COM_DefaultExtension 983 ================== 984 */ 985 void 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 1006 char com_token[1024]; 1007 int com_argc; 1008 char **com_argv; 1009 1010 1011 /* 1012 ============== 1013 COM_Parse 1014 1015 Parse a token out of a string 1016 ============== 1017 */ 1018 char *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 1030 skipwhite: 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 ================ 1080 COM_CheckParm 1081 1082 Returns the position (1 to argc-1) in the program's argument list 1083 where the given parameter apears, or 0 if not present 1084 ================ 1085 */ 1086 int 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 ================ 1103 COM_CheckRegistered 1104 1105 Looks for the pop.txt file and verifies it. 1106 Sets the "registered" cvar. 1107 Immediately exits out if an alternate game was attempted to be started without 1108 being registered. 1109 ================ 1110 */ 1111 void 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 #if 0 1124 #ifndef SERVERONLY 1125 // FIXME DEBUG -- only temporary 1126 if (com_modified) 1127 Sys_Error ("You must have the registered version to play QuakeWorld"); 1128 #endif 1129 #endif 1130 return; 1131 } 1132 1133 fread (check, 1, sizeof(check), h); 1134 fclose (h); 1135 1136 for (i=0 ; i<128 ; i++) 1137 if (pop[i] != (unsigned short)BigShort (check[i])) 1138 Sys_Error ("Corrupted data file."); 1139 1140 Cvar_Set ("registered", "1"); 1141 static_registered = 1; 1142 Con_Printf ("Playing registered version.\n"); 1143 } 1144 1145 1146 1147 /* 1148 ================ 1149 COM_InitArgv 1150 ================ 1151 */ 1152 void COM_InitArgv (int argc, char **argv) 1153 { 1154 qboolean safe; 1155 int i; 1156 1157 safe = false; 1158 1159 for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ; 1160 com_argc++) 1161 { 1162 largv[com_argc] = argv[com_argc]; 1163 if (!Q_strcmp ("-safe", argv[com_argc])) 1164 safe = true; 1165 } 1166 1167 if (safe) 1168 { 1169 // force all the safe-mode switches. Note that we reserved extra space in 1170 // case we need to add these, so we don't need an overflow check 1171 for (i=0 ; i<NUM_SAFE_ARGVS ; i++) 1172 { 1173 largv[com_argc] = safeargvs[i]; 1174 com_argc++; 1175 } 1176 } 1177 1178 largv[com_argc] = argvdummy; 1179 com_argv = largv; 1180 } 1181 1182 /* 1183 ================ 1184 COM_AddParm 1185 1186 Adds the given string at the end of the current argument list 1187 ================ 1188 */ 1189 void COM_AddParm (char *parm) 1190 { 1191 largv[com_argc++] = parm; 1192 } 1193 1194 1195 /* 1196 ================ 1197 COM_Init 1198 ================ 1199 */ 1200 void COM_Init (void) 1201 { 1202 byte swaptest[2] = {1,0}; 1203 1204 // set the byte swapping variables in a portable manner 1205 if ( *(short *)swaptest == 1) 1206 { 1207 bigendien = false; 1208 BigShort = ShortSwap; 1209 LittleShort = ShortNoSwap; 1210 BigLong = LongSwap; 1211 LittleLong = LongNoSwap; 1212 BigFloat = FloatSwap; 1213 LittleFloat = FloatNoSwap; 1214 } 1215 else 1216 { 1217 bigendien = true; 1218 BigShort = ShortNoSwap; 1219 LittleShort = ShortSwap; 1220 BigLong = LongNoSwap; 1221 LittleLong = LongSwap; 1222 BigFloat = FloatNoSwap; 1223 LittleFloat = FloatSwap; 1224 } 1225 1226 Cvar_RegisterVariable (®istered); 1227 Cmd_AddCommand ("path", COM_Path_f); 1228 1229 COM_InitFilesystem (); 1230 COM_CheckRegistered (); 1231 } 1232 1233 1234 /* 1235 ============ 1236 va 1237 1238 does a varargs printf into a temp buffer, so I don't need to have 1239 varargs versions of all text functions. 1240 FIXME: make this buffer size safe someday 1241 ============ 1242 */ 1243 char *va(char *format, ...) 1244 { 1245 va_list argptr; 1246 static char string[1024]; 1247 1248 va_start (argptr, format); 1249 vsprintf (string, format,argptr); 1250 va_end (argptr); 1251 1252 return string; 1253 } 1254 1255 1256 /// just for debugging 1257 int memsearch (byte *start, int count, int search) 1258 { 1259 int i; 1260 1261 for (i=0 ; i<count ; i++) 1262 if (start[i] == search) 1263 return i; 1264 return -1; 1265 } 1266 1267 /* 1268 ============================================================================= 1269 1270 QUAKE FILESYSTEM 1271 1272 ============================================================================= 1273 */ 1274 1275 int com_filesize; 1276 1277 1278 // 1279 // in memory 1280 // 1281 1282 typedef struct 1283 { 1284 char name[MAX_QPATH]; 1285 int filepos, filelen; 1286 } packfile_t; 1287 1288 typedef struct pack_s 1289 { 1290 char filename[MAX_OSPATH]; 1291 FILE *handle; 1292 int numfiles; 1293 packfile_t *files; 1294 } pack_t; 1295 1296 // 1297 // on disk 1298 // 1299 typedef struct 1300 { 1301 char name[56]; 1302 int filepos, filelen; 1303 } dpackfile_t; 1304 1305 typedef struct 1306 { 1307 char id[4]; 1308 int dirofs; 1309 int dirlen; 1310 } dpackheader_t; 1311 1312 #define MAX_FILES_IN_PACK 2048 1313 1314 char com_gamedir[MAX_OSPATH]; 1315 char com_basedir[MAX_OSPATH]; 1316 1317 typedef struct searchpath_s 1318 { 1319 char filename[MAX_OSPATH]; 1320 pack_t *pack; // only one of filename / pack will be used 1321 struct searchpath_s *next; 1322 } searchpath_t; 1323 1324 searchpath_t *com_searchpaths; 1325 searchpath_t *com_base_searchpaths; // without gamedirs 1326 1327 /* 1328 ================ 1329 COM_filelength 1330 ================ 1331 */ 1332 int COM_filelength (FILE *f) 1333 { 1334 int pos; 1335 int end; 1336 1337 pos = ftell (f); 1338 fseek (f, 0, SEEK_END); 1339 end = ftell (f); 1340 fseek (f, pos, SEEK_SET); 1341 1342 return end; 1343 } 1344 1345 int COM_FileOpenRead (char *path, FILE **hndl) 1346 { 1347 FILE *f; 1348 1349 f = fopen(path, "rb"); 1350 if (!f) 1351 { 1352 *hndl = NULL; 1353 return -1; 1354 } 1355 *hndl = f; 1356 1357 return COM_filelength(f); 1358 } 1359 1360 /* 1361 ============ 1362 COM_Path_f 1363 1364 ============ 1365 */ 1366 void COM_Path_f (void) 1367 { 1368 searchpath_t *s; 1369 1370 Con_Printf ("Current search path:\n"); 1371 for (s=com_searchpaths ; s ; s=s->next) 1372 { 1373 if (s == com_base_searchpaths) 1374 Con_Printf ("----------\n"); 1375 if (s->pack) 1376 Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles); 1377 else 1378 Con_Printf ("%s\n", s->filename); 1379 } 1380 } 1381 1382 /* 1383 ============ 1384 COM_WriteFile 1385 1386 The filename will be prefixed by the current game directory 1387 ============ 1388 */ 1389 void COM_WriteFile (char *filename, void *data, int len) 1390 { 1391 FILE *f; 1392 char name[MAX_OSPATH]; 1393 1394 sprintf (name, "%s/%s", com_gamedir, filename); 1395 1396 f = fopen (name, "wb"); 1397 if (!f) { 1398 Sys_mkdir(com_gamedir); 1399 f = fopen (name, "wb"); 1400 if (!f) 1401 Sys_Error ("Error opening %s", filename); 1402 } 1403 1404 Sys_Printf ("COM_WriteFile: %s\n", name); 1405 fwrite (data, 1, len, f); 1406 fclose (f); 1407 } 1408 1409 1410 /* 1411 ============ 1412 COM_CreatePath 1413 1414 Only used for CopyFile and download 1415 ============ 1416 */ 1417 void COM_CreatePath (char *path) 1418 { 1419 char *ofs; 1420 1421 for (ofs = path+1 ; *ofs ; ofs++) 1422 { 1423 if (*ofs == '/') 1424 { // create the directory 1425 *ofs = 0; 1426 Sys_mkdir (path); 1427 *ofs = '/'; 1428 } 1429 } 1430 } 1431 1432 1433 /* 1434 =========== 1435 COM_CopyFile 1436 1437 Copies a file over from the net to the local cache, creating any directories 1438 needed. This is for the convenience of developers using ISDN from home. 1439 =========== 1440 */ 1441 void COM_CopyFile (char *netpath, char *cachepath) 1442 { 1443 FILE *in, *out; 1444 int remaining, count; 1445 char buf[4096]; 1446 1447 remaining = COM_FileOpenRead (netpath, &in); 1448 COM_CreatePath (cachepath); // create directories up to the cache file 1449 out = fopen(cachepath, "wb"); 1450 if (!out) 1451 Sys_Error ("Error opening %s", cachepath); 1452 1453 while (remaining) 1454 { 1455 if (remaining < (int) sizeof(buf)) 1456 count = remaining; 1457 else 1458 count = sizeof(buf); 1459 fread (buf, 1, count, in); 1460 fwrite (buf, 1, count, out); 1461 remaining -= count; 1462 } 1463 1464 fclose (in); 1465 fclose (out); 1466 } 1467 1468 /* 1469 =========== 1470 COM_FindFile 1471 1472 Finds the file in the search path. 1473 Sets com_filesize and one of handle or file 1474 =========== 1475 */ 1476 int file_from_pak; // global indicating file came from pack file ZOID 1477 1478 int COM_FOpenFile (char *filename, FILE **file) 1479 { 1480 searchpath_t *search; 1481 char netpath[MAX_OSPATH]; 1482 pack_t *pak; 1483 int i; 1484 int findtime; 1485 1486 file_from_pak = 0; 1487 1488 // 1489 // search through the path, one element at a time 1490 // 1491 for (search = com_searchpaths ; search ; search = search->next) 1492 { 1493 // is the element a pak file? 1494 if (search->pack) 1495 { 1496 // look through all the pak file elements 1497 pak = search->pack; 1498 for (i=0 ; i<pak->numfiles ; i++) 1499 if (!strcmp (pak->files[i].name, filename)) 1500 { // found it! 1501 Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename); 1502 // open a new file on the pakfile 1503 *file = fopen (pak->filename, "rb"); 1504 if (!*file) 1505 Sys_Error ("Couldn't reopen %s", pak->filename); 1506 fseek (*file, pak->files[i].filepos, SEEK_SET); 1507 com_filesize = pak->files[i].filelen; 1508 file_from_pak = 1; 1509 return com_filesize; 1510 } 1511 } 1512 else 1513 { 1514 // check a file in the directory tree 1515 if (!static_registered) 1516 { // if not a registered version, don't ever go beyond base 1517 if ( strchr (filename, '/') || strchr (filename,'\\')) 1518 continue; 1519 } 1520 1521 sprintf (netpath, "%s/%s",search->filename, filename); 1522 1523 findtime = Sys_FileTime (netpath); 1524 if (findtime == -1) 1525 continue; 1526 1527 Sys_Printf ("FindFile: %s\n",netpath); 1528 1529 *file = fopen (netpath, "rb"); 1530 return COM_filelength (*file); 1531 } 1532 1533 } 1534 1535 Sys_Printf ("FindFile: can't find %s\n", filename); 1536 1537 *file = NULL; 1538 com_filesize = -1; 1539 return -1; 1540 } 1541 1542 /* 1543 ============ 1544 COM_LoadFile 1545 1546 Filename are reletive to the quake directory. 1547 Allways appends a 0 byte to the loaded data. 1548 ============ 1549 */ 1550 cache_user_t *loadcache; 1551 byte *loadbuf; 1552 int loadsize; 1553 byte *COM_LoadFile (char *path, int usehunk) 1554 { 1555 FILE *h; 1556 byte *buf; 1557 char base[32]; 1558 int len; 1559 1560 buf = NULL; // quiet compiler warning 1561 1562 // look for it in the filesystem or pack files 1563 len = com_filesize = COM_FOpenFile (path, &h); 1564 if (!h) 1565 return NULL; 1566 1567 // extract the filename base name for hunk tag 1568 COM_FileBase (path, base); 1569 1570 if (usehunk == 1) 1571 buf = Hunk_AllocName (len+1, base); 1572 else if (usehunk == 2) 1573 buf = Hunk_TempAlloc (len+1); 1574 else if (usehunk == 0) 1575 buf = Z_Malloc (len+1); 1576 else if (usehunk == 3) 1577 buf = Cache_Alloc (loadcache, len+1, base); 1578 else if (usehunk == 4) 1579 { 1580 if (len+1 > loadsize) 1581 buf = Hunk_TempAlloc (len+1); 1582 else 1583 buf = loadbuf; 1584 } 1585 else 1586 Sys_Error ("COM_LoadFile: bad usehunk"); 1587 1588 if (!buf) 1589 Sys_Error ("COM_LoadFile: not enough space for %s", path); 1590 1591 ((byte *)buf)[len] = 0; 1592 #ifndef SERVERONLY 1593 Draw_BeginDisc (); 1594 #endif 1595 fread (buf, 1, len, h); 1596 fclose (h); 1597 #ifndef SERVERONLY 1598 Draw_EndDisc (); 1599 #endif 1600 1601 return buf; 1602 } 1603 1604 byte *COM_LoadHunkFile (char *path) 1605 { 1606 return COM_LoadFile (path, 1); 1607 } 1608 1609 byte *COM_LoadTempFile (char *path) 1610 { 1611 return COM_LoadFile (path, 2); 1612 } 1613 1614 void COM_LoadCacheFile (char *path, struct cache_user_s *cu) 1615 { 1616 loadcache = cu; 1617 COM_LoadFile (path, 3); 1618 } 1619 1620 // uses temp hunk if larger than bufsize 1621 byte *COM_LoadStackFile (char *path, void *buffer, int bufsize) 1622 { 1623 byte *buf; 1624 1625 loadbuf = (byte *)buffer; 1626 loadsize = bufsize; 1627 buf = COM_LoadFile (path, 4); 1628 1629 return buf; 1630 } 1631 1632 /* 1633 ================= 1634 COM_LoadPackFile 1635 1636 Takes an explicit (not game tree related) path to a pak file. 1637 1638 Loads the header and directory, adding the files at the beginning 1639 of the list so they override previous pack files. 1640 ================= 1641 */ 1642 pack_t *COM_LoadPackFile (char *packfile) 1643 { 1644 dpackheader_t header; 1645 int i; 1646 packfile_t *newfiles; 1647 int numpackfiles; 1648 pack_t *pack; 1649 FILE *packhandle; 1650 dpackfile_t info[MAX_FILES_IN_PACK]; 1651 unsigned short crc; 1652 1653 if (COM_FileOpenRead (packfile, &packhandle) == -1) 1654 return NULL; 1655 1656 fread (&header, 1, sizeof(header), packhandle); 1657 if (header.id[0] != 'P' || header.id[1] != 'A' 1658 || header.id[2] != 'C' || header.id[3] != 'K') 1659 Sys_Error ("%s is not a packfile", packfile); 1660 header.dirofs = LittleLong (header.dirofs); 1661 header.dirlen = LittleLong (header.dirlen); 1662 1663 numpackfiles = header.dirlen / sizeof(dpackfile_t); 1664 1665 if (numpackfiles > MAX_FILES_IN_PACK) 1666 Sys_Error ("%s has %i files", packfile, numpackfiles); 1667 1668 if (numpackfiles != PAK0_COUNT) 1669 com_modified = true; // not the original file 1670 1671 newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t)); 1672 1673 fseek (packhandle, header.dirofs, SEEK_SET); 1674 fread (&info, 1, header.dirlen, packhandle); 1675 1676 // crc the directory to check for modifications 1677 crc = CRC_Block((byte *)info, header.dirlen); 1678 1679 // CRC_Init (&crc); 1680 // for (i=0 ; i<header.dirlen ; i++) 1681 // CRC_ProcessByte (&crc, ((byte *)info)[i]); 1682 if (crc != PAK0_CRC) 1683 com_modified = true; 1684 1685 // parse the directory 1686 for (i=0 ; i<numpackfiles ; i++) 1687 { 1688 strcpy (newfiles[i].name, info[i].name); 1689 newfiles[i].filepos = LittleLong(info[i].filepos); 1690 newfiles[i].filelen = LittleLong(info[i].filelen); 1691 } 1692 1693 pack = Z_Malloc (sizeof (pack_t)); 1694 strcpy (pack->filename, packfile); 1695 pack->handle = packhandle; 1696 pack->numfiles = numpackfiles; 1697 pack->files = newfiles; 1698 1699 Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles); 1700 return pack; 1701 } 1702 1703 1704 /* 1705 ================ 1706 COM_AddGameDirectory 1707 1708 Sets com_gamedir, adds the directory to the head of the path, 1709 then loads and adds pak1.pak pak2.pak ... 1710 ================ 1711 */ 1712 void COM_AddGameDirectory (char *dir) 1713 { 1714 int i; 1715 searchpath_t *search; 1716 pack_t *pak; 1717 char pakfile[MAX_OSPATH]; 1718 char *p; 1719 1720 if ((p = strrchr(dir, '/')) != NULL) 1721 strcpy(gamedirfile, ++p); 1722 else 1723 strcpy(gamedirfile, p); 1724 strcpy (com_gamedir, dir); 1725 1726 // 1727 // add the directory to the search path 1728 // 1729 search = Hunk_Alloc (sizeof(searchpath_t)); 1730 strcpy (search->filename, dir); 1731 search->next = com_searchpaths; 1732 com_searchpaths = search; 1733 1734 // 1735 // add any pak files in the format pak0.pak pak1.pak, ... 1736 // 1737 for (i=0 ; ; i++) 1738 { 1739 sprintf (pakfile, "%s/pak%i.pak", dir, i); 1740 pak = COM_LoadPackFile (pakfile); 1741 if (!pak) 1742 break; 1743 search = Hunk_Alloc (sizeof(searchpath_t)); 1744 search->pack = pak; 1745 search->next = com_searchpaths; 1746 com_searchpaths = search; 1747 } 1748 1749 } 1750 1751 /* 1752 ================ 1753 COM_Gamedir 1754 1755 Sets the gamedir and path to a different directory. 1756 ================ 1757 */ 1758 void COM_Gamedir (char *dir) 1759 { 1760 searchpath_t *search, *next; 1761 int i; 1762 pack_t *pak; 1763 char pakfile[MAX_OSPATH]; 1764 1765 if (strstr(dir, "..") || strstr(dir, "/") 1766 || strstr(dir, "\\") || strstr(dir, ":") ) 1767 { 1768 Con_Printf ("Gamedir should be a single filename, not a path\n"); 1769 return; 1770 } 1771 1772 if (!strcmp(gamedirfile, dir)) 1773 return; // still the same 1774 strcpy (gamedirfile, dir); 1775 1776 // 1777 // free up any current game dir info 1778 // 1779 while (com_searchpaths != com_base_searchpaths) 1780 { 1781 if (com_searchpaths->pack) 1782 { 1783 fclose (com_searchpaths->pack->handle); 1784 Z_Free (com_searchpaths->pack->files); 1785 Z_Free (com_searchpaths->pack); 1786 } 1787 next = com_searchpaths->next; 1788 Z_Free (com_searchpaths); 1789 com_searchpaths = next; 1790 } 1791 1792 // 1793 // flush all data, so it will be forced to reload 1794 // 1795 Cache_Flush (); 1796 1797 if (!strcmp(dir,"id1") || !strcmp(dir, "qw")) 1798 return; 1799 1800 sprintf (com_gamedir, "%s/%s", com_basedir, dir); 1801 1802 // 1803 // add the directory to the search path 1804 // 1805 search = Z_Malloc (sizeof(searchpath_t)); 1806 strcpy (search->filename, com_gamedir); 1807 search->next = com_searchpaths; 1808 com_searchpaths = search; 1809 1810 // 1811 // add any pak files in the format pak0.pak pak1.pak, ... 1812 // 1813 for (i=0 ; ; i++) 1814 { 1815 sprintf (pakfile, "%s/pak%i.pak", com_gamedir, i); 1816 pak = COM_LoadPackFile (pakfile); 1817 if (!pak) 1818 break; 1819 search = Z_Malloc (sizeof(searchpath_t)); 1820 search->pack = pak; 1821 search->next = com_searchpaths; 1822 com_searchpaths = search; 1823 } 1824 } 1825 1826 /* 1827 ================ 1828 COM_InitFilesystem 1829 ================ 1830 */ 1831 void COM_InitFilesystem (void) 1832 { 1833 int i; 1834 1835 // 1836 // -basedir <path> 1837 // Overrides the system supplied base directory (under id1) 1838 // 1839 i = COM_CheckParm ("-basedir"); 1840 if (i && i < com_argc-1) 1841 strcpy (com_basedir, com_argv[i+1]); 1842 else 1843 strcpy (com_basedir, host_parms.basedir); 1844 1845 // 1846 // start up with id1 by default 1847 // 1848 COM_AddGameDirectory (va("%s/id1", com_basedir) ); 1849 COM_AddGameDirectory (va("%s/qw", com_basedir) ); 1850 1851 // any set gamedirs will be freed up to here 1852 com_base_searchpaths = com_searchpaths; 1853 } 1854 1855 1856 1857 /* 1858 ===================================================================== 1859 1860 INFO STRINGS 1861 1862 ===================================================================== 1863 */ 1864 1865 /* 1866 =============== 1867 Info_ValueForKey 1868 1869 Searches the string for the given 1870 key and returns the associated value, or an empty string. 1871 =============== 1872 */ 1873 char *Info_ValueForKey (char *s, char *key) 1874 { 1875 char pkey[512]; 1876 static char value[4][512]; // use two buffers so compares 1877 // work without stomping on each other 1878 static int valueindex; 1879 char *o; 1880 1881 valueindex = (valueindex + 1) % 4; 1882 if (*s == '\\') 1883 s++; 1884 while (1) 1885 { 1886 o = pkey; 1887 while (*s != '\\') 1888 { 1889 if (!*s) 1890 return ""; 1891 *o++ = *s++; 1892 } 1893 *o = 0; 1894 s++; 1895 1896 o = value[valueindex]; 1897 1898 while (*s != '\\' && *s) 1899 { 1900 if (!*s) 1901 return ""; 1902 *o++ = *s++; 1903 } 1904 *o = 0; 1905 1906 if (!strcmp (key, pkey) ) 1907 return value[valueindex]; 1908 1909 if (!*s) 1910 return ""; 1911 s++; 1912 } 1913 } 1914 1915 void Info_RemoveKey (char *s, char *key) 1916 { 1917 char *start; 1918 char pkey[512]; 1919 char value[512]; 1920 char *o; 1921 1922 if (strstr (key, "\\")) 1923 { 1924 Con_Printf ("Can't use a key with a \\\n"); 1925 return; 1926 } 1927 1928 while (1) 1929 { 1930 start = s; 1931 if (*s == '\\') 1932 s++; 1933 o = pkey; 1934 while (*s != '\\') 1935 { 1936 if (!*s) 1937 return; 1938 *o++ = *s++; 1939 } 1940 *o = 0; 1941 s++; 1942 1943 o = value; 1944 while (*s != '\\' && *s) 1945 { 1946 if (!*s) 1947 return; 1948 *o++ = *s++; 1949 } 1950 *o = 0; 1951 1952 if (!strcmp (key, pkey) ) 1953 { 1954 strcpy (start, s); // remove this part 1955 return; 1956 } 1957 1958 if (!*s) 1959 return; 1960 } 1961 1962 } 1963 1964 void Info_RemovePrefixedKeys (char *start, char prefix) 1965 { 1966 char *s; 1967 char pkey[512]; 1968 char value[512]; 1969 char *o; 1970 1971 s = start; 1972 1973 while (1) 1974 { 1975 if (*s == '\\') 1976 s++; 1977 o = pkey; 1978 while (*s != '\\') 1979 { 1980 if (!*s) 1981 return; 1982 *o++ = *s++; 1983 } 1984 *o = 0; 1985 s++; 1986 1987 o = value; 1988 while (*s != '\\' && *s) 1989 { 1990 if (!*s) 1991 return; 1992 *o++ = *s++; 1993 } 1994 *o = 0; 1995 1996 if (pkey[0] == prefix) 1997 { 1998 Info_RemoveKey (start, pkey); 1999 s = start; 2000 } 2001 2002 if (!*s) 2003 return; 2004 } 2005 2006 } 2007 2008 2009 void Info_SetValueForStarKey (char *s, char *key, char *value, int maxsize) 2010 { 2011 char new[1024], *v; 2012 int c; 2013 #ifdef SERVERONLY 2014 extern cvar_t sv_highchars; 2015 #endif 2016 2017 if (strstr (key, "\\") || strstr (value, "\\") ) 2018 { 2019 Con_Printf ("Can't use keys or values with a \\\n"); 2020 return; 2021 } 2022 2023 if (strstr (key, "\"") || strstr (value, "\"") ) 2024 { 2025 Con_Printf ("Can't use keys or values with a \"\n"); 2026 return; 2027 } 2028 2029 if (strlen(key) > 63 || strlen(value) > 63) 2030 { 2031 Con_Printf ("Keys and values must be < 64 characters.\n"); 2032 return; 2033 } 2034 2035 // this next line is kinda trippy 2036 if (*(v = Info_ValueForKey(s, key))) { 2037 // key exists, make sure we have enough room for new value, if we don't, 2038 // don't change it! 2039 if ((int) (strlen(value) - strlen(v) + strlen(s)) > maxsize) { 2040 Con_Printf ("Info string length exceeded\n"); 2041 return; 2042 } 2043 } 2044 Info_RemoveKey (s, key); 2045 if (!value || !strlen(value)) 2046 return; 2047 2048 sprintf (new, "\\%s\\%s", key, value); 2049 2050 if ((int)(strlen(new) + strlen(s)) > maxsize) 2051 { 2052 Con_Printf ("Info string length exceeded\n"); 2053 return; 2054 } 2055 2056 // only copy ascii values 2057 s += strlen(s); 2058 v = new; 2059 while (*v) 2060 { 2061 c = (unsigned char)*v++; 2062 #ifndef SERVERONLY 2063 // client only allows highbits on name 2064 if (stricmp(key, "name") != 0) { 2065 c &= 127; 2066 if (c < 32 || c > 127) 2067 continue; 2068 // auto lowercase team 2069 if (stricmp(key, "team") == 0) 2070 c = tolower(c); 2071 } 2072 #else 2073 if (!sv_highchars.value) { 2074 c &= 127; 2075 if (c < 32 || c > 127) 2076 continue; 2077 } 2078 #endif 2079 // c &= 127; // strip high bits 2080 if (c > 13) // && c < 127) 2081 *s++ = c; 2082 } 2083 *s = 0; 2084 } 2085 2086 void Info_SetValueForKey (char *s, char *key, char *value, int maxsize) 2087 { 2088 if (key[0] == '*') 2089 { 2090 Con_Printf ("Can't set * keys\n"); 2091 return; 2092 } 2093 2094 Info_SetValueForStarKey (s, key, value, maxsize); 2095 } 2096 2097 void Info_Print (char *s) 2098 { 2099 char key[512]; 2100 char value[512]; 2101 char *o; 2102 int l; 2103 2104 if (*s == '\\') 2105 s++; 2106 while (*s) 2107 { 2108 o = key; 2109 while (*s && *s != '\\') 2110 *o++ = *s++; 2111 2112 l = o - key; 2113 if (l < 20) 2114 { 2115 memset (o, ' ', 20-l); 2116 key[20] = 0; 2117 } 2118 else 2119 *o = 0; 2120 Con_Printf ("%s", key); 2121 2122 if (!*s) 2123 { 2124 Con_Printf ("MISSING VALUE\n"); 2125 return; 2126 } 2127 2128 o = value; 2129 s++; 2130 while (*s && *s != '\\') 2131 *o++ = *s++; 2132 *o = 0; 2133 2134 if (*s) 2135 s++; 2136 Con_Printf ("%s\n", value); 2137 } 2138 } 2139 2140 static byte chktbl[1024 + 4] = { 2141 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01, 2142 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a, 2143 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58, 2144 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3, 2145 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b, 2146 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36, 2147 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8, 2148 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27, 2149 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd, 2150 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63, 2151 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2, 2152 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d, 2153 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65, 2154 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f, 2155 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f, 2156 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42, 2157 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59, 2158 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9, 2159 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69, 2160 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba, 2161 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85, 2162 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4, 2163 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8, 2164 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa, 2165 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05, 2166 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7, 2167 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a, 2168 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb, 2169 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b, 2170 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d, 2171 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce, 2172 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3, 2173 2174 // map checksum goes here 2175 0x00,0x00,0x00,0x00 2176 }; 2177 2178 static byte chkbuf[16 + 60 + 4]; 2179 2180 static unsigned last_mapchecksum = 0; 2181 2182 #if 0 2183 /* 2184 ==================== 2185 COM_BlockSequenceCheckByte 2186 2187 For proxy protecting 2188 ==================== 2189 */ 2190 byte COM_BlockSequenceCheckByte (byte *base, int length, int sequence, unsigned mapchecksum) 2191 { 2192 int checksum; 2193 byte *p; 2194 2195 if (last_mapchecksum != mapchecksum) { 2196 last_mapchecksum = mapchecksum; 2197 chktbl[1024] = (mapchecksum & 0xff000000) >> 24; 2198 chktbl[1025] = (mapchecksum & 0x00ff0000) >> 16; 2199 chktbl[1026] = (mapchecksum & 0x0000ff00) >> 8; 2200 chktbl[1027] = (mapchecksum & 0x000000ff); 2201 2202 Com_BlockFullChecksum (chktbl, sizeof(chktbl), chkbuf); 2203 } 2204 2205 p = chktbl + (sequence % (sizeof(chktbl) - 8)); 2206 2207 if (length > 60) 2208 length = 60; 2209 memcpy (chkbuf + 16, base, length); 2210 2211 length += 16; 2212 2213 chkbuf[length] = (sequence & 0xff) ^ p[0]; 2214 chkbuf[length+1] = p[1]; 2215 chkbuf[length+2] = ((sequence>>8) & 0xff) ^ p[2]; 2216 chkbuf[length+3] = p[3]; 2217 2218 length += 4; 2219 2220 checksum = LittleLong(Com_BlockChecksum (chkbuf, length)); 2221 2222 checksum &= 0xff; 2223 2224 return checksum; 2225 } 2226 #endif 2227 2228 /* 2229 ==================== 2230 COM_BlockSequenceCRCByte 2231 2232 For proxy protecting 2233 ==================== 2234 */ 2235 byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence) 2236 { 2237 unsigned short crc; 2238 byte *p; 2239 byte chkb[60 + 4]; 2240 2241 p = chktbl + (sequence % (sizeof(chktbl) - 8)); 2242 2243 if (length > 60) 2244 length = 60; 2245 memcpy (chkb, base, length); 2246 2247 chkb[length] = (sequence & 0xff) ^ p[0]; 2248 chkb[length+1] = p[1]; 2249 chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2]; 2250 chkb[length+3] = p[3]; 2251 2252 length += 4; 2253 2254 crc = CRC_Block(chkb, length); 2255 2256 crc &= 0xff; 2257 2258 return crc; 2259 } 2260 2261 // char *date = "Oct 24 1996"; 2262 static char *date = __DATE__ ; 2263 static char *mon[12] = 2264 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 2265 static char mond[12] = 2266 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 2267 2268 // returns days since Oct 24 1996 2269 int build_number( void ) 2270 { 2271 int m = 0; 2272 int d = 0; 2273 int y = 0; 2274 static int b = 0; 2275 2276 if (b != 0) 2277 return b; 2278 2279 for (m = 0; m < 11; m++) 2280 { 2281 if (Q_strncasecmp( &date[0], mon[m], 3 ) == 0) 2282 break; 2283 d += mond[m]; 2284 } 2285 2286 d += atoi( &date[4] ) - 1; 2287 2288 y = atoi( &date[7] ) - 1900; 2289 2290 b = d + (int)((y - 1) * 365.25); 2291 2292 if (((y % 4) == 0) && m > 1) 2293 { 2294 b += 1; 2295 } 2296 2297 b -= 35778; // Dec 16 1998 2298 2299 return b; 2300 } 2301 2302