2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // common.c -- misc functions used in client and server
32 #define NUM_SAFE_ARGVS 7
34 static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
35 static char *argvdummy = " ";
37 static char *safeargvs[NUM_SAFE_ARGVS] =
38 {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-window"};
40 cvar_t registered = {0, "registered","0"};
41 cvar_t cmdline = {0, "cmdline","0"};
43 qboolean com_modified; // set true if using non-id files
47 //int static_registered = 1; // only for startup check, then set
49 qboolean msg_suppress_1 = 0;
51 void COM_InitFilesystem (void);
57 // LordHavoc: made commandline 1024 characters instead of 256
58 #define CMDLINE_LENGTH 1024
59 char com_cmdline[CMDLINE_LENGTH];
67 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.
69 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
70 only used during filesystem initialization.
72 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.
74 The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines. If there is a cache directory
75 specified, when a file is found by the normal search path, it will be mirrored
76 into the cache directory, then opened there.
81 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.
85 //============================================================================
89 ============================================================================
91 LIBRARY REPLACEMENT FUNCTIONS
93 ============================================================================
97 void Q_memset (void *dest, int fill, int count)
101 if ( (((long)dest | count) & 3) == 0)
104 fill = fill | (fill<<8) | (fill<<16) | (fill<<24);
105 for (i=0 ; i<count ; i++)
106 ((int *)dest)[i] = fill;
109 for (i=0 ; i<count ; i++)
110 ((byte *)dest)[i] = fill;
113 void Q_memcpy (void *dest, void *src, int count)
117 if (( ( (long)dest | (long)src | count) & 3) == 0 )
120 for (i=0 ; i<count ; i++)
121 ((int *)dest)[i] = ((int *)src)[i];
124 for (i=0 ; i<count ; i++)
125 ((byte *)dest)[i] = ((byte *)src)[i];
128 int Q_memcmp (void *m1, void *m2, int count)
133 if (((byte *)m1)[count] != ((byte *)m2)[count])
139 void Q_strcpy (char *dest, char *src)
148 void Q_strncpy (char *dest, char *src, int count)
150 while (*src && count--)
158 int Q_strlen (char *str)
169 char *Q_strrchr(char *s, char c)
171 int len = Q_strlen(s);
174 if (*--s == c) return s;
178 void Q_strcat (char *dest, char *src)
180 dest += Q_strlen(dest);
181 Q_strcpy (dest, src);
184 int Q_strcmp (char *s1, char *s2)
189 return -1; // strings not equal
191 return 0; // strings are equal
199 int Q_strncmp (char *s1, char *s2, int count)
206 return -1; // strings not equal
208 return 0; // strings are equal
216 int Q_strncasecmp (char *s1, char *s2, int n)
226 return 0; // strings are equal until end point
230 if (c1 >= 'a' && c1 <= 'z')
232 if (c2 >= 'a' && c2 <= 'z')
235 return -1; // strings not equal
238 return 0; // strings are equal
246 int Q_strcasecmp (char *s1, char *s2)
248 return Q_strncasecmp (s1, s2, 99999);
251 int Q_atoi (char *str)
270 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
276 if (c >= '0' && c <= '9')
277 val = (val<<4) + c - '0';
278 else if (c >= 'a' && c <= 'f')
279 val = (val<<4) + c - 'a' + 10;
280 else if (c >= 'A' && c <= 'F')
281 val = (val<<4) + c - 'A' + 10;
288 // check for character
292 return sign * str[1];
301 if (c <'0' || c > '9')
303 val = val*10 + c - '0';
310 float Q_atof (char *str)
330 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
336 if (c >= '0' && c <= '9')
337 val = (val*16) + c - '0';
338 else if (c >= 'a' && c <= 'f')
339 val = (val*16) + c - 'a' + 10;
340 else if (c >= 'A' && c <= 'F')
341 val = (val*16) + c - 'A' + 10;
348 // check for character
352 return sign * str[1];
368 if (c <'0' || c > '9')
370 val = val*10 + c - '0';
376 while (total > decimal)
387 ============================================================================
391 ============================================================================
394 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
395 short (*BigShort) (short l);
396 short (*LittleShort) (short l);
397 int (*BigLong) (int l);
398 int (*LittleLong) (int l);
399 float (*BigFloat) (float l);
400 float (*LittleFloat) (float l);
403 short ShortSwap (short l)
413 short ShortNoSwap (short l)
427 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
430 int LongNoSwap (int l)
435 float FloatSwap (float f)
445 dat2.b[0] = dat1.b[3];
446 dat2.b[1] = dat1.b[2];
447 dat2.b[2] = dat1.b[1];
448 dat2.b[3] = dat1.b[0];
452 float FloatNoSwap (float f)
458 ==============================================================================
462 Handles byte ordering and avoids alignment errors
463 ==============================================================================
470 void MSG_WriteChar (sizebuf_t *sb, int c)
475 // if (c < -128 || c > 127)
476 // Sys_Error ("MSG_WriteChar: range error");
479 buf = SZ_GetSpace (sb, 1);
483 void MSG_WriteByte (sizebuf_t *sb, int c)
488 // if (c < 0 || c > 255)
489 // Sys_Error ("MSG_WriteByte: range error");
492 buf = SZ_GetSpace (sb, 1);
496 void MSG_WriteShort (sizebuf_t *sb, int c)
501 // if (c < ((short)0x8000) || c > (short)0x7fff)
502 // Sys_Error ("MSG_WriteShort: range error");
505 buf = SZ_GetSpace (sb, 2);
510 void MSG_WriteLong (sizebuf_t *sb, int c)
514 buf = SZ_GetSpace (sb, 4);
516 buf[1] = (c>>8)&0xff;
517 buf[2] = (c>>16)&0xff;
521 void MSG_WriteFloat (sizebuf_t *sb, float f)
531 dat.l = LittleLong (dat.l);
533 SZ_Write (sb, &dat.l, 4);
536 void MSG_WriteString (sizebuf_t *sb, char *s)
539 SZ_Write (sb, "", 1);
541 SZ_Write (sb, s, strlen(s)+1);
544 // used by server (always dpprotocol)
545 // moved to common.h as #define
547 void MSG_WriteFloatCoord (sizebuf_t *sb, float f)
549 MSG_WriteFloat(sb, f);
554 void MSG_WriteCoord (sizebuf_t *sb, float f)
557 MSG_WriteFloat(sb, f);
559 MSG_WriteShort (sb, (int)(f*8.0f + 0.5f));
562 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
564 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
567 // LordHavoc: round to nearest value, rather than rounding down, fixes crosshair problem
568 void MSG_WriteAngle (sizebuf_t *sb, float f)
570 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
577 qboolean msg_badread;
579 void MSG_BeginReading (void)
586 // returns -1 and sets msg_badread if no more characters are available
587 int MSG_ReadChar (void)
591 // LordHavoc: minor optimization
592 if (msg_readcount >= net_message.cursize)
593 // if (msg_readcount+1 > net_message.cursize)
599 c = (signed char)net_message.data[msg_readcount];
605 int MSG_ReadByte (void)
609 // LordHavoc: minor optimization
610 if (msg_readcount >= net_message.cursize)
611 // if (msg_readcount+1 > net_message.cursize)
617 c = (unsigned char)net_message.data[msg_readcount];
624 int MSG_ReadShort (void)
628 if (msg_readcount+2 > net_message.cursize)
634 c = (short)(net_message.data[msg_readcount]
635 + (net_message.data[msg_readcount+1]<<8));
642 int MSG_ReadLong (void)
646 if (msg_readcount+4 > net_message.cursize)
652 c = net_message.data[msg_readcount]
653 + (net_message.data[msg_readcount+1]<<8)
654 + (net_message.data[msg_readcount+2]<<16)
655 + (net_message.data[msg_readcount+3]<<24);
662 float MSG_ReadFloat (void)
671 dat.b[0] = net_message.data[msg_readcount];
672 dat.b[1] = net_message.data[msg_readcount+1];
673 dat.b[2] = net_message.data[msg_readcount+2];
674 dat.b[3] = net_message.data[msg_readcount+3];
677 dat.l = LittleLong (dat.l);
682 char *MSG_ReadString (void)
684 static char string[2048];
691 if (c == -1 || c == 0)
695 } while (l < sizeof(string)-1);
702 // used by server (always dpprotocol)
703 // moved to common.h as #define
705 float MSG_ReadFloatCoord (void)
707 return MSG_ReadFloat();
712 float MSG_ReadCoord (void)
715 return MSG_ReadFloat();
717 return MSG_ReadShort() * (1.0f/8.0f);
721 float MSG_ReadCoord (void)
723 return MSG_ReadShort() * (1.0f/8.0f);
726 float MSG_ReadAngle (void)
728 return MSG_ReadChar() * (360.0f/256.0f);
731 float MSG_ReadPreciseAngle (void)
733 return MSG_ReadShort() * (360.0f/65536);
738 //===========================================================================
740 void SZ_Alloc (sizebuf_t *buf, int startsize)
744 buf->data = Hunk_AllocName (startsize, "sizebuf");
745 buf->maxsize = startsize;
750 void SZ_Free (sizebuf_t *buf)
752 // Z_Free (buf->data);
758 void SZ_Clear (sizebuf_t *buf)
763 void *SZ_GetSpace (sizebuf_t *buf, int length)
767 if (buf->cursize + length > buf->maxsize)
769 if (!buf->allowoverflow)
770 Host_Error ("SZ_GetSpace: overflow without allowoverflow set - use -zone on the commandline for more zone memory, default: 128k (quake original default was 48k)");
772 if (length > buf->maxsize)
773 Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
775 buf->overflowed = true;
776 Con_Printf ("SZ_GetSpace: overflow");
780 data = buf->data + buf->cursize;
781 buf->cursize += length;
786 void SZ_Write (sizebuf_t *buf, void *data, int length)
788 memcpy (SZ_GetSpace(buf,length),data,length);
791 void SZ_Print (sizebuf_t *buf, char *data)
795 len = strlen(data)+1;
797 // byte * cast to keep VC++ happy
798 if (buf->data[buf->cursize-1])
799 memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
801 memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
805 //============================================================================
813 char *COM_SkipPath (char *pathname)
832 // LordHavoc: replacement for severely broken COM_StripExtension that was used in original quake.
833 void COM_StripExtension (char *in, char *out)
840 if ((*in == '/') || (*in == '\\') || (*in == ':'))
853 char *COM_FileExtension (char *in)
855 static char exten[8];
858 while (*in && *in != '.')
863 for (i=0 ; i<7 && *in ; i++,in++)
874 void COM_FileBase (char *in, char *out)
893 strcpy (out,"?model?");
908 void COM_DefaultExtension (char *path, char *extension)
912 // if path doesn't have a .EXT, append extension
913 // (extension should include the .)
915 src = path + strlen(path) - 1;
917 while (*src != '/' && src != path)
920 return; // it has an extension
924 strcat (path, extension);
932 Parse a token out of a string
935 char *COM_Parse (char *data)
948 while ( (c = *data) <= ' ')
951 return NULL; // end of file;
956 if (c=='/' && data[1] == '/')
958 while (*data && *data != '\n')
964 // handle quoted strings specially
981 // parse single characters
982 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
990 // parse a regular word
997 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
1010 Returns the position (1 to argc-1) in the program's argument list
1011 where the given parameter apears, or 0 if not present
1014 int COM_CheckParm (char *parm)
1018 for (i=1 ; i<com_argc ; i++)
1021 continue; // NEXTSTEP sometimes clears appkit vars.
1022 if (!strcmp (parm,com_argv[i]))
1033 Looks for the pop.txt file and verifies it.
1034 Sets the "registered" cvar.
1035 Immediately exits out if an alternate game was attempted to be started without
1039 void COM_CheckRegistered (void)
1041 Cvar_Set ("cmdline", com_cmdline);
1043 // static_registered = 0;
1045 if (!Sys_FileTime("gfx/pop.lmp"))
1048 Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
1050 Con_Printf ("Playing shareware version.\n");
1052 // Sys_Error ("This dedicated server requires a full registered copy of Quake");
1054 // Con_Printf ("Playing shareware version.\n");
1055 // if (com_modified)
1056 // Sys_Error ("You must have the registered version to use modified games");
1060 // Cvar_Set ("cmdline", com_cmdline);
1061 Cvar_Set ("registered", "1");
1062 // static_registered = 1;
1063 Con_Printf ("Playing registered version.\n");
1067 void COM_Path_f (void);
1075 void COM_InitArgv (int argc, char **argv)
1080 // reconstitute the command line for the cmdline externally visible cvar
1083 for (j=0 ; (j<MAX_NUM_ARGVS) && (j< argc) ; j++)
1087 while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i])
1089 com_cmdline[n++] = argv[j][i++];
1092 if (n < (CMDLINE_LENGTH - 1))
1093 com_cmdline[n++] = ' ';
1102 for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;
1105 largv[com_argc] = argv[com_argc];
1106 if (!strcmp ("-safe", argv[com_argc]))
1112 // force all the safe-mode switches. Note that we reserved extra space in
1113 // case we need to add these, so we don't need an overflow check
1114 for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
1116 largv[com_argc] = safeargvs[i];
1121 largv[com_argc] = argvdummy;
1125 gamemode = GAME_ZYMOTIC;
1127 gamemode = GAME_FIENDARENA;
1129 gamemode = GAME_NEHAHRA;
1131 if (COM_CheckParm ("-zymotic"))
1132 gamemode = GAME_ZYMOTIC;
1133 else if (COM_CheckParm ("-fiendarena"))
1134 gamemode = GAME_FIENDARENA;
1135 else if (COM_CheckParm ("-nehahra"))
1136 gamemode = GAME_NEHAHRA;
1137 else if (COM_CheckParm ("-hipnotic"))
1138 gamemode = GAME_HIPNOTIC;
1139 else if (COM_CheckParm ("-rogue"))
1140 gamemode = GAME_ROGUE;
1145 gamename = "DarkPlaces";
1148 gamename = "Darkplaces-Hipnotic";
1151 gamename = "Darkplaces-Rogue";
1154 gamename = "DarkPlaces-Nehahra";
1156 case GAME_FIENDARENA:
1157 gamename = "FiendArena";
1160 gamename = "Zymotic";
1163 Sys_Error("COM_InitArgv: unknown gamemode %i\n", gamemode);
1169 unsigned int qmalloctotal_alloc, qmalloctotal_alloccount, qmalloctotal_free, qmalloctotal_freecount;
1171 void *qmalloc(unsigned int size)
1174 qmalloctotal_alloc += size;
1175 qmalloctotal_alloccount++;
1176 mem = malloc(size+sizeof(unsigned int));
1180 return (void *)(mem + 1);
1183 void qfree(void *mem)
1189 m--; // back up to size
1190 qmalloctotal_free += *m; // size
1191 qmalloctotal_freecount++;
1195 extern void GL_TextureStats_PrintTotal(void);
1196 extern int hunk_low_used, hunk_high_used, hunk_size;
1197 void COM_Memstats_f(void)
1199 Con_Printf("%i malloc calls totalling %i bytes (%.4gMB)\n%i free calls totalling %i bytes (%.4gMB)\n%i bytes (%.4gMB) currently allocated\n", qmalloctotal_alloccount, qmalloctotal_alloc, qmalloctotal_alloc / 1048576.0, qmalloctotal_freecount, qmalloctotal_free, qmalloctotal_free / 1048576.0, qmalloctotal_alloc - qmalloctotal_free, (qmalloctotal_alloc - qmalloctotal_free) / 1048576.0);
1200 GL_TextureStats_PrintTotal();
1201 Con_Printf ("%i bytes (%.4gMB) of %.4gMB hunk in use\n", hunk_low_used + hunk_high_used, (hunk_low_used + hunk_high_used) / 1048576.0, hunk_size / 1048576.0);
1205 extern void Mathlib_Init(void);
1212 void COM_Init (char *basedir)
1214 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
1215 byte swaptest[2] = {1,0};
1217 // set the byte swapping variables in a portable manner
1218 if ( *(short *)swaptest == 1)
1220 BigShort = ShortSwap;
1221 LittleShort = ShortNoSwap;
1223 LittleLong = LongNoSwap;
1224 BigFloat = FloatSwap;
1225 LittleFloat = FloatNoSwap;
1229 BigShort = ShortNoSwap;
1230 LittleShort = ShortSwap;
1231 BigLong = LongNoSwap;
1232 LittleLong = LongSwap;
1233 BigFloat = FloatNoSwap;
1234 LittleFloat = FloatSwap;
1238 Cvar_RegisterVariable (®istered);
1239 Cvar_RegisterVariable (&cmdline);
1240 Cmd_AddCommand ("path", COM_Path_f);
1241 Cmd_AddCommand ("memstats", COM_Memstats_f);
1245 COM_InitFilesystem ();
1246 COM_CheckRegistered ();
1254 does a varargs printf into a temp buffer, so I don't need to have
1255 varargs versions of all text functions.
1256 FIXME: make this buffer size safe someday
1259 char *va(char *format, ...)
1262 static char string[1024];
1264 va_start (argptr, format);
1265 vsprintf (string, format,argptr);
1272 /// just for debugging
1273 int memsearch (byte *start, int count, int search)
1277 for (i=0 ; i<count ; i++)
1278 if (start[i] == search)
1284 =============================================================================
1288 =============================================================================
1300 char name[MAX_QPATH];
1301 int filepos, filelen;
1304 typedef struct pack_s
1306 char filename[MAX_OSPATH];
1318 int filepos, filelen;
1328 // LordHavoc: was 2048, increased to 16384 and changed info[MAX_PACK_FILES] to a temporary malloc to avoid stack overflows
1329 #define MAX_FILES_IN_PACK 16384
1332 char com_cachedir[MAX_OSPATH];
1334 char com_gamedir[MAX_OSPATH];
1336 typedef struct searchpath_s
1338 char filename[MAX_OSPATH];
1339 pack_t *pack; // only one of filename / pack will be used
1340 struct searchpath_s *next;
1343 searchpath_t *com_searchpaths;
1351 void COM_Path_f (void)
1355 Con_Printf ("Current search path:\n");
1356 for (s=com_searchpaths ; s ; s=s->next)
1360 Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
1363 Con_Printf ("%s\n", s->filename);
1371 LordHavoc: Previously only used for CopyFile, now also used for COM_WriteFile.
1374 void COM_CreatePath (char *path)
1378 for (ofs = path+1 ; *ofs ; ofs++)
1380 if (*ofs == '/' || *ofs == '\\' || *ofs == ':')
1381 { // create the directory
1395 The filename will be prefixed by the current game directory
1398 void COM_WriteFile (char *filename, void *data, int len)
1401 char name[MAX_OSPATH];
1403 sprintf (name, "%s/%s", com_gamedir, filename);
1405 // LordHavoc: added this
1406 COM_CreatePath (name); // create directories up to the file
1408 handle = Sys_FileOpenWrite (name);
1411 Sys_Printf ("COM_WriteFile: failed on %s\n", name);
1415 Con_Printf ("COM_WriteFile: %s\n", name);
1416 Sys_FileWrite (handle, data, len);
1417 Sys_FileClose (handle);
1425 Copies a file over from the net to the local cache, creating any directories
1426 needed. This is for the convenience of developers using ISDN from home.
1429 void COM_CopyFile (char *netpath, char *cachepath)
1432 int remaining, count;
1435 remaining = Sys_FileOpenRead (netpath, &in);
1436 COM_CreatePath (cachepath); // create directories up to the cache file
1437 out = Sys_FileOpenWrite (cachepath);
1441 if (remaining < sizeof(buf))
1444 count = sizeof(buf);
1445 Sys_FileRead (in, buf, count);
1446 Sys_FileWrite (out, buf, count);
1451 Sys_FileClose (out);
1459 QFile * COM_OpenRead (const char *path, int offs, int len, qboolean zip)
1461 int fd = open (path, O_RDONLY);
1462 unsigned char id[2];
1463 unsigned char len_bytes[4];
1467 Sys_Error ("Couldn't open %s", path);
1470 if (offs < 0 || len < 0)
1474 len = lseek (fd, 0, SEEK_END);
1475 lseek (fd, 0, SEEK_SET);
1477 lseek (fd, offs, SEEK_SET);
1481 if (id[0] == 0x1f && id[1] == 0x8b)
1483 lseek (fd, offs + len - 4, SEEK_SET);
1484 read (fd, len_bytes, 4);
1485 len = ((len_bytes[3] << 24)
1486 | (len_bytes[2] << 16)
1487 | (len_bytes[1] << 8)
1491 lseek (fd, offs, SEEK_SET);
1495 setmode (fd, O_BINARY);
1498 return Qdopen (fd, "rbz");
1500 return Qdopen (fd, "rb");
1507 Finds the file in the search path.
1508 Sets com_filesize and one of handle or file
1511 int COM_FindFile (char *filename, QFile **file, qboolean quiet, qboolean zip)
1513 searchpath_t *search;
1514 char netpath[MAX_OSPATH];
1516 char cachepath[MAX_OSPATH];
1522 char gzfilename[MAX_OSPATH];
1525 filenamelen = strlen (filename);
1526 sprintf (gzfilename, "%s.gz", filename);
1529 Sys_Error ("COM_FindFile: file not set");
1532 // search through the path, one element at a time
1534 search = com_searchpaths;
1536 // { // gross hack to use quake 1 progs with quake 2 maps
1537 // if (!strcmp(filename, "progs.dat"))
1538 // search = search->next;
1541 for ( ; search ; search = search->next)
1543 // is the element a pak file?
1546 // look through all the pak file elements
1548 for (i=0 ; i<pak->numfiles ; i++)
1549 if (!strcmp (pak->files[i].name, filename)
1550 || !strcmp (pak->files[i].name, gzfilename))
1553 Sys_Printf ("PackFile: %s : %s\n",pak->filename, pak->files[i].name);
1554 // open a new file on the pakfile
1555 *file = COM_OpenRead (pak->filename, pak->files[i].filepos, pak->files[i].filelen, zip);
1556 return com_filesize;
1561 // check a file in the directory tree
1562 // if (!static_registered)
1563 // { // if not a registered version, don't ever go beyond base
1564 // if ( strchr (filename, '/') || strchr (filename,'\\'))
1568 sprintf (netpath, "%s/%s",search->filename, filename);
1570 findtime = Sys_FileTime (netpath);
1575 // see if the file needs to be updated in the cache
1576 if (com_cachedir[0])
1579 if ((strlen(netpath) < 2) || (netpath[1] != ':'))
1580 sprintf (cachepath,"%s%s", com_cachedir, netpath);
1582 sprintf (cachepath,"%s%s", com_cachedir, netpath+2);
1584 sprintf (cachepath,"%s%s", com_cachedir, netpath);
1587 cachetime = Sys_FileTime (cachepath);
1589 if (cachetime < findtime)
1590 COM_CopyFile (netpath, cachepath);
1591 strcpy (netpath, cachepath);
1596 Sys_Printf ("FindFile: %s\n",netpath);
1597 *file = COM_OpenRead (netpath, -1, -1, zip);
1598 return com_filesize;
1604 Sys_Printf ("FindFile: can't find %s\n", filename);
1616 If the requested file is inside a packfile, a new QFile * will be opened
1620 int COM_FOpenFile (char *filename, QFile **file, qboolean quiet, qboolean zip)
1622 return COM_FindFile (filename, file, quiet, zip);
1630 Filename are reletive to the quake directory.
1631 Always appends a 0 byte.
1634 cache_user_t *loadcache;
1637 byte *COM_LoadFile (char *path, int usehunk, qboolean quiet)
1644 buf = NULL; // quiet compiler warning
1647 // look for it in the filesystem or pack files
1648 len = COM_FOpenFile (path, &h, quiet, true);
1654 // extract the filename base name for hunk tag
1655 COM_FileBase (path, base);
1660 buf = Hunk_AllocName (len+1, va("%s (file)", path));
1662 Sys_Error ("COM_LoadFile: not enough hunk space for %s (size %i)", path, len);
1665 // buf = Z_Malloc (len+1);
1667 // Sys_Error ("COM_LoadFile: not enough zone space for %s (size %i)", path, len);
1670 // buf = Cache_Alloc (loadcache, len+1, base);
1672 // Sys_Error ("COM_LoadFile: not enough cache space for %s (size %i)", path, len);
1675 buf = qmalloc (len+1);
1677 Sys_Error ("COM_LoadFile: not enough available memory for %s (size %i)", path, len);
1680 Sys_Error ("COM_LoadFile: bad usehunk");
1684 ((byte *)buf)[len] = 0;
1686 Qread (h, buf, len);
1692 byte *COM_LoadHunkFile (char *path, qboolean quiet)
1694 return COM_LoadFile (path, 1, quiet);
1697 // LordHavoc: returns malloc'd memory
1698 byte *COM_LoadMallocFile (char *path, qboolean quiet)
1700 return COM_LoadFile (path, 5, quiet);
1704 void COM_LoadCacheFile (char *path, struct cache_user_s *cu, qboolean quiet)
1707 COM_LoadFile (path, 3, quiet);
1715 Takes an explicit (not game tree related) path to a pak file.
1717 Loads the header and directory, adding the files at the beginning
1718 of the list so they override previous pack files.
1721 pack_t *COM_LoadPackFile (char *packfile)
1723 dpackheader_t header;
1725 packfile_t *newfiles;
1729 // LordHavoc: changed from stack array to temporary malloc, allowing huge pack directories
1732 if (Sys_FileOpenRead (packfile, &packhandle) == -1)
1734 // Con_Printf ("Couldn't open %s\n", packfile);
1737 Sys_FileRead (packhandle, (void *)&header, sizeof(header));
1738 if (header.id[0] != 'P' || header.id[1] != 'A'
1739 || header.id[2] != 'C' || header.id[3] != 'K')
1740 Sys_Error ("%s is not a packfile", packfile);
1741 header.dirofs = LittleLong (header.dirofs);
1742 header.dirlen = LittleLong (header.dirlen);
1744 numpackfiles = header.dirlen / sizeof(dpackfile_t);
1746 if (numpackfiles > MAX_FILES_IN_PACK)
1747 Sys_Error ("%s has %i files", packfile, numpackfiles);
1749 newfiles = Hunk_AllocName (numpackfiles * sizeof(packfile_t), "pack file-table");
1751 info = qmalloc(sizeof(*info)*MAX_FILES_IN_PACK);
1752 Sys_FileSeek (packhandle, header.dirofs);
1753 Sys_FileRead (packhandle, (void *)info, header.dirlen);
1755 // parse the directory
1756 for (i=0 ; i<numpackfiles ; i++)
1758 strcpy (newfiles[i].name, info[i].name);
1759 newfiles[i].filepos = LittleLong(info[i].filepos);
1760 newfiles[i].filelen = LittleLong(info[i].filelen);
1764 pack = Hunk_AllocName (sizeof (pack_t), packfile);
1765 strcpy (pack->filename, packfile);
1766 pack->handle = packhandle;
1767 pack->numfiles = numpackfiles;
1768 pack->files = newfiles;
1770 Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
1777 COM_AddGameDirectory
1779 Sets com_gamedir, adds the directory to the head of the path,
1780 then loads and adds pak1.pak pak2.pak ...
1783 void COM_AddGameDirectory (char *dir)
1786 searchpath_t *search;
1788 char pakfile[MAX_OSPATH];
1790 strcpy (com_gamedir, dir);
1793 // add the directory to the search path
1795 search = Hunk_AllocName (sizeof(searchpath_t), "pack info");
1796 strcpy (search->filename, dir);
1797 search->next = com_searchpaths;
1798 com_searchpaths = search;
1801 // add any pak files in the format pak0.pak pak1.pak, ...
1805 sprintf (pakfile, "%s/pak%i.pak", dir, i);
1806 pak = COM_LoadPackFile (pakfile);
1809 search = Hunk_AllocName (sizeof(searchpath_t), "pack info");
1811 search->next = com_searchpaths;
1812 com_searchpaths = search;
1816 // add the contents of the parms.txt file to the end of the command line
1826 void COM_InitFilesystem (void)
1829 char basedir[MAX_OSPATH];
1830 searchpath_t *search;
1834 // Overrides the system supplied base directory (under GAMENAME)
1836 i = COM_CheckParm ("-basedir");
1837 if (i && i < com_argc-1)
1838 strcpy (basedir, com_argv[i+1]);
1840 strcpy (basedir, host_parms.basedir);
1842 j = strlen (basedir);
1846 if ((basedir[j-1] == '\\') || (basedir[j-1] == '/'))
1853 // Overrides the system supplied cache directory (NULL or /qcache)
1854 // -cachedir - will disable caching.
1856 i = COM_CheckParm ("-cachedir");
1857 if (i && i < com_argc-1)
1859 if (com_argv[i+1][0] == '-')
1860 com_cachedir[0] = 0;
1862 strcpy (com_cachedir, com_argv[i+1]);
1864 else if (host_parms.cachedir)
1865 strcpy (com_cachedir, host_parms.cachedir);
1867 com_cachedir[0] = 0;
1870 // start up with GAMENAME by default (id1)
1871 COM_AddGameDirectory (va("%s/"GAMENAME, basedir) );
1878 COM_AddGameDirectory (va("%s/hipnotic", basedir) );
1881 COM_AddGameDirectory (va("%s/rogue", basedir) );
1884 COM_AddGameDirectory (va("%s/nehahra", basedir) );
1886 case GAME_FIENDARENA:
1887 COM_AddGameDirectory (va("%s/fiendarena", basedir) );
1890 COM_AddGameDirectory (va("%s/zymotic", basedir) );
1893 Sys_Error("COM_InitFilesystem: unknown gamemode %i\n", gamemode);
1899 // Adds basedir/gamedir as an override game
1901 i = COM_CheckParm ("-game");
1902 if (i && i < com_argc-1)
1904 com_modified = true;
1905 COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1]));
1909 // -path <dir or packfile> [<dir or packfile>] ...
1910 // Fully specifies the exact search path, overriding the generated one
1912 i = COM_CheckParm ("-path");
1915 com_modified = true;
1916 com_searchpaths = NULL;
1917 while (++i < com_argc)
1919 if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
1922 search = Hunk_AllocName (sizeof(searchpath_t), "pack info");
1923 if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
1925 search->pack = COM_LoadPackFile (com_argv[i]);
1927 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
1930 strcpy (search->filename, com_argv[i]);
1931 search->next = com_searchpaths;
1932 com_searchpaths = search;
1936 // if (COM_CheckParm ("-proghack"))
1940 int COM_FileExists(char *filename)
1942 searchpath_t *search;
1943 char netpath[MAX_OSPATH];
1948 for (search = com_searchpaths;search;search = search->next)
1953 for (i = 0;i < pak->numfiles;i++)
1954 if (!strcmp (pak->files[i].name, filename))
1959 sprintf (netpath, "%s/%s",search->filename, filename);
1960 findtime = Sys_FileTime (netpath);
1970 //======================================
1971 // LordHavoc: added these because they are useful
1973 void COM_ToLowerString(char *in, char *out)
1977 if (*in >= 'A' && *in <= 'Z')
1978 *out++ = *in++ + 'a' - 'A';
1984 void COM_ToUpperString(char *in, char *out)
1988 if (*in >= 'a' && *in <= 'z')
1989 *out++ = *in++ + 'A' - 'a';