|
|
1.1 root 1: // common.c -- misc functions used in client and server
2:
3: #include "quakedef.h"
4:
5: #define NUM_SAFE_ARGVS 6
6:
7: static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
8: static char *argvdummy = " ";
9:
10: static char *safeargvs[NUM_SAFE_ARGVS] =
11: {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse"};
12:
13: cvar_t registered = {"registered","0"};
14:
15: qboolean com_modified; // set true if using non-id files
16:
17: int static_registered = 1; // only for startup check, then set
18:
19: void COM_InitFilesystem (void);
20:
21: // if a packfile directory differs from this, it is assumed to be hacked
22: #define PAK0_COUNT 339
23: #define PAK0_CRC 32981
24:
25: // this graphic needs to be in the pak file to use registered features
26: unsigned short pop[] =
27: {
28: 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
29: ,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000
30: ,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000
31: ,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600
32: ,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563
33: ,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564
34: ,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564
35: ,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563
36: ,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500
37: ,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200
38: ,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000
39: ,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000
40: ,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000
41: ,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000
42: ,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000
43: ,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000
44: };
45:
46: /*
47:
48:
49: 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.
50:
51: 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
52: only used during filesystem initialization.
53:
54: 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.
55:
56: The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines. If there is a cache directory
57: specified, when a file is found by the normal search path, it will be mirrored
58: into the cache directory, then opened there.
59:
60:
61:
62: FIXME:
63: The file "parms.txt" will be read out of the game directory and appended to the current command line arguments to allow different games to initialize startup parms differently. This could be used to add a "-sspeed 22050" for the high quality sound edition. Because they are added at the end, they will not override an explicit setting on the original command line.
64:
65: */
66:
67: //============================================================================
68:
69:
70: // ClearLink is used for new headnodes
71: void ClearLink (link_t *l)
72: {
73: l->prev = l->next = l;
74: }
75:
76: void RemoveLink (link_t *l)
77: {
78: l->next->prev = l->prev;
79: l->prev->next = l->next;
80: }
81:
82: void InsertLinkBefore (link_t *l, link_t *before)
83: {
84: l->next = before;
85: l->prev = before->prev;
86: l->prev->next = l;
87: l->next->prev = l;
88: }
89: void InsertLinkAfter (link_t *l, link_t *after)
90: {
91: l->next = after->next;
92: l->prev = after;
93: l->prev->next = l;
94: l->next->prev = l;
95: }
96:
97: /*
98: ============================================================================
99:
100: LIBRARY REPLACEMENT FUNCTIONS
101:
102: ============================================================================
103: */
104:
105: void Q_memset (void *dest, int fill, int count)
106: {
107: int i;
108:
109: if ( (((long)dest | count) & 3) == 0)
110: {
111: count >>= 2;
112: fill = fill | (fill<<8) | (fill<<16) | (fill<<24);
113: for (i=0 ; i<count ; i++)
114: ((int *)dest)[i] = fill;
115: }
116: else
117: for (i=0 ; i<count ; i++)
118: ((byte *)dest)[i] = fill;
119: }
120:
121: void Q_memcpy (void *dest, void *src, int count)
122: {
123: int i;
124:
125: if (( ( (long)dest | (long)src | count) & 3) == 0 )
126: {
127: count>>=2;
128: for (i=0 ; i<count ; i++)
129: ((int *)dest)[i] = ((int *)src)[i];
130: }
131: else
132: for (i=0 ; i<count ; i++)
133: ((byte *)dest)[i] = ((byte *)src)[i];
134: }
135:
136: int Q_memcmp (void *m1, void *m2, int count)
137: {
138: while(count)
139: {
140: count--;
141: if (((byte *)m1)[count] != ((byte *)m2)[count])
142: return -1;
143: }
144: return 0;
145: }
146:
147: void Q_strcpy (char *dest, char *src)
148: {
149: while (*src)
150: {
151: *dest++ = *src++;
152: }
153: *dest++ = 0;
154: }
155:
156: void Q_strncpy (char *dest, char *src, int count)
157: {
158: while (*src && count--)
159: {
160: *dest++ = *src++;
161: }
162: if (count)
163: *dest++ = 0;
164: }
165:
166: int Q_strlen (char *str)
167: {
168: int count;
169:
170: count = 0;
171: while (str[count])
172: count++;
173:
174: return count;
175: }
176:
177: char *Q_strrchr(char *s, char c)
178: {
179: int len = Q_strlen(s);
180: s += len;
181: while (len--)
182: if (*--s == c) return s;
183: return 0;
184: }
185:
186: void Q_strcat (char *dest, char *src)
187: {
188: dest += Q_strlen(dest);
189: Q_strcpy (dest, src);
190: }
191:
192: int Q_strcmp (char *s1, char *s2)
193: {
194: while (1)
195: {
196: if (*s1 != *s2)
197: return -1; // strings not equal
198: if (!*s1)
199: return 0; // strings are equal
200: s1++;
201: s2++;
202: }
203:
204: return -1;
205: }
206:
207: int Q_strncmp (char *s1, char *s2, int count)
208: {
209: while (1)
210: {
211: if (!count--)
212: return 0;
213: if (*s1 != *s2)
214: return -1; // strings not equal
215: if (!*s1)
216: return 0; // strings are equal
217: s1++;
218: s2++;
219: }
220:
221: return -1;
222: }
223:
224: int Q_strncasecmp (char *s1, char *s2, int n)
225: {
226: int c1, c2;
227:
228: while (1)
229: {
230: c1 = *s1++;
231: c2 = *s2++;
232:
233: if (!n--)
234: return 0; // strings are equal until end point
235:
236: if (c1 != c2)
237: {
238: if (c1 >= 'a' && c1 <= 'z')
239: c1 -= ('a' - 'A');
240: if (c2 >= 'a' && c2 <= 'z')
241: c2 -= ('a' - 'A');
242: if (c1 != c2)
243: return -1; // strings not equal
244: }
245: if (!c1)
246: return 0; // strings are equal
247: // s1++;
248: // s2++;
249: }
250:
251: return -1;
252: }
253:
254: int Q_strcasecmp (char *s1, char *s2)
255: {
256: return Q_strncasecmp (s1, s2, 99999);
257: }
258:
259: int Q_atoi (char *str)
260: {
261: int val;
262: int sign;
263: int c;
264:
265: if (*str == '-')
266: {
267: sign = -1;
268: str++;
269: }
270: else
271: sign = 1;
272:
273: val = 0;
274:
275: //
276: // check for hex
277: //
278: if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
279: {
280: str += 2;
281: while (1)
282: {
283: c = *str++;
284: if (c >= '0' && c <= '9')
285: val = (val<<4) + c - '0';
286: else if (c >= 'a' && c <= 'f')
287: val = (val<<4) + c - 'a' + 10;
288: else if (c >= 'A' && c <= 'F')
289: val = (val<<4) + c - 'A' + 10;
290: else
291: return val*sign;
292: }
293: }
294:
295: //
296: // check for character
297: //
298: if (str[0] == '\'')
299: {
300: return sign * str[1];
301: }
302:
303: //
304: // assume decimal
305: //
306: while (1)
307: {
308: c = *str++;
309: if (c <'0' || c > '9')
310: return val*sign;
311: val = val*10 + c - '0';
312: }
313:
314: return 0;
315: }
316:
317:
318: float Q_atof (char *str)
319: {
320: float val;
321: int sign;
322: int c;
323: int decimal, total;
324:
325: if (*str == '-')
326: {
327: sign = -1;
328: str++;
329: }
330: else
331: sign = 1;
332:
333: val = 0;
334:
335: //
336: // check for hex
337: //
338: if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
339: {
340: str += 2;
341: while (1)
342: {
343: c = *str++;
344: if (c >= '0' && c <= '9')
345: val = (val*16) + c - '0';
346: else if (c >= 'a' && c <= 'f')
347: val = (val*16) + c - 'a' + 10;
348: else if (c >= 'A' && c <= 'F')
349: val = (val*16) + c - 'A' + 10;
350: else
351: return val*sign;
352: }
353: }
354:
355: //
356: // check for character
357: //
358: if (str[0] == '\'')
359: {
360: return sign * str[1];
361: }
362:
363: //
364: // assume decimal
365: //
366: decimal = -1;
367: total = 0;
368: while (1)
369: {
370: c = *str++;
371: if (c == '.')
372: {
373: decimal = total;
374: continue;
375: }
376: if (c <'0' || c > '9')
377: break;
378: val = val*10 + c - '0';
379: total++;
380: }
381:
382: if (decimal == -1)
383: return val*sign;
384: while (total > decimal)
385: {
386: val /= 10;
387: total--;
388: }
389:
390: return val*sign;
391: }
392:
393: /*
394: ============================================================================
395:
396: BYTE ORDER FUNCTIONS
397:
398: ============================================================================
399: */
400:
401: qboolean bigendien;
402:
403: short (*BigShort) (short l);
404: short (*LittleShort) (short l);
405: int (*BigLong) (int l);
406: int (*LittleLong) (int l);
407: float (*BigFloat) (float l);
408: float (*LittleFloat) (float l);
409:
410: short ShortSwap (short l)
411: {
412: byte b1,b2;
413:
414: b1 = l&255;
415: b2 = (l>>8)&255;
416:
417: return (b1<<8) + b2;
418: }
419:
420: short ShortNoSwap (short l)
421: {
422: return l;
423: }
424:
425: int LongSwap (int l)
426: {
427: byte b1,b2,b3,b4;
428:
429: b1 = l&255;
430: b2 = (l>>8)&255;
431: b3 = (l>>16)&255;
432: b4 = (l>>24)&255;
433:
434: return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
435: }
436:
437: int LongNoSwap (int l)
438: {
439: return l;
440: }
441:
442: float FloatSwap (float f)
443: {
444: union
445: {
446: float f;
447: byte b[4];
448: } dat1, dat2;
449:
450:
451: dat1.f = f;
452: dat2.b[0] = dat1.b[3];
453: dat2.b[1] = dat1.b[2];
454: dat2.b[2] = dat1.b[1];
455: dat2.b[3] = dat1.b[0];
456: return dat2.f;
457: }
458:
459: float FloatNoSwap (float f)
460: {
461: return f;
462: }
463:
464: /*
465: ==============================================================================
466:
467: MESSAGE IO FUNCTIONS
468:
469: Handles byte ordering and avoids alignment errors
470: ==============================================================================
471: */
472:
473: //
474: // writing functions
475: //
476:
477: void MSG_WriteChar (sizebuf_t *sb, int c)
478: {
479: byte *buf;
480:
481: #ifdef PARANOID
482: if (c < -128 || c > 127)
483: Sys_Error ("MSG_WriteChar: range error");
484: #endif
485:
486: buf = SZ_GetSpace (sb, 1);
487: buf[0] = c;
488: }
489:
490: void MSG_WriteByte (sizebuf_t *sb, int c)
491: {
492: byte *buf;
493:
494: #ifdef PARANOID
495: if (c < 0 || c > 255)
496: Sys_Error ("MSG_WriteByte: range error");
497: #endif
498:
499: buf = SZ_GetSpace (sb, 1);
500: buf[0] = c;
501: }
502:
503: void MSG_WriteShort (sizebuf_t *sb, int c)
504: {
505: byte *buf;
506:
507: #ifdef PARANOID
508: if (c < ((short)0x8000) || c > (short)0x7fff)
509: Sys_Error ("MSG_WriteShort: range error");
510: #endif
511:
512: buf = SZ_GetSpace (sb, 2);
513: buf[0] = c&0xff;
514: buf[1] = c>>8;
515: }
516:
517: void MSG_WriteLong (sizebuf_t *sb, int c)
518: {
519: byte *buf;
520:
521: buf = SZ_GetSpace (sb, 4);
522: buf[0] = c&0xff;
523: buf[1] = (c>>8)&0xff;
524: buf[2] = (c>>16)&0xff;
525: buf[3] = c>>24;
526: }
527:
528: void MSG_WriteFloat (sizebuf_t *sb, float f)
529: {
530: union
531: {
532: float f;
533: int l;
534: } dat;
535:
536:
537: dat.f = f;
538: dat.l = LittleLong (dat.l);
539:
540: SZ_Write (sb, &dat.l, 4);
541: }
542:
543: void MSG_WriteString (sizebuf_t *sb, char *s)
544: {
545: if (!s)
546: SZ_Write (sb, "", 1);
547: else
548: SZ_Write (sb, s, Q_strlen(s)+1);
549: }
550:
551: void MSG_WriteCoord (sizebuf_t *sb, float f)
552: {
553: MSG_WriteShort (sb, (int)(f*8));
554: }
555:
556: void MSG_WriteAngle (sizebuf_t *sb, float f)
557: {
558: MSG_WriteByte (sb, ((int)f*256/360) & 255);
559: }
560:
561: //
562: // reading functions
563: //
564: int msg_readcount;
565: qboolean msg_badread;
566:
567: void MSG_BeginReading (void)
568: {
569: msg_readcount = 0;
570: msg_badread = false;
571: }
572:
573: // returns -1 and sets msg_badread if no more characters are available
574: int MSG_ReadChar (void)
575: {
576: int c;
577:
578: if (msg_readcount+1 > net_message.cursize)
579: {
580: msg_badread = true;
581: return -1;
582: }
583:
584: c = (signed char)net_message.data[msg_readcount];
585: msg_readcount++;
586:
587: return c;
588: }
589:
590: int MSG_ReadByte (void)
591: {
592: int c;
593:
594: if (msg_readcount+1 > net_message.cursize)
595: {
596: msg_badread = true;
597: return -1;
598: }
599:
600: c = (unsigned char)net_message.data[msg_readcount];
601: msg_readcount++;
602:
603: return c;
604: }
605:
606: int MSG_ReadShort (void)
607: {
608: int c;
609:
610: if (msg_readcount+2 > net_message.cursize)
611: {
612: msg_badread = true;
613: return -1;
614: }
615:
616: c = (short)(net_message.data[msg_readcount]
617: + (net_message.data[msg_readcount+1]<<8));
618:
619: msg_readcount += 2;
620:
621: return c;
622: }
623:
624: int MSG_ReadLong (void)
625: {
626: int c;
627:
628: if (msg_readcount+4 > net_message.cursize)
629: {
630: msg_badread = true;
631: return -1;
632: }
633:
634: c = net_message.data[msg_readcount]
635: + (net_message.data[msg_readcount+1]<<8)
636: + (net_message.data[msg_readcount+2]<<16)
637: + (net_message.data[msg_readcount+3]<<24);
638:
639: msg_readcount += 4;
640:
641: return c;
642: }
643:
644: float MSG_ReadFloat (void)
645: {
646: union
647: {
648: byte b[4];
649: float f;
650: int l;
651: } dat;
652:
653: dat.b[0] = net_message.data[msg_readcount];
654: dat.b[1] = net_message.data[msg_readcount+1];
655: dat.b[2] = net_message.data[msg_readcount+2];
656: dat.b[3] = net_message.data[msg_readcount+3];
657: msg_readcount += 4;
658:
659: dat.l = LittleLong (dat.l);
660:
661: return dat.f;
662: }
663:
664: char *MSG_ReadString (void)
665: {
666: static char string[2048];
667: int l,c;
668:
669: l = 0;
670: do
671: {
672: c = MSG_ReadChar ();
673: if (c == -1 || c == 0)
674: break;
675: string[l] = c;
676: l++;
677: } while (l < sizeof(string)-1);
678:
679: string[l] = 0;
680:
681: return string;
682: }
683:
684: float MSG_ReadCoord (void)
685: {
686: return MSG_ReadShort() * (1.0/8);
687: }
688:
689: float MSG_ReadAngle (void)
690: {
691: return MSG_ReadChar() * (360.0/256);
692: }
693:
694:
695:
696: //===========================================================================
697:
698: void SZ_Alloc (sizebuf_t *buf, int startsize)
699: {
700: if (startsize < 256)
701: startsize = 256;
702: buf->data = Hunk_AllocName (startsize, "sizebuf");
703: buf->maxsize = startsize;
704: buf->cursize = 0;
705: }
706:
707:
708: void SZ_Free (sizebuf_t *buf)
709: {
710: // Z_Free (buf->data);
711: // buf->data = NULL;
712: // buf->maxsize = 0;
713: buf->cursize = 0;
714: }
715:
716: void SZ_Clear (sizebuf_t *buf)
717: {
718: buf->cursize = 0;
719: }
720:
721: void *SZ_GetSpace (sizebuf_t *buf, int length)
722: {
723: void *data;
724:
725: if (buf->cursize + length > buf->maxsize)
726: {
727: if (!buf->allowoverflow)
728: Sys_Error ("SZ_GetSpace: overflow without allowoverflow set");
729:
730: if (length > buf->maxsize)
731: Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);
732:
733: buf->overflowed = true;
734: Con_Printf ("SZ_GetSpace: overflow");
735: SZ_Clear (buf);
736: }
737:
738: data = buf->data + buf->cursize;
739: buf->cursize += length;
740:
741: return data;
742: }
743:
744: void SZ_Write (sizebuf_t *buf, void *data, int length)
745: {
746: Q_memcpy (SZ_GetSpace(buf,length),data,length);
747: }
748:
749: void SZ_Print (sizebuf_t *buf, char *data)
750: {
751: int len;
752:
753: len = Q_strlen(data)+1;
754:
755: // byte * cast to keep VC++ happy
756: if (buf->data[buf->cursize-1])
757: Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
758: else
759: Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
760: }
761:
762:
763: //============================================================================
764:
765:
766: /*
767: ============
768: COM_SkipPath
769: ============
770: */
771: char *COM_SkipPath (char *pathname)
772: {
773: char *last;
774:
775: last = pathname;
776: while (*pathname)
777: {
778: if (*pathname=='/')
779: last = pathname+1;
780: pathname++;
781: }
782: return last;
783: }
784:
785: /*
786: ============
787: COM_StripExtension
788: ============
789: */
790: void COM_StripExtension (char *in, char *out)
791: {
792: while (*in && *in != '.')
793: *out++ = *in++;
794: *out = 0;
795: }
796:
797: /*
798: ============
799: COM_FileExtension
800: ============
801: */
802: char *COM_FileExtension (char *in)
803: {
804: static char exten[8];
805: int i;
806:
807: while (*in && *in != '.')
808: in++;
809: if (!*in)
810: return "";
811: in++;
812: for (i=0 ; i<7 && *in ; i++,in++)
813: exten[i] = *in;
814: exten[i] = 0;
815: return exten;
816: }
817:
818: /*
819: ============
820: COM_FileBase
821: ============
822: */
823: void COM_FileBase (char *in, char *out)
824: {
825: char *s, *s2;
826:
827: s = in + strlen(in) - 1;
828:
829: while (s != in && *s != '.')
830: s--;
831:
832: for (s2 = s ; *s2 && *s2 != '/' ; s2--)
833: ;
834:
835: if (s-s2 < 2)
836: strcpy (out,"?model?");
837: else
838: {
839: s--;
840: strncpy (out,s2+1, s-s2);
841: out[s-s2] = 0;
842: }
843: }
844:
845:
846: /*
847: ==================
848: COM_DefaultExtension
849: ==================
850: */
851: void COM_DefaultExtension (char *path, char *extension)
852: {
853: char *src;
854: //
855: // if path doesn't have a .EXT, append extension
856: // (extension should include the .)
857: //
858: src = path + strlen(path) - 1;
859:
860: while (*src != '/' && src != path)
861: {
862: if (*src == '.')
863: return; // it has an extension
864: src--;
865: }
866:
867: strcat (path, extension);
868: }
869:
870: //============================================================================
871:
872: char com_token[1024];
873: int com_argc;
874: char **com_argv;
875:
876:
877: /*
878: ==============
879: COM_Parse
880:
881: Parse a token out of a string
882: ==============
883: */
884: char *COM_Parse (char *data)
885: {
886: int c;
887: int len;
888:
889: len = 0;
890: com_token[0] = 0;
891:
892: if (!data)
893: return NULL;
894:
895: // skip whitespace
896: skipwhite:
897: while ( (c = *data) <= ' ')
898: {
899: if (c == 0)
900: return NULL; // end of file;
901: data++;
902: }
903:
904: // skip // comments
905: if (c=='/' && data[1] == '/')
906: {
907: while (*data && *data != '\n')
908: data++;
909: goto skipwhite;
910: }
911:
912:
913: // handle quoted strings specially
914: if (c == '\"')
915: {
916: data++;
917: while (1)
918: {
919: c = *data++;
920: if (c=='\"' || !c)
921: {
922: com_token[len] = 0;
923: return data;
924: }
925: com_token[len] = c;
926: len++;
927: }
928: }
929:
930: // parse single characters
931: if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
932: {
933: com_token[len] = c;
934: len++;
935: com_token[len] = 0;
936: return data+1;
937: }
938:
939: // parse a regular word
940: do
941: {
942: com_token[len] = c;
943: data++;
944: len++;
945: c = *data;
946: if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
947: break;
948: } while (c>32);
949:
950: com_token[len] = 0;
951: return data;
952: }
953:
954:
955: /*
956: ================
957: COM_CheckParm
958:
959: Returns the position (1 to argc-1) in the program's argument list
960: where the given parameter apears, or 0 if not present
961: ================
962: */
963: int COM_CheckParm (char *parm)
964: {
965: int i;
966:
967: for (i=1 ; i<com_argc ; i++)
968: {
969: if (!com_argv[i])
970: continue; // NEXTSTEP sometimes clears appkit vars.
971: if (!Q_strcmp (parm,com_argv[i]))
972: return i;
973: }
974:
975: return 0;
976: }
977:
978: /*
979: ================
980: COM_CheckRegistered
981:
982: Looks for the pop.txt file and verifies it.
983: Sets the "registered" cvar.
984: Immediately exits out if an alternate game was attempted to be started without
985: being registered.
986: ================
987: */
988: void COM_CheckRegistered (void)
989: {
990: int h;
991: unsigned short check[128];
992: int i;
993:
994: COM_OpenFile("gfx/pop.lmp", &h);
995: static_registered = 0;
996:
997: if (h == -1)
998: {
999: #if WINDED
1000: Sys_Error ("This dedicated server requires a full registered copy of Quake");
1001: #endif
1002: Con_Printf ("Playing shareware version.\n");
1003: if (com_modified)
1004: Sys_Error ("You must have the registered version to use modified games");
1005: return;
1006: }
1007:
1008: Sys_FileRead (h, check, sizeof(check));
1009: COM_CloseFile (h);
1010:
1011: for (i=0 ; i<128 ; i++)
1012: if (pop[i] != (unsigned short)BigShort (check[i]))
1013: Sys_Error ("Corrupted data file.");
1014:
1015: Cvar_Set ("registered", "1");
1016: static_registered = 1;
1017: Con_Printf ("Playing registered version.\n");
1018: }
1019:
1020:
1021: void COM_Path_f (void);
1022:
1023:
1024: /*
1025: ================
1026: COM_InitArgv
1027: ================
1028: */
1029: void COM_InitArgv (int argc, char **argv)
1030: {
1031: qboolean safe;
1032: int i;
1033:
1034: safe = false;
1035:
1036: for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;
1037: com_argc++)
1038: {
1039: largv[com_argc] = argv[com_argc];
1040: if (!Q_strcmp ("-safe", argv[com_argc]))
1041: safe = true;
1042: }
1043:
1044: if (safe)
1045: {
1046: // force all the safe-mode switches. Note that we reserved extra space in
1047: // case we need to add these, so we don't need an overflow check
1048: for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
1049: {
1050: largv[com_argc] = safeargvs[i];
1051: com_argc++;
1052: }
1053: }
1054:
1055: largv[com_argc] = argvdummy;
1056: com_argv = largv;
1057: }
1058:
1059:
1060: /*
1061: ================
1062: COM_Init
1063: ================
1064: */
1065: void COM_Init (char *basedir)
1066: {
1067: byte swaptest[2] = {1,0};
1068:
1069: // set the byte swapping variables in a portable manner
1070: if ( *(short *)swaptest == 1)
1071: {
1072: bigendien = false;
1073: BigShort = ShortSwap;
1074: LittleShort = ShortNoSwap;
1075: BigLong = LongSwap;
1076: LittleLong = LongNoSwap;
1077: BigFloat = FloatSwap;
1078: LittleFloat = FloatNoSwap;
1079: }
1080: else
1081: {
1082: bigendien = true;
1083: BigShort = ShortNoSwap;
1084: LittleShort = ShortSwap;
1085: BigLong = LongNoSwap;
1086: LittleLong = LongSwap;
1087: BigFloat = FloatNoSwap;
1088: LittleFloat = FloatSwap;
1089: }
1090:
1091: Cvar_RegisterVariable (®istered);
1092: Cmd_AddCommand ("path", COM_Path_f);
1093:
1094: COM_InitFilesystem ();
1095: COM_CheckRegistered ();
1096: }
1097:
1098:
1099: /*
1100: ============
1101: va
1102:
1103: does a varargs printf into a temp buffer, so I don't need to have
1104: varargs versions of all text functions.
1105: FIXME: make this buffer size safe someday
1106: ============
1107: */
1108: char *va(char *format, ...)
1109: {
1110: va_list argptr;
1111: static char string[1024];
1112:
1113: va_start (argptr, format);
1114: vsprintf (string, format,argptr);
1115: va_end (argptr);
1116:
1117: return string;
1118: }
1119:
1120:
1121: /// just for debugging
1122: int memsearch (byte *start, int count, int search)
1123: {
1124: int i;
1125:
1126: for (i=0 ; i<count ; i++)
1127: if (start[i] == search)
1128: return i;
1129: return -1;
1130: }
1131:
1132: /*
1133: =============================================================================
1134:
1135: QUAKE FILESYSTEM
1136:
1137: =============================================================================
1138: */
1139:
1140: int com_filesize;
1141:
1142:
1143: //
1144: // in memory
1145: //
1146:
1147: typedef struct
1148: {
1149: char name[MAX_QPATH];
1150: int filepos, filelen;
1151: } packfile_t;
1152:
1153: typedef struct pack_s
1154: {
1155: char filename[MAX_OSPATH];
1156: int handle;
1157: int numfiles;
1158: packfile_t *files;
1159: } pack_t;
1160:
1161: //
1162: // on disk
1163: //
1164: typedef struct
1165: {
1166: char name[56];
1167: int filepos, filelen;
1168: } dpackfile_t;
1169:
1170: typedef struct
1171: {
1172: char id[4];
1173: int dirofs;
1174: int dirlen;
1175: } dpackheader_t;
1176:
1177: #define MAX_FILES_IN_PACK 2048
1178:
1179: char com_cachedir[MAX_OSPATH];
1180: char com_gamedir[MAX_OSPATH];
1181:
1182: typedef struct searchpath_s
1183: {
1184: char filename[MAX_OSPATH];
1185: pack_t *pack; // only one of filename / pack will be used
1186: struct searchpath_s *next;
1187: } searchpath_t;
1188:
1189: searchpath_t *com_searchpaths;
1190:
1191: /*
1192: ============
1193: COM_Path_f
1194:
1195: ============
1196: */
1197: void COM_Path_f (void)
1198: {
1199: searchpath_t *s;
1200:
1201: Con_Printf ("Current search path:\n");
1202: for (s=com_searchpaths ; s ; s=s->next)
1203: {
1204: if (s->pack)
1205: {
1206: Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
1207: }
1208: else
1209: Con_Printf ("%s\n", s->filename);
1210: }
1211: }
1212:
1213: /*
1214: ============
1215: COM_WriteFile
1216:
1217: The filename will be prefixed by the current game directory
1218: ============
1219: */
1220: void COM_WriteFile (char *filename, void *data, int len)
1221: {
1222: int handle;
1223: char name[MAX_OSPATH];
1224:
1225: sprintf (name, "%s/%s", com_gamedir, filename);
1226:
1227: handle = Sys_FileOpenWrite (name);
1228: if (handle == -1)
1229: {
1230: Sys_Printf ("COM_WriteFile: failed on %s\n", name);
1231: return;
1232: }
1233:
1234: Sys_Printf ("COM_WriteFile: %s\n", name);
1235: Sys_FileWrite (handle, data, len);
1236: Sys_FileClose (handle);
1237: }
1238:
1239:
1240: /*
1241: ============
1242: COM_CreatePath
1243:
1244: Only used for CopyFile
1245: ============
1246: */
1247: void COM_CreatePath (char *path)
1248: {
1249: char *ofs;
1250:
1251: for (ofs = path+1 ; *ofs ; ofs++)
1252: {
1253: if (*ofs == '/')
1254: { // create the directory
1255: *ofs = 0;
1256: Sys_mkdir (path);
1257: *ofs = '/';
1258: }
1259: }
1260: }
1261:
1262:
1263: /*
1264: ===========
1265: COM_CopyFile
1266:
1267: Copies a file over from the net to the local cache, creating any directories
1268: needed. This is for the convenience of developers using ISDN from home.
1269: ===========
1270: */
1271: void COM_CopyFile (char *netpath, char *cachepath)
1272: {
1273: int in, out;
1274: int remaining, count;
1275: char buf[4096];
1276:
1277: remaining = Sys_FileOpenRead (netpath, &in);
1278: COM_CreatePath (cachepath); // create directories up to the cache file
1279: out = Sys_FileOpenWrite (cachepath);
1280:
1281: while (remaining)
1282: {
1283: if (remaining < sizeof(buf))
1284: count = remaining;
1285: else
1286: count = sizeof(buf);
1287: Sys_FileRead (in, buf, count);
1288: Sys_FileWrite (out, buf, count);
1289: remaining -= count;
1290: }
1291:
1292: Sys_FileClose (in);
1293: Sys_FileClose (out);
1294: }
1295:
1296: /*
1297: ===========
1298: COM_FindFile
1299:
1300: Finds the file in the search path.
1301: Sets com_filesize and one of handle or file
1302: ===========
1303: */
1304: int COM_FindFile (char *filename, int *handle, FILE **file)
1305: {
1306: searchpath_t *search;
1307: char netpath[MAX_OSPATH];
1308: char cachepath[MAX_OSPATH];
1309: pack_t *pak;
1310: int i;
1311: int findtime, cachetime;
1312:
1313: if (file && handle)
1314: Sys_Error ("COM_FindFile: both handle and file set");
1315: if (!file && !handle)
1316: Sys_Error ("COM_FindFile: neither handle or file set");
1317:
1318: //
1319: // search through the path, one element at a time
1320: //
1321: for (search = com_searchpaths ; search ; search = search->next)
1322: {
1323: // is the element a pak file?
1324: if (search->pack)
1325: {
1326: // look through all the pak file elements
1327: pak = search->pack;
1328: for (i=0 ; i<pak->numfiles ; i++)
1329: if (!strcmp (pak->files[i].name, filename))
1330: { // found it!
1331: Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename);
1332: if (handle)
1333: {
1334: *handle = pak->handle;
1335: Sys_FileSeek (pak->handle, pak->files[i].filepos);
1336: }
1337: else
1338: { // open a new file on the pakfile
1339: *file = fopen (pak->filename, "rb");
1340: if (*file)
1341: fseek (*file, pak->files[i].filepos, SEEK_SET);
1342: }
1343: com_filesize = pak->files[i].filelen;
1344: return com_filesize;
1345: }
1346: }
1347: else
1348: {
1349: // check a file in the directory tree
1350: if (!static_registered)
1351: { // if not a registered version, don't ever go beyond base
1352: if ( strchr (filename, '/') || strchr (filename,'\\'))
1353: continue;
1354: }
1355:
1356: sprintf (netpath, "%s/%s",search->filename, filename);
1357:
1358: findtime = Sys_FileTime (netpath);
1359: if (findtime == -1)
1360: continue;
1361:
1362: // see if the file needs to be updated in the cache
1363: if (!com_cachedir[0])
1364: strcpy (cachepath, netpath);
1365: else
1366: {
1367: //@@@
1368: if ((strlen(netpath) < 2) || (netpath[1] != ':'))
1369: sprintf (cachepath,"%s%s", com_cachedir, netpath);
1370: else
1371: sprintf (cachepath,"%s%s", com_cachedir, netpath+2);
1372:
1373: cachetime = Sys_FileTime (cachepath);
1374:
1375: if (cachetime < findtime)
1376: COM_CopyFile (netpath, cachepath);
1377: strcpy (netpath, cachepath);
1378: }
1379:
1380: Sys_Printf ("FindFile: %s\n",netpath);
1381: com_filesize = Sys_FileOpenRead (netpath, &i);
1382: if (handle)
1383: *handle = i;
1384: else
1385: {
1386: Sys_FileClose (i);
1387: *file = fopen (netpath, "rb");
1388: }
1389: return com_filesize;
1390: }
1391:
1392: }
1393:
1394: Sys_Printf ("FindFile: can't find %s\n", filename);
1395:
1396: if (handle)
1397: *handle = -1;
1398: else
1399: *file = NULL;
1400: com_filesize = -1;
1401: return -1;
1402: }
1403:
1404:
1405: /*
1406: ===========
1407: COM_OpenFile
1408:
1409: filename never has a leading slash, but may contain directory walks
1410: returns a handle and a length
1411: it may actually be inside a pak file
1412: ===========
1413: */
1414: int COM_OpenFile (char *filename, int *handle)
1415: {
1416: return COM_FindFile (filename, handle, NULL);
1417: }
1418:
1419: /*
1420: ===========
1421: COM_FOpenFile
1422:
1423: If the requested file is inside a packfile, a new FILE * will be opened
1424: into the file.
1425: ===========
1426: */
1427: int COM_FOpenFile (char *filename, FILE **file)
1428: {
1429: return COM_FindFile (filename, NULL, file);
1430: }
1431:
1432: /*
1433: ============
1434: COM_CloseFile
1435:
1436: If it is a pak file handle, don't really close it
1437: ============
1438: */
1439: void COM_CloseFile (int h)
1440: {
1441: searchpath_t *s;
1442:
1443: for (s = com_searchpaths ; s ; s=s->next)
1444: if (s->pack && s->pack->handle == h)
1445: return;
1446:
1447: Sys_FileClose (h);
1448: }
1449:
1450:
1451: /*
1452: ============
1453: COM_LoadFile
1454:
1455: Filename are reletive to the quake directory.
1456: Allways appends a 0 byte.
1457: ============
1458: */
1459: cache_user_t *loadcache;
1460: byte *loadbuf;
1461: int loadsize;
1462: byte *COM_LoadFile (char *path, int usehunk)
1463: {
1464: int h;
1465: byte *buf;
1466: char base[32];
1467: int len;
1468:
1469: buf = NULL; // quiet compiler warning
1470:
1471: // look for it in the filesystem or pack files
1472: len = COM_OpenFile (path, &h);
1473: if (h == -1)
1474: return NULL;
1475:
1476: // extract the filename base name for hunk tag
1477: COM_FileBase (path, base);
1478:
1479: if (usehunk == 1)
1480: buf = Hunk_AllocName (len+1, base);
1481: else if (usehunk == 2)
1482: buf = Hunk_TempAlloc (len+1);
1483: else if (usehunk == 0)
1484: buf = Z_Malloc (len+1);
1485: else if (usehunk == 3)
1486: buf = Cache_Alloc (loadcache, len+1, base);
1487: else if (usehunk == 4)
1488: {
1489: if (len+1 > loadsize)
1490: buf = Hunk_TempAlloc (len+1);
1491: else
1492: buf = loadbuf;
1493: }
1494: else
1495: Sys_Error ("COM_LoadFile: bad usehunk");
1496:
1497: if (!buf)
1498: Sys_Error ("COM_LoadFile: not enough space for %s", path);
1499:
1500: ((byte *)buf)[len] = 0;
1501:
1502: Draw_BeginDisc ();
1503: Sys_FileRead (h, buf, len);
1504: COM_CloseFile (h);
1505: Draw_EndDisc ();
1506:
1507: return buf;
1508: }
1509:
1510: byte *COM_LoadHunkFile (char *path)
1511: {
1512: return COM_LoadFile (path, 1);
1513: }
1514:
1515: byte *COM_LoadTempFile (char *path)
1516: {
1517: return COM_LoadFile (path, 2);
1518: }
1519:
1520: void COM_LoadCacheFile (char *path, struct cache_user_s *cu)
1521: {
1522: loadcache = cu;
1523: COM_LoadFile (path, 3);
1524: }
1525:
1526: // uses temp hunk if larger than bufsize
1527: byte *COM_LoadStackFile (char *path, void *buffer, int bufsize)
1528: {
1529: byte *buf;
1530:
1531: loadbuf = (byte *)buffer;
1532: loadsize = bufsize;
1533: buf = COM_LoadFile (path, 4);
1534:
1535: return buf;
1536: }
1537:
1538: /*
1539: =================
1540: COM_LoadPackFile
1541:
1542: Takes an explicit (not game tree related) path to a pak file.
1543:
1544: Loads the header and directory, adding the files at the beginning
1545: of the list so they override previous pack files.
1546: =================
1547: */
1548: pack_t *COM_LoadPackFile (char *packfile)
1549: {
1550: dpackheader_t header;
1551: int i;
1552: packfile_t *newfiles;
1553: int numpackfiles;
1554: pack_t *pack;
1555: int packhandle;
1556: dpackfile_t info[MAX_FILES_IN_PACK];
1557: unsigned short crc;
1558:
1559: if (Sys_FileOpenRead (packfile, &packhandle) == -1)
1560: {
1561: // Con_Printf ("Couldn't open %s\n", packfile);
1562: return NULL;
1563: }
1564: Sys_FileRead (packhandle, (void *)&header, sizeof(header));
1565: if (header.id[0] != 'P' || header.id[1] != 'A'
1566: || header.id[2] != 'C' || header.id[3] != 'K')
1567: Sys_Error ("%s is not a packfile", packfile);
1568: header.dirofs = LittleLong (header.dirofs);
1569: header.dirlen = LittleLong (header.dirlen);
1570:
1571: numpackfiles = header.dirlen / sizeof(dpackfile_t);
1572:
1573: if (numpackfiles > MAX_FILES_IN_PACK)
1574: Sys_Error ("%s has %i files", packfile, numpackfiles);
1575:
1576: if (numpackfiles != PAK0_COUNT)
1577: com_modified = true; // not the original file
1578:
1579: newfiles = Hunk_AllocName (numpackfiles * sizeof(packfile_t), "packfile");
1580:
1581: Sys_FileSeek (packhandle, header.dirofs);
1582: Sys_FileRead (packhandle, (void *)info, header.dirlen);
1583:
1584: // crc the directory to check for modifications
1585: CRC_Init (&crc);
1586: for (i=0 ; i<header.dirlen ; i++)
1587: CRC_ProcessByte (&crc, ((byte *)info)[i]);
1588: if (crc != PAK0_CRC)
1589: com_modified = true;
1590:
1591: // parse the directory
1592: for (i=0 ; i<numpackfiles ; i++)
1593: {
1594: strcpy (newfiles[i].name, info[i].name);
1595: newfiles[i].filepos = LittleLong(info[i].filepos);
1596: newfiles[i].filelen = LittleLong(info[i].filelen);
1597: }
1598:
1599: pack = Hunk_Alloc (sizeof (pack_t));
1600: strcpy (pack->filename, packfile);
1601: pack->handle = packhandle;
1602: pack->numfiles = numpackfiles;
1603: pack->files = newfiles;
1604:
1605: Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
1606: return pack;
1607: }
1608:
1609:
1610: /*
1611: ================
1612: COM_AddGameDirectory
1613:
1614: Sets com_gamedir, adds the directory to the head of the path,
1615: then loads and adds pak1.pak pak2.pak ...
1616: ================
1617: */
1618: void COM_AddGameDirectory (char *dir)
1619: {
1620: int i;
1621: searchpath_t *search;
1622: pack_t *pak;
1623: char pakfile[MAX_OSPATH];
1624:
1625: strcpy (com_gamedir, dir);
1626:
1627: //
1628: // add the directory to the search path
1629: //
1630: search = Hunk_Alloc (sizeof(searchpath_t));
1631: strcpy (search->filename, dir);
1632: search->next = com_searchpaths;
1633: com_searchpaths = search;
1634:
1635: //
1636: // add any pak files in the format pak0.pak pak1.pak, ...
1637: //
1638: for (i=0 ; ; i++)
1639: {
1640: sprintf (pakfile, "%s/pak%i.pak", dir, i);
1641: pak = COM_LoadPackFile (pakfile);
1642: if (!pak)
1643: break;
1644: search = Hunk_Alloc (sizeof(searchpath_t));
1645: search->pack = pak;
1646: search->next = com_searchpaths;
1647: com_searchpaths = search;
1648: }
1649:
1650: //
1651: // add the contents of the parms.txt file to the end of the command line
1652: //
1653:
1654: }
1655:
1656: /*
1657: ================
1658: COM_InitFilesystem
1659: ================
1660: */
1661: void COM_InitFilesystem (void)
1662: {
1663: int i;
1664: char basedir[MAX_OSPATH];
1665: searchpath_t *search;
1666:
1667: //
1668: // -basedir <path>
1669: // Overrides the system supplied base directory (under GAMENAME)
1670: //
1671: i = COM_CheckParm ("-basedir");
1672: if (i && i < com_argc-1)
1673: strcpy (basedir, com_argv[i+1]);
1674: else
1675: strcpy (basedir, host_parms.basedir);
1676:
1677: //
1678: // -cachedir <path>
1679: // Overrides the system supplied cache directory (NULL or /qcache)
1680: // -cachedir - will disable caching.
1681: //
1682: i = COM_CheckParm ("-cachedir");
1683: if (i && i < com_argc-1)
1684: {
1685: if (com_argv[i+1][0] == '-')
1686: com_cachedir[0] = 0;
1687: else
1688: strcpy (com_cachedir, com_argv[i+1]);
1689: }
1690: else if (host_parms.cachedir)
1691: strcpy (com_cachedir, host_parms.cachedir);
1692: else
1693: com_cachedir[0] = 0;
1694:
1695: //
1696: // start up with GAMENAME by default (id1)
1697: //
1698: COM_AddGameDirectory (va("%s/"GAMENAME, basedir) );
1699:
1700: //
1701: // -game <gamedir>
1702: // Adds basedir/gamedir as an override game
1703: //
1704: i = COM_CheckParm ("-game");
1705: if (i && i < com_argc-1)
1706: {
1707: com_modified = true;
1708: COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1]));
1709: }
1710:
1711: //
1712: // -path <dir or packfile> [<dir or packfile>] ...
1713: // Fully specifies the exact serach path, overriding the generated one
1714: //
1715: i = COM_CheckParm ("-path");
1716: if (i)
1717: {
1718: com_modified = true;
1719: com_searchpaths = NULL;
1720: while (++i < com_argc)
1721: {
1722: if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
1723: break;
1724:
1725: search = Hunk_Alloc (sizeof(searchpath_t));
1726: if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
1727: {
1728: search->pack = COM_LoadPackFile (com_argv[i]);
1729: if (!search->pack)
1730: Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
1731: }
1732: else
1733: strcpy (search->filename, com_argv[i]);
1734: search->next = com_searchpaths;
1735: com_searchpaths = search;
1736: }
1737: }
1738: }
1739:
1740:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.