]> icculus.org git repositories - divverent/darkplaces.git/blob - common.c
Gigantic commit - dlight system rewritten
[divverent/darkplaces.git] / common.c
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 "quakedef.h"
23
24 #define NUM_SAFE_ARGVS  7
25
26 static char     *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
27 static char     *argvdummy = " ";
28
29 static char     *safeargvs[NUM_SAFE_ARGVS] =
30         {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"};
31
32 cvar_t  registered = {"registered","0"};
33 cvar_t  cmdline = {"cmdline","0", false, true};
34
35 qboolean        com_modified;   // set true if using non-id files
36
37 qboolean                proghack;
38
39 int             static_registered = 1;  // only for startup check, then set
40
41 qboolean                msg_suppress_1 = 0;
42
43 void COM_InitFilesystem (void);
44
45 // if a packfile directory differs from this, it is assumed to be hacked
46 #define PAK0_COUNT              339
47 #define PAK0_CRC                32981
48
49 char    com_token[1024];
50 int             com_argc;
51 char    **com_argv;
52
53 #define CMDLINE_LENGTH  256
54 char    com_cmdline[CMDLINE_LENGTH];
55
56 qboolean                standard_quake = true, rogue = false, hipnotic = false, nehahra = false;
57
58 // this graphic needs to be in the pak file to use registered features
59 unsigned short pop[] =
60 {
61  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
62 ,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000
63 ,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000
64 ,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600
65 ,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563
66 ,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564
67 ,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564
68 ,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563
69 ,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500
70 ,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200
71 ,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000
72 ,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000
73 ,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000
74 ,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000
75 ,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000
76 ,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000
77 };
78
79 /*
80
81
82 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.
83
84 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
85 only used during filesystem initialization.
86
87 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.
88
89 The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines.  If there is a cache directory
90 specified, when a file is found by the normal search path, it will be mirrored
91 into the cache directory, then opened there.
92
93
94
95 FIXME:
96 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.
97         
98 */
99
100 //============================================================================
101
102
103 // ClearLink is used for new headnodes
104 void ClearLink (link_t *l)
105 {
106         l->prev = l->next = l;
107 }
108
109 void RemoveLink (link_t *l)
110 {
111         l->next->prev = l->prev;
112         l->prev->next = l->next;
113 }
114
115 void InsertLinkBefore (link_t *l, link_t *before)
116 {
117         l->next = before;
118         l->prev = before->prev;
119         l->prev->next = l;
120         l->next->prev = l;
121 }
122 void InsertLinkAfter (link_t *l, link_t *after)
123 {
124         l->next = after->next;
125         l->prev = after;
126         l->prev->next = l;
127         l->next->prev = l;
128 }
129
130 /*
131 ============================================================================
132
133                                         LIBRARY REPLACEMENT FUNCTIONS
134
135 ============================================================================
136 */
137
138 /*
139 void Q_memset (void *dest, int fill, int count)
140 {
141         int             i;
142         
143         if ( (((long)dest | count) & 3) == 0)
144         {
145                 count >>= 2;
146                 fill = fill | (fill<<8) | (fill<<16) | (fill<<24);
147                 for (i=0 ; i<count ; i++)
148                         ((int *)dest)[i] = fill;
149         }
150         else
151                 for (i=0 ; i<count ; i++)
152                         ((byte *)dest)[i] = fill;
153 }
154
155 void Q_memcpy (void *dest, void *src, int count)
156 {
157         int             i;
158         
159         if (( ( (long)dest | (long)src | count) & 3) == 0 )
160         {
161                 count>>=2;
162                 for (i=0 ; i<count ; i++)
163                         ((int *)dest)[i] = ((int *)src)[i];
164         }
165         else
166                 for (i=0 ; i<count ; i++)
167                         ((byte *)dest)[i] = ((byte *)src)[i];
168 }
169
170 int Q_memcmp (void *m1, void *m2, int count)
171 {
172         while(count)
173         {
174                 count--;
175                 if (((byte *)m1)[count] != ((byte *)m2)[count])
176                         return -1;
177         }
178         return 0;
179 }
180
181 void Q_strcpy (char *dest, char *src)
182 {
183         while (*src)
184         {
185                 *dest++ = *src++;
186         }
187         *dest++ = 0;
188 }
189
190 void Q_strncpy (char *dest, char *src, int count)
191 {
192         while (*src && count--)
193         {
194                 *dest++ = *src++;
195         }
196         if (count)
197                 *dest++ = 0;
198 }
199
200 int Q_strlen (char *str)
201 {
202         int             count;
203         
204         count = 0;
205         while (str[count])
206                 count++;
207
208         return count;
209 }
210
211 char *Q_strrchr(char *s, char c)
212 {
213     int len = Q_strlen(s);
214     s += len;
215     while (len--)
216         if (*--s == c) return s;
217     return 0;
218 }
219
220 void Q_strcat (char *dest, char *src)
221 {
222         dest += Q_strlen(dest);
223         Q_strcpy (dest, src);
224 }
225
226 int Q_strcmp (char *s1, char *s2)
227 {
228         while (1)
229         {
230                 if (*s1 != *s2)
231                         return -1;              // strings not equal    
232                 if (!*s1)
233                         return 0;               // strings are equal
234                 s1++;
235                 s2++;
236         }
237         
238         return -1;
239 }
240
241 int Q_strncmp (char *s1, char *s2, int count)
242 {
243         while (1)
244         {
245                 if (!count--)
246                         return 0;
247                 if (*s1 != *s2)
248                         return -1;              // strings not equal    
249                 if (!*s1)
250                         return 0;               // strings are equal
251                 s1++;
252                 s2++;
253         }
254         
255         return -1;
256 }
257 */
258 int Q_strncasecmp (char *s1, char *s2, int n)
259 {
260         int             c1, c2;
261         
262         while (1)
263         {
264                 c1 = *s1++;
265                 c2 = *s2++;
266
267                 if (!n--)
268                         return 0;               // strings are equal until end point
269                 
270                 if (c1 != c2)
271                 {
272                         if (c1 >= 'a' && c1 <= 'z')
273                                 c1 -= ('a' - 'A');
274                         if (c2 >= 'a' && c2 <= 'z')
275                                 c2 -= ('a' - 'A');
276                         if (c1 != c2)
277                                 return -1;              // strings not equal
278                 }
279                 if (!c1)
280                         return 0;               // strings are equal
281 //              s1++;
282 //              s2++;
283         }
284         
285         return -1;
286 }
287
288 int Q_strcasecmp (char *s1, char *s2)
289 {
290         return Q_strncasecmp (s1, s2, 99999);
291 }
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
431                                         BYTE ORDER FUNCTIONS
432
433 ============================================================================
434 */
435
436 #ifndef WIN32
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 #endif
444
445 short   ShortSwap (short l)
446 {
447         byte    b1,b2;
448
449         b1 = l&255;
450         b2 = (l>>8)&255;
451
452         return (b1<<8) + b2;
453 }
454
455 short   ShortNoSwap (short l)
456 {
457         return l;
458 }
459
460 int    LongSwap (int l)
461 {
462         byte    b1,b2,b3,b4;
463
464         b1 = l&255;
465         b2 = (l>>8)&255;
466         b3 = (l>>16)&255;
467         b4 = (l>>24)&255;
468
469         return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
470 }
471
472 int     LongNoSwap (int l)
473 {
474         return l;
475 }
476
477 float FloatSwap (float f)
478 {
479         union
480         {
481                 float   f;
482                 byte    b[4];
483         } dat1, dat2;
484         
485         
486         dat1.f = f;
487         dat2.b[0] = dat1.b[3];
488         dat2.b[1] = dat1.b[2];
489         dat2.b[2] = dat1.b[1];
490         dat2.b[3] = dat1.b[0];
491         return dat2.f;
492 }
493
494 float FloatNoSwap (float f)
495 {
496         return f;
497 }
498
499 /*
500 ==============================================================================
501
502                         MESSAGE IO FUNCTIONS
503
504 Handles byte ordering and avoids alignment errors
505 ==============================================================================
506 */
507
508 //
509 // writing functions
510 //
511
512 void MSG_WriteChar (sizebuf_t *sb, int c)
513 {
514         byte    *buf;
515         
516 //#ifdef PARANOID
517 //      if (c < -128 || c > 127)
518 //              Sys_Error ("MSG_WriteChar: range error");
519 //#endif
520
521         buf = SZ_GetSpace (sb, 1);
522         buf[0] = c;
523 }
524
525 void MSG_WriteByte (sizebuf_t *sb, int c)
526 {
527         byte    *buf;
528         
529 //#ifdef PARANOID
530 //      if (c < 0 || c > 255)
531 //              Sys_Error ("MSG_WriteByte: range error");
532 //#endif
533
534         buf = SZ_GetSpace (sb, 1);
535         buf[0] = c;
536 }
537
538 void MSG_WriteShort (sizebuf_t *sb, int c)
539 {
540         byte    *buf;
541         
542 //#ifdef PARANOID
543 //      if (c < ((short)0x8000) || c > (short)0x7fff)
544 //              Sys_Error ("MSG_WriteShort: range error");
545 //#endif
546
547         buf = SZ_GetSpace (sb, 2);
548         buf[0] = c&0xff;
549         buf[1] = c>>8;
550 }
551
552 void MSG_WriteLong (sizebuf_t *sb, int c)
553 {
554         byte    *buf;
555         
556         buf = SZ_GetSpace (sb, 4);
557         buf[0] = c&0xff;
558         buf[1] = (c>>8)&0xff;
559         buf[2] = (c>>16)&0xff;
560         buf[3] = c>>24;
561 }
562
563 void MSG_WriteFloat (sizebuf_t *sb, float f)
564 {
565         union
566         {
567                 float   f;
568                 int     l;
569         } dat;
570         
571         
572         dat.f = f;
573         dat.l = LittleLong (dat.l);
574         
575         SZ_Write (sb, &dat.l, 4);
576 }
577
578 void MSG_WriteString (sizebuf_t *sb, char *s)
579 {
580         if (!s)
581                 SZ_Write (sb, "", 1);
582         else
583                 SZ_Write (sb, s, strlen(s)+1);
584 }
585
586 /*
587 void MSG_WriteCoord (sizebuf_t *sb, float f)
588 {
589         if (dpprotocol)
590         {
591                 byte    *buf;
592                 int c = (int)f;
593                 buf = SZ_GetSpace (sb, 3);
594                 buf[0] =  c        & 0xff;
595                 buf[1] = (c >>  8) & 0xff;
596                 buf[2] = (c >> 16) & 0xff;
597         }
598         else
599                 MSG_WriteShort (sb, (int)(f*8));
600 }
601 */
602
603 void MSG_WriteCoord (sizebuf_t *sb, float f)
604 {
605         if (dpprotocol)
606                 MSG_WriteFloat(sb, f);
607         /*
608         {
609                 int     i = (int) (f * 16.0f), j = 0, k, l;
610                 // 1 sign bit, 5bit exponent, 10bit mantissa with implicit 1
611                 if (i < 0)
612                 {
613                         i = -i;
614                         j = 0x8000;
615                 }
616
617                 // LordHavoc: lets hope the compiler is good, if not it will still perform tolerably
618                 for (k = 31,l = 0x80000000;!(i & l);k--,l >>= 1);
619                 j |= k << 10 | ((i >> (k - 10)) & 0x3FF);
620                 
621                 MSG_WriteShort(sb, j);
622         }
623         */
624         else
625                 MSG_WriteShort (sb, (int)(f*8));
626 }
627
628 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
629 {
630         MSG_WriteShort (sb, (int) (f*65536.0f/360) & 65535);
631 }
632
633 void MSG_WriteAngle (sizebuf_t *sb, float f)
634 {
635         MSG_WriteByte (sb, ((int)f*256/360) & 255);
636 }
637
638 //
639 // reading functions
640 //
641 int                     msg_readcount;
642 qboolean        msg_badread;
643
644 void MSG_BeginReading (void)
645 {
646         msg_readcount = 0;
647         msg_badread = false;
648 }
649
650 /*
651 // returns -1 and sets msg_badread if no more characters are available
652 int MSG_ReadChar (void)
653 {
654         int     c;
655         
656         // LordHavoc: minor optimization
657         if (msg_readcount >= net_message.cursize)
658 //      if (msg_readcount+1 > net_message.cursize)
659         {
660                 msg_badread = true;
661                 return -1;
662         }
663                 
664         c = (signed char)net_message.data[msg_readcount];
665         msg_readcount++;
666         
667         return c;
668 }
669
670 int MSG_ReadByte (void)
671 {
672         int     c;
673         
674         // LordHavoc: minor optimization
675         if (msg_readcount >= net_message.cursize)
676 //      if (msg_readcount+1 > net_message.cursize)
677         {
678                 msg_badread = true;
679                 return -1;
680         }
681                 
682         c = (unsigned char)net_message.data[msg_readcount];
683         msg_readcount++;
684         
685         return c;
686 }
687 */
688
689 int MSG_ReadShort (void)
690 {
691         int     c;
692         
693         if (msg_readcount+2 > net_message.cursize)
694         {
695                 msg_badread = true;
696                 return -1;
697         }
698                 
699         c = (short)(net_message.data[msg_readcount]
700         + (net_message.data[msg_readcount+1]<<8));
701         
702         msg_readcount += 2;
703         
704         return c;
705 }
706
707 int MSG_ReadLong (void)
708 {
709         int     c;
710         
711         if (msg_readcount+4 > net_message.cursize)
712         {
713                 msg_badread = true;
714                 return -1;
715         }
716                 
717         c = net_message.data[msg_readcount]
718         + (net_message.data[msg_readcount+1]<<8)
719         + (net_message.data[msg_readcount+2]<<16)
720         + (net_message.data[msg_readcount+3]<<24);
721         
722         msg_readcount += 4;
723         
724         return c;
725 }
726
727 float MSG_ReadFloat (void)
728 {
729         union
730         {
731                 byte    b[4];
732                 float   f;
733                 int     l;
734         } dat;
735         
736         dat.b[0] =      net_message.data[msg_readcount];
737         dat.b[1] =      net_message.data[msg_readcount+1];
738         dat.b[2] =      net_message.data[msg_readcount+2];
739         dat.b[3] =      net_message.data[msg_readcount+3];
740         msg_readcount += 4;
741         
742         dat.l = LittleLong (dat.l);
743
744         return dat.f;   
745 }
746
747 char *MSG_ReadString (void)
748 {
749         static char     string[2048];
750         int             l,c;
751         
752         l = 0;
753         do
754         {
755                 c = MSG_ReadChar ();
756                 if (c == -1 || c == 0)
757                         break;
758                 string[l] = c;
759                 l++;
760         } while (l < sizeof(string)-1);
761         
762         string[l] = 0;
763         
764         return string;
765 }
766
767 /*
768 float MSG_ReadAbsoluteCoord (void)
769 {
770         if (dpprotocol)
771         {
772                 int     c;
773                 
774                 if (msg_readcount+3 > net_message.cursize)
775                 {
776                         msg_badread = true;
777                         return 0;
778                 }
779                         
780                 c  = net_message.data[msg_readcount  ];
781                 c |= net_message.data[msg_readcount+1] << 8;
782                 c |= net_message.data[msg_readcount+2] << 16;
783                 if (c & 0x800000)
784                         c |= ~0xFFFFFF; // sign extend
785                 
786                 msg_readcount += 3;
787                 
788                 return (float) c * (1.0f / 16.0f);
789         }
790         else
791         {
792                 int     c;
793                 
794                 if (msg_readcount+2 > net_message.cursize)
795                 {
796                         msg_badread = true;
797                         return 0;
798                 }
799                         
800                 c  = (short) (net_message.data[msg_readcount  ] |= net_message.data[msg_readcount+1] << 8);
801                 
802                 msg_readcount += 2;
803                 
804                 return (float) c * (1.0f / 8.0f);
805 //              return MSG_ReadShort() * (1.0f/8.0f);
806         }
807 }
808 */
809
810 float MSG_ReadCoord (void)
811 {
812         if (dpprotocol)
813                 return MSG_ReadFloat();
814         /*
815         {
816                 int     c, i;
817                 
818                 if (msg_readcount+2 > net_message.cursize)
819                 {
820                         msg_badread = true;
821                         return 0;
822                 }
823                         
824                 c  = net_message.data[msg_readcount  ] |= net_message.data[msg_readcount+1] << 8;
825                 
826                 msg_readcount += 2;
827
828                 if (!c)
829                         return 0.0f;
830                 // 1 sign bit, 5bit exponent, 10bit mantissa with implicit 1
831                 i = ((c & 0x03FF) | (0x0400)) << (((c & 0x7C00) >> 10) - 10);
832                 if (c & 0x8000)
833                         i = -i;
834                 return i * (1.0f / 16.0f);
835         }
836         */
837         else
838         {
839                 int     c;
840                 
841                 if (msg_readcount+2 > net_message.cursize)
842                 {
843                         msg_badread = true;
844                         return 0;
845                 }
846                         
847                 c  = (short) (net_message.data[msg_readcount  ] | (net_message.data[msg_readcount+1] << 8));
848                 
849                 msg_readcount += 2;
850                 
851                 return ((float) c * (1.0f / 8.0f));
852 //              return MSG_ReadShort() * (1.0f/8.0f);
853         }
854 }
855
856 /*
857 float MSG_ReadCoord (void)
858 {
859         return MSG_ReadShort() * (1.0f/8.0f);
860 }
861
862 float MSG_ReadAngle (void)
863 {
864         return MSG_ReadChar() * (360.0f/256.0f);
865 }
866 */
867
868 float MSG_ReadPreciseAngle (void)
869 {
870         return MSG_ReadShort() * (360.0f/65536);
871 }
872
873
874 //===========================================================================
875
876 void SZ_Alloc (sizebuf_t *buf, int startsize)
877 {
878         if (startsize < 256)
879                 startsize = 256;
880         buf->data = Hunk_AllocName (startsize, "sizebuf");
881         buf->maxsize = startsize;
882         buf->cursize = 0;
883 }
884
885
886 void SZ_Free (sizebuf_t *buf)
887 {
888 //      Z_Free (buf->data);
889 //      buf->data = NULL;
890 //      buf->maxsize = 0;
891         buf->cursize = 0;
892 }
893
894 void SZ_Clear (sizebuf_t *buf)
895 {
896         buf->cursize = 0;
897 }
898
899 void *SZ_GetSpace (sizebuf_t *buf, int length)
900 {
901         void    *data;
902         
903         if (buf->cursize + length > buf->maxsize)
904         {
905                 if (!buf->allowoverflow)
906                         Host_Error ("SZ_GetSpace: overflow without allowoverflow set - use -zone on the commandline for more zone memory, default: 512k (quake original default was 48k)");
907                 
908                 if (length > buf->maxsize)
909                         Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
910                         
911                 buf->overflowed = true;
912                 Con_Printf ("SZ_GetSpace: overflow");
913                 SZ_Clear (buf); 
914         }
915
916         data = buf->data + buf->cursize;
917         buf->cursize += length;
918         
919         return data;
920 }
921
922 void SZ_Write (sizebuf_t *buf, void *data, int length)
923 {
924         memcpy (SZ_GetSpace(buf,length),data,length);         
925 }
926
927 void SZ_Print (sizebuf_t *buf, char *data)
928 {
929         int             len;
930         
931         len = strlen(data)+1;
932
933 // byte * cast to keep VC++ happy
934         if (buf->data[buf->cursize-1])
935                 memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
936         else
937                 memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
938 }
939
940
941 //============================================================================
942
943
944 /*
945 ============
946 COM_SkipPath
947 ============
948 */
949 char *COM_SkipPath (char *pathname)
950 {
951         char    *last;
952         
953         last = pathname;
954         while (*pathname)
955         {
956                 if (*pathname=='/')
957                         last = pathname+1;
958                 pathname++;
959         }
960         return last;
961 }
962
963 /*
964 ============
965 COM_StripExtension
966 ============
967 */
968 void COM_StripExtension (char *in, char *out)
969 {
970         while (*in && *in != '.')
971                 *out++ = *in++;
972         *out = 0;
973 }
974
975 /*
976 ============
977 COM_FileExtension
978 ============
979 */
980 char *COM_FileExtension (char *in)
981 {
982         static char exten[8];
983         int             i;
984
985         while (*in && *in != '.')
986                 in++;
987         if (!*in)
988                 return "";
989         in++;
990         for (i=0 ; i<7 && *in ; i++,in++)
991                 exten[i] = *in;
992         exten[i] = 0;
993         return exten;
994 }
995
996 /*
997 ============
998 COM_FileBase
999 ============
1000 */
1001 void COM_FileBase (char *in, char *out)
1002 {
1003         char *s, *s2;
1004         
1005         s = in + strlen(in) - 1;
1006         
1007         while (s != in && *s != '.')
1008                 s--;
1009         
1010         for (s2 = s ; *s2 && *s2 != '/' ; s2--)
1011         ;
1012         
1013         if (s-s2 < 2)
1014                 strcpy (out,"?model?");
1015         else
1016         {
1017                 s--;
1018                 strncpy (out,s2+1, s-s2);
1019                 out[s-s2] = 0;
1020         }
1021 }
1022
1023
1024 /*
1025 ==================
1026 COM_DefaultExtension
1027 ==================
1028 */
1029 void COM_DefaultExtension (char *path, char *extension)
1030 {
1031         char    *src;
1032 //
1033 // if path doesn't have a .EXT, append extension
1034 // (extension should include the .)
1035 //
1036         src = path + strlen(path) - 1;
1037
1038         while (*src != '/' && src != path)
1039         {
1040                 if (*src == '.')
1041                         return;                 // it has an extension
1042                 src--;
1043         }
1044
1045         strcat (path, extension);
1046 }
1047
1048
1049 /*
1050 ==============
1051 COM_Parse
1052
1053 Parse a token out of a string
1054 ==============
1055 */
1056 char *COM_Parse (char *data)
1057 {
1058         int             c;
1059         int             len;
1060         
1061         len = 0;
1062         com_token[0] = 0;
1063         
1064         if (!data)
1065                 return NULL;
1066                 
1067 // skip whitespace
1068 skipwhite:
1069         while ( (c = *data) <= ' ')
1070         {
1071                 if (c == 0)
1072                         return NULL;                    // end of file;
1073                 data++;
1074         }
1075         
1076 // skip // comments
1077         if (c=='/' && data[1] == '/')
1078         {
1079                 while (*data && *data != '\n')
1080                         data++;
1081                 goto skipwhite;
1082         }
1083         
1084
1085 // handle quoted strings specially
1086         if (c == '\"')
1087         {
1088                 data++;
1089                 while (1)
1090                 {
1091                         c = *data++;
1092                         if (c=='\"' || !c)
1093                         {
1094                                 com_token[len] = 0;
1095                                 return data;
1096                         }
1097                         com_token[len] = c;
1098                         len++;
1099                 }
1100         }
1101
1102 // parse single characters
1103         if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
1104         {
1105                 com_token[len] = c;
1106                 len++;
1107                 com_token[len] = 0;
1108                 return data+1;
1109         }
1110
1111 // parse a regular word
1112         do
1113         {
1114                 com_token[len] = c;
1115                 data++;
1116                 len++;
1117                 c = *data;
1118         if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
1119                         break;
1120         } while (c>32);
1121         
1122         com_token[len] = 0;
1123         return data;
1124 }
1125
1126
1127 /*
1128 ================
1129 COM_CheckParm
1130
1131 Returns the position (1 to argc-1) in the program's argument list
1132 where the given parameter apears, or 0 if not present
1133 ================
1134 */
1135 int COM_CheckParm (char *parm)
1136 {
1137         int             i;
1138         
1139         for (i=1 ; i<com_argc ; i++)
1140         {
1141                 if (!com_argv[i])
1142                         continue;               // NEXTSTEP sometimes clears appkit vars.
1143                 if (!strcmp (parm,com_argv[i]))
1144                         return i;
1145         }
1146                 
1147         return 0;
1148 }
1149
1150 /*
1151 ================
1152 COM_CheckRegistered
1153
1154 Looks for the pop.txt file and verifies it.
1155 Sets the "registered" cvar.
1156 Immediately exits out if an alternate game was attempted to be started without
1157 being registered.
1158 ================
1159 */
1160 void COM_CheckRegistered (void)
1161 {
1162         int             h;
1163         unsigned short  check[128];
1164         int                     i;
1165
1166         Cvar_Set ("cmdline", com_cmdline);
1167
1168         COM_OpenFile("gfx/pop.lmp", &h, false);
1169         static_registered = 0;
1170
1171         if (h == -1)
1172         {
1173                 if (com_modified)
1174                         Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
1175                 else
1176                         Con_Printf ("Playing shareware version.\n");
1177 //#if WINDED
1178 //      Sys_Error ("This dedicated server requires a full registered copy of Quake");
1179 //#endif
1180 //              Con_Printf ("Playing shareware version.\n");
1181 //              if (com_modified)
1182 //                      Sys_Error ("You must have the registered version to use modified games");
1183                 return;
1184         }
1185
1186         Sys_FileRead (h, check, sizeof(check));
1187         COM_CloseFile (h);
1188         
1189         for (i=0 ; i<128 ; i++)
1190                 if (pop[i] != (unsigned short)BigShort (check[i]))
1191                         Sys_Error ("Corrupted data file.");
1192         
1193 //      Cvar_Set ("cmdline", com_cmdline);
1194         Cvar_Set ("registered", "1");
1195         static_registered = 1;
1196         Con_Printf ("Playing registered version.\n");
1197 }
1198
1199
1200 void COM_Path_f (void);
1201
1202
1203 /*
1204 ================
1205 COM_InitArgv
1206 ================
1207 */
1208 void COM_InitArgv (int argc, char **argv)
1209 {
1210         qboolean        safe;
1211         int             i, j, n;
1212
1213 // reconstitute the command line for the cmdline externally visible cvar
1214         n = 0;
1215
1216         for (j=0 ; (j<MAX_NUM_ARGVS) && (j< argc) ; j++)
1217         {
1218                 i = 0;
1219
1220                 while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i])
1221                 {
1222                         com_cmdline[n++] = argv[j][i++];
1223                 }
1224
1225                 if (n < (CMDLINE_LENGTH - 1))
1226                         com_cmdline[n++] = ' ';
1227                 else
1228                         break;
1229         }
1230
1231         com_cmdline[n] = 0;
1232
1233         safe = false;
1234
1235         for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;
1236                  com_argc++)
1237         {
1238                 largv[com_argc] = argv[com_argc];
1239                 if (!strcmp ("-safe", argv[com_argc]))
1240                         safe = true;
1241         }
1242
1243         if (safe)
1244         {
1245         // force all the safe-mode switches. Note that we reserved extra space in
1246         // case we need to add these, so we don't need an overflow check
1247                 for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
1248                 {
1249                         largv[com_argc] = safeargvs[i];
1250                         com_argc++;
1251                 }
1252         }
1253
1254         largv[com_argc] = argvdummy;
1255         com_argv = largv;
1256
1257 #ifdef NEHAHRA
1258         nehahra = true;
1259         standard_quake = false;
1260 #else
1261         if (COM_CheckParm ("-rogue"))
1262         {
1263                 rogue = true;
1264                 standard_quake = false;
1265         }
1266
1267         if (COM_CheckParm ("-hipnotic"))
1268         {
1269                 hipnotic = true;
1270                 standard_quake = false;
1271         }
1272
1273         if (COM_CheckParm ("-nehahra"))
1274         {
1275                 nehahra = true;
1276                 standard_quake = false;
1277         }
1278 #endif
1279 }
1280
1281
1282 /*
1283 ================
1284 COM_Init
1285 ================
1286 */
1287 void COM_Init (char *basedir)
1288 {
1289 #ifndef WIN32
1290         byte    swaptest[2] = {1,0};
1291
1292 // set the byte swapping variables in a portable manner 
1293         if ( *(short *)swaptest == 1)
1294         {
1295                 BigShort = ShortSwap;
1296                 LittleShort = ShortNoSwap;
1297                 BigLong = LongSwap;
1298                 LittleLong = LongNoSwap;
1299                 BigFloat = FloatSwap;
1300                 LittleFloat = FloatNoSwap;
1301         }
1302         else
1303         {
1304                 BigShort = ShortNoSwap;
1305                 LittleShort = ShortSwap;
1306                 BigLong = LongNoSwap;
1307                 LittleLong = LongSwap;
1308                 BigFloat = FloatNoSwap;
1309                 LittleFloat = FloatSwap;
1310         }
1311 #endif
1312
1313         Cvar_RegisterVariable (&registered);
1314         Cvar_RegisterVariable (&cmdline);
1315         Cmd_AddCommand ("path", COM_Path_f);
1316
1317         COM_InitFilesystem ();
1318         COM_CheckRegistered ();
1319 }
1320
1321
1322 /*
1323 ============
1324 va
1325
1326 does a varargs printf into a temp buffer, so I don't need to have
1327 varargs versions of all text functions.
1328 FIXME: make this buffer size safe someday
1329 ============
1330 */
1331 char    *va(char *format, ...)
1332 {
1333         va_list         argptr;
1334         static char             string[1024];
1335         
1336         va_start (argptr, format);
1337         vsprintf (string, format,argptr);
1338         va_end (argptr);
1339
1340         return string;  
1341 }
1342
1343
1344 /// just for debugging
1345 int     memsearch (byte *start, int count, int search)
1346 {
1347         int             i;
1348         
1349         for (i=0 ; i<count ; i++)
1350                 if (start[i] == search)
1351                         return i;
1352         return -1;
1353 }
1354
1355 /*
1356 =============================================================================
1357
1358 QUAKE FILESYSTEM
1359
1360 =============================================================================
1361 */
1362
1363 int     com_filesize;
1364
1365
1366 //
1367 // in memory
1368 //
1369
1370 typedef struct
1371 {
1372         char    name[MAX_QPATH];
1373         int             filepos, filelen;
1374 } packfile_t;
1375
1376 typedef struct pack_s
1377 {
1378         char    filename[MAX_OSPATH];
1379         int             handle;
1380         int             numfiles;
1381         packfile_t      *files;
1382 } pack_t;
1383
1384 //
1385 // on disk
1386 //
1387 typedef struct
1388 {
1389         char    name[56];
1390         int             filepos, filelen;
1391 } dpackfile_t;
1392
1393 typedef struct
1394 {
1395         char    id[4];
1396         int             dirofs;
1397         int             dirlen;
1398 } dpackheader_t;
1399
1400 // LordHavoc: was 2048, increased to 16384 and changed info[MAX_PACK_FILES] to a temporary malloc to avoid stack overflows
1401 #define MAX_FILES_IN_PACK       16384
1402
1403 char    com_cachedir[MAX_OSPATH];
1404 char    com_gamedir[MAX_OSPATH];
1405
1406 typedef struct searchpath_s
1407 {
1408         char    filename[MAX_OSPATH];
1409         pack_t  *pack;          // only one of filename / pack will be used
1410         struct searchpath_s *next;
1411 } searchpath_t;
1412
1413 searchpath_t    *com_searchpaths;
1414
1415 /*
1416 ============
1417 COM_Path_f
1418
1419 ============
1420 */
1421 void COM_Path_f (void)
1422 {
1423         searchpath_t    *s;
1424         
1425         Con_Printf ("Current search path:\n");
1426         for (s=com_searchpaths ; s ; s=s->next)
1427         {
1428                 if (s->pack)
1429                 {
1430                         Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
1431                 }
1432                 else
1433                         Con_Printf ("%s\n", s->filename);
1434         }
1435 }
1436
1437 /*
1438 ============
1439 COM_WriteFile
1440
1441 The filename will be prefixed by the current game directory
1442 ============
1443 */
1444 void COM_WriteFile (char *filename, void *data, int len)
1445 {
1446         int             handle;
1447         char    name[MAX_OSPATH];
1448         
1449         sprintf (name, "%s/%s", com_gamedir, filename);
1450
1451         handle = Sys_FileOpenWrite (name);
1452         if (handle == -1)
1453         {
1454                 Sys_Printf ("COM_WriteFile: failed on %s\n", name);
1455                 return;
1456         }
1457         
1458         Sys_Printf ("COM_WriteFile: %s\n", name);
1459         Sys_FileWrite (handle, data, len);
1460         Sys_FileClose (handle);
1461 }
1462
1463
1464 /*
1465 ============
1466 COM_CreatePath
1467
1468 Only used for CopyFile
1469 ============
1470 */
1471 void    COM_CreatePath (char *path)
1472 {
1473         char    *ofs;
1474         
1475         for (ofs = path+1 ; *ofs ; ofs++)
1476         {
1477                 if (*ofs == '/')
1478                 {       // create the directory
1479                         *ofs = 0;
1480                         Sys_mkdir (path);
1481                         *ofs = '/';
1482                 }
1483         }
1484 }
1485
1486
1487 /*
1488 ===========
1489 COM_CopyFile
1490
1491 Copies a file over from the net to the local cache, creating any directories
1492 needed.  This is for the convenience of developers using ISDN from home.
1493 ===========
1494 */
1495 void COM_CopyFile (char *netpath, char *cachepath)
1496 {
1497         int             in, out;
1498         int             remaining, count;
1499         char    buf[4096];
1500         
1501         remaining = Sys_FileOpenRead (netpath, &in);            
1502         COM_CreatePath (cachepath);     // create directories up to the cache file
1503         out = Sys_FileOpenWrite (cachepath);
1504         
1505         while (remaining)
1506         {
1507                 if (remaining < sizeof(buf))
1508                         count = remaining;
1509                 else
1510                         count = sizeof(buf);
1511                 Sys_FileRead (in, buf, count);
1512                 Sys_FileWrite (out, buf, count);
1513                 remaining -= count;
1514         }
1515
1516         Sys_FileClose (in);
1517         Sys_FileClose (out);    
1518 }
1519
1520 /*
1521 ===========
1522 COM_FindFile
1523
1524 Finds the file in the search path.
1525 Sets com_filesize and one of handle or file
1526 ===========
1527 */
1528 int COM_FindFile (char *filename, int *handle, FILE **file, qboolean quiet)
1529 {
1530         searchpath_t    *search;
1531         char            netpath[MAX_OSPATH];
1532         char            cachepath[MAX_OSPATH];
1533         pack_t          *pak;
1534         int                     i;
1535         int                     findtime, cachetime;
1536
1537         if (file && handle)
1538                 Sys_Error ("COM_FindFile: both handle and file set");
1539         if (!file && !handle)
1540                 Sys_Error ("COM_FindFile: neither handle or file set");
1541                 
1542 //
1543 // search through the path, one element at a time
1544 //
1545         search = com_searchpaths;
1546         if (proghack)
1547         {       // gross hack to use quake 1 progs with quake 2 maps
1548                 if (!strcmp(filename, "progs.dat"))
1549                         search = search->next;
1550         }
1551
1552         for ( ; search ; search = search->next)
1553         {
1554         // is the element a pak file?
1555                 if (search->pack)
1556                 {
1557                 // look through all the pak file elements
1558                         pak = search->pack;
1559                         for (i=0 ; i<pak->numfiles ; i++)
1560                                 if (!strcmp (pak->files[i].name, filename))
1561                                 {       // found it!
1562                                         if (!quiet)
1563                                                 Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename);
1564                                         if (handle)
1565                                         {
1566                                                 *handle = pak->handle;
1567                                                 Sys_FileSeek (pak->handle, pak->files[i].filepos);
1568                                         }
1569                                         else
1570                                         {       // open a new file on the pakfile
1571                                                 *file = fopen (pak->filename, "rb");
1572                                                 if (*file)
1573                                                         fseek (*file, pak->files[i].filepos, SEEK_SET);
1574                                         }
1575                                         com_filesize = pak->files[i].filelen;
1576                                         return com_filesize;
1577                                 }
1578                 }
1579                 else
1580                 {               
1581         // check a file in the directory tree
1582 //                      if (!static_registered)
1583 //                      {       // if not a registered version, don't ever go beyond base
1584 //                              if ( strchr (filename, '/') || strchr (filename,'\\'))
1585 //                                      continue;
1586 //                      }
1587                         
1588                         sprintf (netpath, "%s/%s",search->filename, filename);
1589                         
1590                         findtime = Sys_FileTime (netpath);
1591                         if (findtime == -1)
1592                                 continue;
1593                                 
1594                 // see if the file needs to be updated in the cache
1595                         if (!com_cachedir[0])
1596                                 strcpy (cachepath, netpath);
1597                         else
1598                         {       
1599 #if defined(_WIN32)
1600                                 if ((strlen(netpath) < 2) || (netpath[1] != ':'))
1601                                         sprintf (cachepath,"%s%s", com_cachedir, netpath);
1602                                 else
1603                                         sprintf (cachepath,"%s%s", com_cachedir, netpath+2);
1604 #else
1605                                 sprintf (cachepath,"%s%s", com_cachedir, netpath);
1606 #endif
1607
1608                                 cachetime = Sys_FileTime (cachepath);
1609                         
1610                                 if (cachetime < findtime)
1611                                         COM_CopyFile (netpath, cachepath);
1612                                 strcpy (netpath, cachepath);
1613                         }       
1614
1615                         if (!quiet)
1616                                 Sys_Printf ("FindFile: %s\n",netpath);
1617                         com_filesize = Sys_FileOpenRead (netpath, &i);
1618                         if (handle)
1619                                 *handle = i;
1620                         else
1621                         {
1622                                 Sys_FileClose (i);
1623                                 *file = fopen (netpath, "rb");
1624                         }
1625                         return com_filesize;
1626                 }
1627                 
1628         }
1629         
1630         if (!quiet)
1631                 Sys_Printf ("FindFile: can't find %s\n", filename);
1632         
1633         if (handle)
1634                 *handle = -1;
1635         else
1636                 *file = NULL;
1637         com_filesize = -1;
1638         return -1;
1639 }
1640
1641
1642 /*
1643 ===========
1644 COM_OpenFile
1645
1646 filename never has a leading slash, but may contain directory walks
1647 returns a handle and a length
1648 it may actually be inside a pak file
1649 ===========
1650 */
1651 int COM_OpenFile (char *filename, int *handle, qboolean quiet)
1652 {
1653         return COM_FindFile (filename, handle, NULL, quiet);
1654 }
1655
1656 /*
1657 ===========
1658 COM_FOpenFile
1659
1660 If the requested file is inside a packfile, a new FILE * will be opened
1661 into the file.
1662 ===========
1663 */
1664 int COM_FOpenFile (char *filename, FILE **file, qboolean quiet)
1665 {
1666         return COM_FindFile (filename, NULL, file, quiet);
1667 }
1668
1669 /*
1670 ============
1671 COM_CloseFile
1672
1673 If it is a pak file handle, don't really close it
1674 ============
1675 */
1676 void COM_CloseFile (int h)
1677 {
1678         searchpath_t    *s;
1679         
1680         for (s = com_searchpaths ; s ; s=s->next)
1681                 if (s->pack && s->pack->handle == h)
1682                         return;
1683                         
1684         Sys_FileClose (h);
1685 }
1686
1687
1688 /*
1689 ============
1690 COM_LoadFile
1691
1692 Filename are reletive to the quake directory.
1693 Allways appends a 0 byte.
1694 ============
1695 */
1696 cache_user_t *loadcache;
1697 byte    *loadbuf;
1698 int             loadsize;
1699 byte *COM_LoadFile (char *path, int usehunk, qboolean quiet)
1700 {
1701         int             h;
1702         byte    *buf;
1703         char    base[32];
1704         int             len;
1705
1706         buf = NULL;     // quiet compiler warning
1707
1708 // look for it in the filesystem or pack files
1709         len = COM_OpenFile (path, &h, quiet);
1710         if (h == -1)
1711                 return NULL;
1712         
1713 // extract the filename base name for hunk tag
1714         COM_FileBase (path, base);
1715         
1716         if (usehunk == 1)
1717                 buf = Hunk_AllocName (len+1, base);
1718         else if (usehunk == 2)
1719                 buf = Hunk_TempAlloc (len+1);
1720         else if (usehunk == 0)
1721                 buf = Z_Malloc (len+1);
1722         else if (usehunk == 3)
1723                 buf = Cache_Alloc (loadcache, len+1, base);
1724         else if (usehunk == 4)
1725         {
1726                 if (len+1 > loadsize)
1727                         buf = Hunk_TempAlloc (len+1);
1728                 else
1729                         buf = loadbuf;
1730         }
1731         else if (usehunk == 5)
1732                 buf = malloc (len+1);
1733         else
1734                 Sys_Error ("COM_LoadFile: bad usehunk");
1735
1736         if (!buf)
1737                 Sys_Error ("COM_LoadFile: not enough space for %s", path);
1738                 
1739         ((byte *)buf)[len] = 0;
1740
1741         Sys_FileRead (h, buf, len);                     
1742         COM_CloseFile (h);
1743
1744         return buf;
1745 }
1746
1747 byte *COM_LoadHunkFile (char *path, qboolean quiet)
1748 {
1749         return COM_LoadFile (path, 1, quiet);
1750 }
1751
1752 byte *COM_LoadTempFile (char *path, qboolean quiet)
1753 {
1754         return COM_LoadFile (path, 2, quiet);
1755 }
1756
1757 // LordHavoc: returns malloc'd memory
1758 byte *COM_LoadMallocFile (char *path, qboolean quiet)
1759 {
1760         return COM_LoadFile (path, 5, quiet);
1761 }
1762
1763 void COM_LoadCacheFile (char *path, struct cache_user_s *cu, qboolean quiet)
1764 {
1765         loadcache = cu;
1766         COM_LoadFile (path, 3, quiet);
1767 }
1768
1769 // uses temp hunk if larger than bufsize
1770 byte *COM_LoadStackFile (char *path, void *buffer, int bufsize, qboolean quiet)
1771 {
1772         byte    *buf;
1773         
1774         loadbuf = (byte *)buffer;
1775         loadsize = bufsize;
1776         buf = COM_LoadFile (path, 4, quiet);
1777         
1778         return buf;
1779 }
1780
1781 /*
1782 =================
1783 COM_LoadPackFile
1784
1785 Takes an explicit (not game tree related) path to a pak file.
1786
1787 Loads the header and directory, adding the files at the beginning
1788 of the list so they override previous pack files.
1789 =================
1790 */
1791 pack_t *COM_LoadPackFile (char *packfile)
1792 {
1793         dpackheader_t   header;
1794         int                             i;
1795         packfile_t              *newfiles;
1796         int                             numpackfiles;
1797         pack_t                  *pack;
1798         int                             packhandle;
1799         // LordHavoc: changed from stack array to temporary malloc, allowing huge pack directories
1800         dpackfile_t             *info;
1801         unsigned short          crc;
1802
1803         if (Sys_FileOpenRead (packfile, &packhandle) == -1)
1804         {
1805 //              Con_Printf ("Couldn't open %s\n", packfile);
1806                 return NULL;
1807         }
1808         Sys_FileRead (packhandle, (void *)&header, sizeof(header));
1809         if (header.id[0] != 'P' || header.id[1] != 'A'
1810         || header.id[2] != 'C' || header.id[3] != 'K')
1811                 Sys_Error ("%s is not a packfile", packfile);
1812         header.dirofs = LittleLong (header.dirofs);
1813         header.dirlen = LittleLong (header.dirlen);
1814
1815         numpackfiles = header.dirlen / sizeof(dpackfile_t);
1816
1817         if (numpackfiles > MAX_FILES_IN_PACK)
1818                 Sys_Error ("%s has %i files", packfile, numpackfiles);
1819
1820         if (numpackfiles != PAK0_COUNT)
1821                 com_modified = true;    // not the original file
1822
1823         newfiles = Hunk_AllocName (numpackfiles * sizeof(packfile_t), "packfile");
1824
1825         info = malloc(sizeof(*info)*MAX_FILES_IN_PACK);
1826         Sys_FileSeek (packhandle, header.dirofs);
1827         Sys_FileRead (packhandle, (void *)info, header.dirlen);
1828
1829 // crc the directory to check for modifications
1830         CRC_Init (&crc);
1831         // LordHavoc: speedup
1832         CRC_ProcessBytes(&crc, (byte *)info, header.dirlen);
1833 //      for (i=0 ; i<header.dirlen ; i++)
1834 //              CRC_ProcessByte (&crc, ((byte *)info)[i]);
1835         if (crc != PAK0_CRC)
1836                 com_modified = true;
1837
1838 // parse the directory
1839         for (i=0 ; i<numpackfiles ; i++)
1840         {
1841                 strcpy (newfiles[i].name, info[i].name);
1842                 newfiles[i].filepos = LittleLong(info[i].filepos);
1843                 newfiles[i].filelen = LittleLong(info[i].filelen);
1844         }
1845         free(info);
1846
1847         pack = Hunk_Alloc (sizeof (pack_t));
1848         strcpy (pack->filename, packfile);
1849         pack->handle = packhandle;
1850         pack->numfiles = numpackfiles;
1851         pack->files = newfiles;
1852         
1853         Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
1854         return pack;
1855 }
1856
1857
1858 /*
1859 ================
1860 COM_AddGameDirectory
1861
1862 Sets com_gamedir, adds the directory to the head of the path,
1863 then loads and adds pak1.pak pak2.pak ... 
1864 ================
1865 */
1866 void COM_AddGameDirectory (char *dir)
1867 {
1868         int                             i;
1869         searchpath_t    *search;
1870         pack_t                  *pak;
1871         char                    pakfile[MAX_OSPATH];
1872
1873         strcpy (com_gamedir, dir);
1874
1875 //
1876 // add the directory to the search path
1877 //
1878         search = Hunk_Alloc (sizeof(searchpath_t));
1879         strcpy (search->filename, dir);
1880         search->next = com_searchpaths;
1881         com_searchpaths = search;
1882
1883 //
1884 // add any pak files in the format pak0.pak pak1.pak, ...
1885 //
1886         for (i=0 ; ; i++)
1887         {
1888                 sprintf (pakfile, "%s/pak%i.pak", dir, i);
1889                 pak = COM_LoadPackFile (pakfile);
1890                 if (!pak)
1891                         break;
1892                 search = Hunk_Alloc (sizeof(searchpath_t));
1893                 search->pack = pak;
1894                 search->next = com_searchpaths;
1895                 com_searchpaths = search;               
1896         }
1897
1898 //
1899 // add the contents of the parms.txt file to the end of the command line
1900 //
1901
1902 }
1903
1904 /*
1905 ================
1906 COM_InitFilesystem
1907 ================
1908 */
1909 void COM_InitFilesystem (void)
1910 {
1911         int             i, j;
1912         char    basedir[MAX_OSPATH];
1913         searchpath_t    *search;
1914
1915 //
1916 // -basedir <path>
1917 // Overrides the system supplied base directory (under GAMENAME)
1918 //
1919         i = COM_CheckParm ("-basedir");
1920         if (i && i < com_argc-1)
1921                 strcpy (basedir, com_argv[i+1]);
1922         else
1923                 strcpy (basedir, host_parms.basedir);
1924
1925         j = strlen (basedir);
1926
1927         if (j > 0)
1928         {
1929                 if ((basedir[j-1] == '\\') || (basedir[j-1] == '/'))
1930                         basedir[j-1] = 0;
1931         }
1932
1933 //
1934 // -cachedir <path>
1935 // Overrides the system supplied cache directory (NULL or /qcache)
1936 // -cachedir - will disable caching.
1937 //
1938         i = COM_CheckParm ("-cachedir");
1939         if (i && i < com_argc-1)
1940         {
1941                 if (com_argv[i+1][0] == '-')
1942                         com_cachedir[0] = 0;
1943                 else
1944                         strcpy (com_cachedir, com_argv[i+1]);
1945         }
1946         else if (host_parms.cachedir)
1947                 strcpy (com_cachedir, host_parms.cachedir);
1948         else
1949                 com_cachedir[0] = 0;
1950
1951 //
1952 // start up with GAMENAME by default (id1)
1953 //
1954         COM_AddGameDirectory (va("%s/"GAMENAME, basedir) );
1955
1956 #ifdef NEHAHRA
1957         COM_AddGameDirectory (va("%s/nehahra", basedir) );
1958 #else
1959         if (COM_CheckParm ("-rogue"))
1960                 COM_AddGameDirectory (va("%s/rogue", basedir) );
1961         if (COM_CheckParm ("-hipnotic"))
1962                 COM_AddGameDirectory (va("%s/hipnotic", basedir) );
1963         if (COM_CheckParm ("-nehahra"))
1964                 COM_AddGameDirectory (va("%s/nehahra", basedir) );
1965 #endif
1966
1967 //
1968 // -game <gamedir>
1969 // Adds basedir/gamedir as an override game
1970 //
1971         i = COM_CheckParm ("-game");
1972         if (i && i < com_argc-1)
1973         {
1974                 com_modified = true;
1975                 COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1]));
1976         }
1977
1978 //
1979 // -path <dir or packfile> [<dir or packfile>] ...
1980 // Fully specifies the exact serach path, overriding the generated one
1981 //
1982         i = COM_CheckParm ("-path");
1983         if (i)
1984         {
1985                 com_modified = true;
1986                 com_searchpaths = NULL;
1987                 while (++i < com_argc)
1988                 {
1989                         if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
1990                                 break;
1991                         
1992                         search = Hunk_Alloc (sizeof(searchpath_t));
1993                         if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
1994                         {
1995                                 search->pack = COM_LoadPackFile (com_argv[i]);
1996                                 if (!search->pack)
1997                                         Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
1998                         }
1999                         else
2000                                 strcpy (search->filename, com_argv[i]);
2001                         search->next = com_searchpaths;
2002                         com_searchpaths = search;
2003                 }
2004         }
2005
2006         if (COM_CheckParm ("-proghack"))
2007                 proghack = true;
2008 }
2009
2010 int COM_FileExists(char *filename)
2011 {
2012         searchpath_t    *search;
2013         char                    netpath[MAX_OSPATH];
2014         pack_t                  *pak;
2015         int                             i;
2016         int                             findtime;
2017
2018         for (search = com_searchpaths;search;search = search->next)
2019         {
2020                 if (search->pack)
2021                 {
2022                         pak = search->pack;
2023                         for (i = 0;i < pak->numfiles;i++)
2024                                 if (!strcmp (pak->files[i].name, filename))
2025                                         return true;
2026                 }
2027                 else
2028                 {
2029                         sprintf (netpath, "%s/%s",search->filename, filename);               
2030                         findtime = Sys_FileTime (netpath);
2031                         if (findtime != -1)
2032                                 return true;
2033                 }               
2034         }
2035
2036         return false;
2037 }
2038