~ubuntu-branches/ubuntu/jaunty/openarena/jaunty

« back to all changes in this revision

Viewing changes to code/qcommon/files.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert, Bruno "Fuddl" Kleinert
  • Date: 2008-04-24 14:33:54 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080424143354-0cuxsalv98ajw2js
Tags: 0.7.6-1
[ Bruno "Fuddl" Kleinert ]
* New upstream release
* Freshen 10_fix_build_and_binary_on_alpha.dpatch to apply to latest
  upstream sources
* Remove 10-fix_menudef.h_includes.dpatch which pulled in a missing header
  file. The header is now included in the upstream tarball.
* Remove debian/watch, because upstream places its new releases too often to
  different download locations
* Updated debian/copyright to reflect the download location
* Expand copyright years in debian/copyright

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
be modified at all after startup.  Any files that are created (demos, screenshots,
52
52
etc) will be created reletive to the base path, so base path should usually be writable.
53
53
 
54
 
The "cd path" is the path to an alternate hierarchy that will be searched if a file
55
 
is not located in the base path.  A user can do a partial install that copies some
56
 
data to a base path created on their hard drive and leave the rest on the cd.  Files
57
 
are never writen to the cd path.  It defaults to a value set by the installer, like
58
 
"e:\quake3", but it can be overridden with "+set fs_cdpath g:\quake3".
59
 
 
60
 
If a user runs the game directly from a CD, the base path would be on the CD.  This
61
 
should still function correctly, but all file writes will fail (harmlessly).
62
 
 
63
54
The "home path" is the path used for all write access. On win32 systems we have "base path"
64
55
== "home path", but on *nix systems the base installation is usually readonly, and
65
56
"home path" points to ~/.q3a or similar
93
84
should be exactly the same executables as release versions, but with different data that
94
85
automatically restricts where game media can come from to prevent add-ons from working.
95
86
 
96
 
After the paths are initialized, quake will look for the product.txt file.  If not
97
 
found and verified, the game will run in restricted mode.  In restricted mode, only 
98
 
files contained in demoq3/pak0.pk3 will be available for loading, and only if the zip header is
99
 
verified to not have been modified.  A single exception is made for q3config.cfg.  Files
100
 
can still be written out in restricted mode, so screenshots and demos are allowed.
101
 
Restricted mode can be tested by setting "+set fs_restrict 1" on the command line, even
102
 
if there is a valid product.txt under the basepath or cdpath.
103
 
 
104
 
If not running in restricted mode, and a file is not found in any local filesystem,
105
 
an attempt will be made to download it and save it under the base path.
106
 
 
107
 
If the "fs_copyfiles" cvar is set to 1, then every time a file is sourced from the cd
108
 
path, it will be copied over to the base path.  This is a development aid to help build
109
 
test releases and to copy working sets over slow network links.
110
 
 
111
87
File search order: when FS_FOpenFileRead gets called it will go through the fs_searchpaths
112
88
structure and stop on the first successful hit. fs_searchpaths is built with successive
113
89
calls to FS_AddGameDirectory
258
234
static  char            fs_gamedir[MAX_OSPATH]; // this will be a single file name with no separators
259
235
static  cvar_t          *fs_debug;
260
236
static  cvar_t          *fs_homepath;
 
237
 
 
238
#ifdef MACOS_X
 
239
// Also search the .app bundle for .pk3 files
 
240
static  cvar_t          *fs_apppath;
 
241
#endif
 
242
 
261
243
static  cvar_t          *fs_basepath;
262
244
static  cvar_t          *fs_basegame;
263
 
static  cvar_t          *fs_cdpath;
264
 
static  cvar_t          *fs_copyfiles;
265
245
static  cvar_t          *fs_gamedirvar;
266
 
static  cvar_t          *fs_restrict;
267
246
static  searchpath_t    *fs_searchpaths;
268
247
static  int                     fs_readCount;                   // total bytes read
269
248
static  int                     fs_loadCount;                   // total files read
362
341
{
363
342
        return fs_loadStack;
364
343
}
365
 
                      
 
344
 
366
345
/*
367
346
================
368
347
return a hash value for the filename
676
655
/*
677
656
===========
678
657
FS_SV_FOpenFileRead
679
 
search for a file somewhere below the home path, base path or cd path
680
 
we search in that order, matching FS_SV_FOpenFileRead order
 
658
 
 
659
Search for a file somewhere below the home path then base path
 
660
in that order
681
661
===========
682
662
*/
683
663
int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ) {
696
676
        // don't let sound stutter
697
677
        S_ClearSoundBuffer();
698
678
 
699
 
  // search homepath
 
679
        // search homepath
700
680
        ospath = FS_BuildOSPath( fs_homepath->string, filename, "" );
701
681
        // remove trailing slash
702
682
        ospath[strlen(ospath)-1] = '\0';
707
687
 
708
688
        fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
709
689
        fsh[f].handleSync = qfalse;
710
 
  if (!fsh[f].handleFiles.file.o)
711
 
  {
712
 
    // NOTE TTimo on non *nix systems, fs_homepath == fs_basepath, might want to avoid
713
 
    if (Q_stricmp(fs_homepath->string,fs_basepath->string))
714
 
    {
715
 
      // search basepath
716
 
      ospath = FS_BuildOSPath( fs_basepath->string, filename, "" );
717
 
      ospath[strlen(ospath)-1] = '\0';
718
 
 
719
 
      if ( fs_debug->integer )
720
 
      {
721
 
        Com_Printf( "FS_SV_FOpenFileRead (fs_basepath): %s\n", ospath );
722
 
      }
723
 
 
724
 
      fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
725
 
      fsh[f].handleSync = qfalse;
726
 
 
727
 
      if ( !fsh[f].handleFiles.file.o )
728
 
      {
729
 
        f = 0;
730
 
      }
731
 
    }
732
 
  }
733
 
 
734
 
        if (!fsh[f].handleFiles.file.o) {
735
 
    // search cd path
736
 
    ospath = FS_BuildOSPath( fs_cdpath->string, filename, "" );
737
 
    ospath[strlen(ospath)-1] = '\0';
738
 
 
739
 
    if (fs_debug->integer)
740
 
    {
741
 
      Com_Printf( "FS_SV_FOpenFileRead (fs_cdpath) : %s\n", ospath );
742
 
    }
743
 
 
744
 
          fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
745
 
          fsh[f].handleSync = qfalse;
746
 
 
747
 
          if( !fsh[f].handleFiles.file.o ) {
748
 
            f = 0;
749
 
          }
750
 
  }
751
 
  
 
690
        if (!fsh[f].handleFiles.file.o)
 
691
        {
 
692
                // If fs_homepath == fs_basepath, don't bother
 
693
                if (Q_stricmp(fs_homepath->string,fs_basepath->string))
 
694
                {
 
695
                        // search basepath
 
696
                        ospath = FS_BuildOSPath( fs_basepath->string, filename, "" );
 
697
                        ospath[strlen(ospath)-1] = '\0';
 
698
 
 
699
                        if ( fs_debug->integer )
 
700
                        {
 
701
                                Com_Printf( "FS_SV_FOpenFileRead (fs_basepath): %s\n", ospath );
 
702
                        }
 
703
 
 
704
                        fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
 
705
                        fsh[f].handleSync = qfalse;
 
706
                }
 
707
 
 
708
                if ( !fsh[f].handleFiles.file.o )
 
709
                {
 
710
                        f = 0;
 
711
                }
 
712
        }
 
713
 
752
714
        *fp = f;
753
715
        if (f) {
754
716
                return FS_filelength(f);
836
798
                Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
837
799
        }
838
800
 
839
 
        if (fsh[f].streamed) {
840
 
                Sys_EndStreamedFile(f);
841
 
        }
842
801
        if (fsh[f].zipFile == qtrue) {
843
802
                unzCloseCurrentFile( fsh[f].handleFiles.file.z );
844
803
                if ( fsh[f].handleFiles.unique ) {
974
933
 
975
934
/*
976
935
===========
977
 
FS_ShiftedStrStr
978
 
===========
979
 
*/
980
 
char *FS_ShiftedStrStr(const char *string, const char *substring, int shift) {
981
 
        char buf[MAX_STRING_TOKENS];
982
 
        int i;
983
 
 
984
 
        for (i = 0; substring[i]; i++) {
985
 
                buf[i] = substring[i] + shift;
986
 
        }
987
 
        buf[i] = '\0';
988
 
        return strstr(string, buf);
989
 
}
990
 
 
991
 
/*
992
 
===========
993
936
FS_FOpenFileRead
994
937
 
995
938
Finds the file in the search path.
1123
1066
                                                }
1124
1067
                                        }
1125
1068
 
1126
 
                                        // qagame.qvm   - 13
1127
 
                                        // dTZT`X!di`
1128
 
                                        if (!(pak->referenced & FS_QAGAME_REF) && FS_ShiftedStrStr(filename, "dTZT`X!di`", 13)) {
 
1069
                                        if (!(pak->referenced & FS_QAGAME_REF) && strstr(filename, "qagame.qvm")) {
1129
1070
                                                pak->referenced |= FS_QAGAME_REF;
1130
1071
                                        }
1131
 
                                        // cgame.qvm    - 7
1132
 
                                        // \`Zf^'jof
1133
 
                                        if (!(pak->referenced & FS_CGAME_REF) && FS_ShiftedStrStr(filename , "\\`Zf^'jof", 7)) {
 
1072
                                        if (!(pak->referenced & FS_CGAME_REF) && strstr(filename, "cgame.qvm")) {
1134
1073
                                                pak->referenced |= FS_CGAME_REF;
1135
1074
                                        }
1136
 
                                        // ui.qvm               - 5
1137
 
                                        // pd)lqh
1138
 
                                        if (!(pak->referenced & FS_UI_REF) && FS_ShiftedStrStr(filename , "pd)lqh", 5)) {
 
1075
                                        if (!(pak->referenced & FS_UI_REF) && strstr(filename, "ui.qvm")) {
1139
1076
                                                pak->referenced |= FS_UI_REF;
1140
1077
                                        }
1141
1078
 
1155
1092
                                        temp = zfi->file;
1156
1093
                                        // set the file position in the zip file (also sets the current file info)
1157
1094
                                        unzSetCurrentFileInfoPosition(pak->handle, pakFile->pos);
1158
 
                                        // copy the file info into the unzip structure
1159
 
                                        Com_Memcpy( zfi, pak->handle, sizeof(unz_s) );
 
1095
                                        if ( zfi != pak->handle ) {
 
1096
                                                // copy the file info into the unzip structure
 
1097
                                                Com_Memcpy( zfi, pak->handle, sizeof(unz_s) );
 
1098
                                        }
1160
1099
                                        // we copy this back into the structure
1161
1100
                                        zfi->file = temp;
1162
1101
                                        // open the file in the zip
1177
1116
                        // if we are running restricted, the only files we
1178
1117
                        // will allow to come from the directory are .cfg files
1179
1118
                        l = strlen( filename );
1180
 
      // FIXME TTimo I'm not sure about the fs_numServerPaks test
1181
 
      // if you are using FS_ReadFile to find out if a file exists,
1182
 
      //   this test can make the search fail although the file is in the directory
1183
 
      // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
1184
 
      // turned out I used FS_FileExists instead
1185
 
                        if ( fs_restrict->integer || fs_numServerPaks ) {
 
1119
                        // FIXME TTimo I'm not sure about the fs_numServerPaks test
 
1120
                        // if you are using FS_ReadFile to find out if a file exists,
 
1121
                        //   this test can make the search fail although the file is in the directory
 
1122
                        // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
 
1123
                        // turned out I used FS_FileExists instead
 
1124
                        if ( fs_numServerPaks ) {
1186
1125
 
1187
1126
                                if ( Q_stricmp( filename + l - 4, ".cfg" )              // for config files
1188
1127
                                        && Q_stricmp( filename + l - 5, ".menu" )       // menu files
1208
1147
                                && Q_stricmp( filename + l - 4, ".dat" ) ) {    // for journal files
1209
1148
                                fs_fakeChkSum = random();
1210
1149
                        }
1211
 
      
 
1150
 
1212
1151
                        Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
1213
1152
                        fsh[*file].zipFile = qfalse;
1214
1153
                        if ( fs_debug->integer ) {
1216
1155
                                        dir->path, dir->gamedir );
1217
1156
                        }
1218
1157
 
1219
 
                        // if we are getting it from the cdpath, optionally copy it
1220
 
                        //  to the basepath
1221
 
                        if ( fs_copyfiles->integer && !Q_stricmp( dir->path, fs_cdpath->string ) ) {
1222
 
                                char    *copypath;
1223
 
 
1224
 
                                copypath = FS_BuildOSPath( fs_basepath->string, dir->gamedir, filename );
1225
 
                                FS_CopyFile( netpath, copypath );
1226
 
                        }
1227
 
 
1228
1158
                        return FS_filelength (*file);
1229
1159
                }               
1230
1160
        }
1231
1161
        
1232
 
        Com_DPrintf ("Can't find %s\n", filename);
1233
1162
#ifdef FS_MISSING
1234
1163
        if (missingFiles) {
1235
1164
                fprintf(missingFiles, "%s\n", filename);
1258
1187
        if (fsh[f].streamed) {
1259
1188
                int r;
1260
1189
                fsh[f].streamed = qfalse;
1261
 
                r = Sys_StreamedRead( buffer, len, 1, f);
 
1190
                r = FS_Read( buffer, len, f );
1262
1191
                fsh[f].streamed = qtrue;
1263
1192
                return r;
1264
1193
        } else {
1394
1323
 
1395
1324
        if (fsh[f].streamed) {
1396
1325
                fsh[f].streamed = qfalse;
1397
 
                Sys_StreamSeek( f, offset, origin );
 
1326
                FS_Seek( f, offset, origin );
1398
1327
                fsh[f].streamed = qtrue;
1399
1328
        }
1400
1329
 
1969
1898
                        char    *name;
1970
1899
 
1971
1900
                        // don't scan directories for files if we are pure or restricted
1972
 
                        if ( fs_restrict->integer || fs_numServerPaks ) {
 
1901
                        if ( fs_numServerPaks ) {
1973
1902
                        continue;
1974
1903
                    } else {
1975
1904
                                netpath = FS_BuildOSPath( search->dir->path, search->dir->gamedir, path );
2083
2012
 */
2084
2013
static unsigned int Sys_CountFileList(char **list)
2085
2014
{
2086
 
  int i = 0;
 
2015
        int i = 0;
2087
2016
 
2088
 
  if (list)
2089
 
  {
2090
 
    while (*list)
2091
 
    {
2092
 
      list++;
2093
 
      i++;
2094
 
    }
2095
 
  }
2096
 
  return i;
 
2017
        if (list)
 
2018
        {
 
2019
                while (*list)
 
2020
                {
 
2021
                        list++;
 
2022
                        i++;
 
2023
                }
 
2024
        }
 
2025
        return i;
2097
2026
}
2098
2027
 
2099
 
static char** Sys_ConcatenateFileLists( char **list0, char **list1, char **list2 )
 
2028
static char** Sys_ConcatenateFileLists( char **list0, char **list1 )
2100
2029
{
2101
 
  int totalLength = 0;
2102
 
  char** cat = NULL, **dst, **src;
2103
 
 
2104
 
  totalLength += Sys_CountFileList(list0);
2105
 
  totalLength += Sys_CountFileList(list1);
2106
 
  totalLength += Sys_CountFileList(list2);
2107
 
 
2108
 
  /* Create new list. */
2109
 
  dst = cat = Z_Malloc( ( totalLength + 1 ) * sizeof( char* ) );
2110
 
 
2111
 
  /* Copy over lists. */
2112
 
  if (list0)
2113
 
  {
2114
 
    for (src = list0; *src; src++, dst++)
2115
 
      *dst = *src;
2116
 
  }
2117
 
  if (list1)
2118
 
  {
2119
 
    for (src = list1; *src; src++, dst++)
2120
 
      *dst = *src;
2121
 
  }
2122
 
  if (list2)
2123
 
  {
2124
 
    for (src = list2; *src; src++, dst++)
2125
 
      *dst = *src;
2126
 
  }
2127
 
 
2128
 
  // Terminate the list
2129
 
  *dst = NULL;
2130
 
 
2131
 
  // Free our old lists.
2132
 
  // NOTE: not freeing their content, it's been merged in dst and still being used
2133
 
  if (list0) Z_Free( list0 );
2134
 
  if (list1) Z_Free( list1 );
2135
 
  if (list2) Z_Free( list2 );
2136
 
 
2137
 
  return cat;
 
2030
        int totalLength = 0;
 
2031
        char** cat = NULL, **dst, **src;
 
2032
 
 
2033
        totalLength += Sys_CountFileList(list0);
 
2034
        totalLength += Sys_CountFileList(list1);
 
2035
 
 
2036
        /* Create new list. */
 
2037
        dst = cat = Z_Malloc( ( totalLength + 1 ) * sizeof( char* ) );
 
2038
 
 
2039
        /* Copy over lists. */
 
2040
        if (list0)
 
2041
        {
 
2042
                for (src = list0; *src; src++, dst++)
 
2043
                        *dst = *src;
 
2044
        }
 
2045
        if (list1)
 
2046
        {
 
2047
                for (src = list1; *src; src++, dst++)
 
2048
                        *dst = *src;
 
2049
        }
 
2050
 
 
2051
        // Terminate the list
 
2052
        *dst = NULL;
 
2053
 
 
2054
        // Free our old lists.
 
2055
        // NOTE: not freeing their content, it's been merged in dst and still being used
 
2056
        if (list0) Z_Free( list0 );
 
2057
        if (list1) Z_Free( list1 );
 
2058
 
 
2059
        return cat;
2138
2060
}
2139
2061
 
2140
2062
/*
2147
2069
================
2148
2070
*/
2149
2071
int     FS_GetModList( char *listbuf, int bufsize ) {
2150
 
  int           nMods, i, j, nTotal, nLen, nPaks, nPotential, nDescLen;
2151
 
  char **pFiles = NULL;
2152
 
  char **pPaks = NULL;
2153
 
  char *name, *path;
2154
 
  char descPath[MAX_OSPATH];
2155
 
  fileHandle_t descHandle;
2156
 
 
2157
 
  int dummy;
2158
 
  char **pFiles0 = NULL;
2159
 
  char **pFiles1 = NULL;
2160
 
  char **pFiles2 = NULL;
2161
 
  qboolean bDrop = qfalse;
2162
 
 
2163
 
  *listbuf = 0;
2164
 
  nMods = nPotential = nTotal = 0;
2165
 
 
2166
 
  pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue );
2167
 
  pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue );
2168
 
  pFiles2 = Sys_ListFiles( fs_cdpath->string, NULL, NULL, &dummy, qtrue );
2169
 
  // we searched for mods in the three paths
2170
 
  // it is likely that we have duplicate names now, which we will cleanup below
2171
 
  pFiles = Sys_ConcatenateFileLists( pFiles0, pFiles1, pFiles2 );
2172
 
  nPotential = Sys_CountFileList(pFiles);
2173
 
 
2174
 
  for ( i = 0 ; i < nPotential ; i++ ) {
2175
 
    name = pFiles[i];
2176
 
    // NOTE: cleaner would involve more changes
2177
 
    // ignore duplicate mod directories
2178
 
    if (i!=0) {
2179
 
      bDrop = qfalse;
2180
 
      for(j=0; j<i; j++)
2181
 
      {
2182
 
        if (Q_stricmp(pFiles[j],name)==0) {
2183
 
          // this one can be dropped
2184
 
          bDrop = qtrue;
2185
 
          break;
2186
 
        }
2187
 
      }
2188
 
    }
2189
 
    if (bDrop) {
2190
 
      continue;
2191
 
    }
2192
 
    // we drop "baseq3" "." and ".."
2193
 
    if (Q_stricmp(name, BASEGAME) && Q_stricmpn(name, ".", 1)) {
2194
 
      // now we need to find some .pk3 files to validate the mod
2195
 
      // NOTE TTimo: (actually I'm not sure why .. what if it's a mod under developement with no .pk3?)
2196
 
      // we didn't keep the information when we merged the directory names, as to what OS Path it was found under
2197
 
      //   so it could be in base path, cd path or home path
2198
 
      //   we will try each three of them here (yes, it's a bit messy)
2199
 
      path = FS_BuildOSPath( fs_basepath->string, name, "" );
2200
 
      nPaks = 0;
2201
 
      pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse); 
2202
 
      Sys_FreeFileList( pPaks ); // we only use Sys_ListFiles to check wether .pk3 files are present
2203
 
 
2204
 
      /* Try on cd path */
2205
 
      if( nPaks <= 0 ) {
2206
 
        path = FS_BuildOSPath( fs_cdpath->string, name, "" );
2207
 
        nPaks = 0;
2208
 
        pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
2209
 
        Sys_FreeFileList( pPaks );
2210
 
      }
2211
 
 
2212
 
      /* try on home path */
2213
 
      if ( nPaks <= 0 )
2214
 
      {
2215
 
        path = FS_BuildOSPath( fs_homepath->string, name, "" );
2216
 
        nPaks = 0;
2217
 
        pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
2218
 
        Sys_FreeFileList( pPaks );
2219
 
      }
2220
 
 
2221
 
      if (nPaks > 0) {
2222
 
        nLen = strlen(name) + 1;
2223
 
        // nLen is the length of the mod path
2224
 
        // we need to see if there is a description available
2225
 
        descPath[0] = '\0';
2226
 
        strcpy(descPath, name);
2227
 
        strcat(descPath, "/description.txt");
2228
 
        nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle );
2229
 
        if ( nDescLen > 0 && descHandle) {
2230
 
          FILE *file;
2231
 
          file = FS_FileForHandle(descHandle);
2232
 
          Com_Memset( descPath, 0, sizeof( descPath ) );
2233
 
          nDescLen = fread(descPath, 1, 48, file);
2234
 
          if (nDescLen >= 0) {
2235
 
            descPath[nDescLen] = '\0';
2236
 
          }
2237
 
          FS_FCloseFile(descHandle);
2238
 
        } else {
2239
 
          strcpy(descPath, name);
2240
 
        }
2241
 
        nDescLen = strlen(descPath) + 1;
2242
 
 
2243
 
        if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) {
2244
 
          strcpy(listbuf, name);
2245
 
          listbuf += nLen;
2246
 
          strcpy(listbuf, descPath);
2247
 
          listbuf += nDescLen;
2248
 
          nTotal += nLen + nDescLen;
2249
 
          nMods++;
2250
 
        }
2251
 
        else {
2252
 
          break;
2253
 
        }
2254
 
      }
2255
 
    }
2256
 
  }
2257
 
  Sys_FreeFileList( pFiles );
2258
 
 
2259
 
  return nMods;
 
2072
        int             nMods, i, j, nTotal, nLen, nPaks, nPotential, nDescLen;
 
2073
        char **pFiles = NULL;
 
2074
        char **pPaks = NULL;
 
2075
        char *name, *path;
 
2076
        char descPath[MAX_OSPATH];
 
2077
        fileHandle_t descHandle;
 
2078
 
 
2079
        int dummy;
 
2080
        char **pFiles0 = NULL;
 
2081
        char **pFiles1 = NULL;
 
2082
        qboolean bDrop = qfalse;
 
2083
 
 
2084
        *listbuf = 0;
 
2085
        nMods = nPotential = nTotal = 0;
 
2086
 
 
2087
        pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue );
 
2088
        pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue );
 
2089
        // we searched for mods in the three paths
 
2090
        // it is likely that we have duplicate names now, which we will cleanup below
 
2091
        pFiles = Sys_ConcatenateFileLists( pFiles0, pFiles1 );
 
2092
        nPotential = Sys_CountFileList(pFiles);
 
2093
 
 
2094
        for ( i = 0 ; i < nPotential ; i++ ) {
 
2095
                name = pFiles[i];
 
2096
                // NOTE: cleaner would involve more changes
 
2097
                // ignore duplicate mod directories
 
2098
                if (i!=0) {
 
2099
                        bDrop = qfalse;
 
2100
                        for(j=0; j<i; j++)
 
2101
                        {
 
2102
                                if (Q_stricmp(pFiles[j],name)==0) {
 
2103
                                        // this one can be dropped
 
2104
                                        bDrop = qtrue;
 
2105
                                        break;
 
2106
                                }
 
2107
                        }
 
2108
                }
 
2109
                if (bDrop) {
 
2110
                        continue;
 
2111
                }
 
2112
                // we drop "baseq3" "." and ".."
 
2113
                if (Q_stricmp(name, BASEGAME) && Q_stricmpn(name, ".", 1)) {
 
2114
                        // now we need to find some .pk3 files to validate the mod
 
2115
                        // NOTE TTimo: (actually I'm not sure why .. what if it's a mod under developement with no .pk3?)
 
2116
                        // we didn't keep the information when we merged the directory names, as to what OS Path it was found under
 
2117
                        //   so it could be in base path, cd path or home path
 
2118
                        //   we will try each three of them here (yes, it's a bit messy)
 
2119
                        path = FS_BuildOSPath( fs_basepath->string, name, "" );
 
2120
                        nPaks = 0;
 
2121
                        pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse); 
 
2122
                        Sys_FreeFileList( pPaks ); // we only use Sys_ListFiles to check wether .pk3 files are present
 
2123
 
 
2124
                        /* try on home path */
 
2125
                        if ( nPaks <= 0 )
 
2126
                        {
 
2127
                                path = FS_BuildOSPath( fs_homepath->string, name, "" );
 
2128
                                nPaks = 0;
 
2129
                                pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
 
2130
                                Sys_FreeFileList( pPaks );
 
2131
                        }
 
2132
 
 
2133
                        if (nPaks > 0) {
 
2134
                                nLen = strlen(name) + 1;
 
2135
                                // nLen is the length of the mod path
 
2136
                                // we need to see if there is a description available
 
2137
                                descPath[0] = '\0';
 
2138
                                strcpy(descPath, name);
 
2139
                                strcat(descPath, "/description.txt");
 
2140
                                nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle );
 
2141
                                if ( nDescLen > 0 && descHandle) {
 
2142
                                        FILE *file;
 
2143
                                        file = FS_FileForHandle(descHandle);
 
2144
                                        Com_Memset( descPath, 0, sizeof( descPath ) );
 
2145
                                        nDescLen = fread(descPath, 1, 48, file);
 
2146
                                        if (nDescLen >= 0) {
 
2147
                                                descPath[nDescLen] = '\0';
 
2148
                                        }
 
2149
                                        FS_FCloseFile(descHandle);
 
2150
                                } else {
 
2151
                                        strcpy(descPath, name);
 
2152
                                }
 
2153
                                nDescLen = strlen(descPath) + 1;
 
2154
 
 
2155
                                if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) {
 
2156
                                        strcpy(listbuf, name);
 
2157
                                        listbuf += nLen;
 
2158
                                        strcpy(listbuf, descPath);
 
2159
                                        listbuf += nDescLen;
 
2160
                                        nTotal += nLen + nDescLen;
 
2161
                                        nMods++;
 
2162
                                }
 
2163
                                else {
 
2164
                                        break;
 
2165
                                }
 
2166
                        }
 
2167
                }
 
2168
        }
 
2169
        Sys_FreeFileList( pFiles );
 
2170
 
 
2171
        return nMods;
2260
2172
}
2261
2173
 
2262
2174
 
2323
2235
*/
2324
2236
int FS_PathCmp( const char *s1, const char *s2 ) {
2325
2237
        int             c1, c2;
2326
 
        
 
2238
 
2327
2239
        do {
2328
2240
                c1 = *s1++;
2329
2241
                c2 = *s2++;
2452
2364
/*
2453
2365
============
2454
2366
FS_TouchFile_f
2455
 
 
2456
 
The only purpose of this function is to allow game script files to copy
2457
 
arbitrary files furing an "fs_copyfiles 1" run.
2458
2367
============
2459
2368
*/
2460
2369
void FS_TouchFile_f( void ) {
2491
2400
then loads the zip headers
2492
2401
================
2493
2402
*/
2494
 
static void FS_AddGameDirectory( const char *path, const char *dir ) {
 
2403
void FS_AddGameDirectory( const char *path, const char *dir ) {
2495
2404
        searchpath_t    *sp;
2496
2405
        int                             i;
2497
2406
        searchpath_t    *search;
2500
2409
        int                             numfiles;
2501
2410
        char                    **pakfiles;
2502
2411
 
2503
 
        // this fixes the case where fs_basepath is the same as fs_cdpath
2504
 
        // which happens on full installs
 
2412
        // Unique
2505
2413
        for ( sp = fs_searchpaths ; sp ; sp = sp->next ) {
2506
2414
                if ( sp->dir && !Q_stricmp(sp->dir->path, path) && !Q_stricmp(sp->dir->gamedir, dir)) {
2507
2415
                        return;                 // we've already got this one
2632
2540
 
2633
2541
                // Make sure the server cannot make us write to non-quake3 directories.
2634
2542
                if(FS_CheckDirTraversal(fs_serverReferencedPakNames[i]))
2635
 
                {
 
2543
                {
2636
2544
                        Com_Printf("WARNING: Invalid download name %s\n", fs_serverReferencedPakNames[i]);
2637
 
                        continue;
2638
 
                }
 
2545
                        continue;
 
2546
                }
2639
2547
 
2640
2548
                for ( sp = fs_searchpaths ; sp ; sp = sp->next ) {
2641
2549
                        if ( sp->pack && sp->pack->checksum == fs_serverReferencedPaks[i] ) {
2647
2555
                if ( !havepak && fs_serverReferencedPakNames[i] && *fs_serverReferencedPakNames[i] ) { 
2648
2556
                        // Don't got it
2649
2557
 
2650
 
      if (dlstring)
2651
 
      {
2652
 
        // We need this to make sure we won't hit the end of the buffer or the server could
2653
 
        // overwrite non-pk3 files on clients by writing so much crap into neededpaks that
2654
 
        // Q_strcat cuts off the .pk3 extension.
2655
 
        
2656
 
        origpos += strlen(origpos);
2657
 
        
2658
 
        // Remote name
2659
 
        Q_strcat( neededpaks, len, "@");
2660
 
        Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
2661
 
        Q_strcat( neededpaks, len, ".pk3" );
2662
 
 
2663
 
        // Local name
2664
 
        Q_strcat( neededpaks, len, "@");
2665
 
        // Do we have one with the same name?
2666
 
        if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
2667
 
        {
2668
 
          char st[MAX_ZPATH];
2669
 
          // We already have one called this, we need to download it to another name
2670
 
          // Make something up with the checksum in it
2671
 
          Com_sprintf( st, sizeof( st ), "%s.%08x.pk3", fs_serverReferencedPakNames[i], fs_serverReferencedPaks[i] );
2672
 
          Q_strcat( neededpaks, len, st );
2673
 
        } else
2674
 
        {
2675
 
          Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
2676
 
          Q_strcat( neededpaks, len, ".pk3" );
2677
 
        }
2678
 
        
2679
 
        // Find out whether it might have overflowed the buffer and don't add this file to the
2680
 
        // list if that is the case.
2681
 
        if(strlen(origpos) + (origpos - neededpaks) >= len - 1)
2682
 
        {
2683
 
                *origpos = '\0';
2684
 
                break;
2685
 
        }
2686
 
      }
2687
 
      else
2688
 
      {
2689
 
        Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
2690
 
                          Q_strcat( neededpaks, len, ".pk3" );
2691
 
        // Do we have one with the same name?
2692
 
        if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
2693
 
        {
2694
 
          Q_strcat( neededpaks, len, " (local file exists with wrong checksum)");
2695
 
        }
2696
 
        Q_strcat( neededpaks, len, "\n");
2697
 
      }
 
2558
                        if (dlstring)
 
2559
                        {
 
2560
                                // We need this to make sure we won't hit the end of the buffer or the server could
 
2561
                                // overwrite non-pk3 files on clients by writing so much crap into neededpaks that
 
2562
                                // Q_strcat cuts off the .pk3 extension.
 
2563
 
 
2564
                                origpos += strlen(origpos);
 
2565
 
 
2566
                                // Remote name
 
2567
                                Q_strcat( neededpaks, len, "@");
 
2568
                                Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
 
2569
                                Q_strcat( neededpaks, len, ".pk3" );
 
2570
 
 
2571
                                // Local name
 
2572
                                Q_strcat( neededpaks, len, "@");
 
2573
                                // Do we have one with the same name?
 
2574
                                if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
 
2575
                                {
 
2576
                                        char st[MAX_ZPATH];
 
2577
                                        // We already have one called this, we need to download it to another name
 
2578
                                        // Make something up with the checksum in it
 
2579
                                        Com_sprintf( st, sizeof( st ), "%s.%08x.pk3", fs_serverReferencedPakNames[i], fs_serverReferencedPaks[i] );
 
2580
                                        Q_strcat( neededpaks, len, st );
 
2581
                                }
 
2582
                                else
 
2583
                                {
 
2584
                                        Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
 
2585
                                        Q_strcat( neededpaks, len, ".pk3" );
 
2586
                                }
 
2587
 
 
2588
                                // Find out whether it might have overflowed the buffer and don't add this file to the
 
2589
                                // list if that is the case.
 
2590
                                if(strlen(origpos) + (origpos - neededpaks) >= len - 1)
 
2591
                                {
 
2592
                                        *origpos = '\0';
 
2593
                                        break;
 
2594
                                }
 
2595
                        }
 
2596
                        else
 
2597
                        {
 
2598
                                Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
 
2599
                                Q_strcat( neededpaks, len, ".pk3" );
 
2600
                                // Do we have one with the same name?
 
2601
                                if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
 
2602
                                {
 
2603
                                        Q_strcat( neededpaks, len, " (local file exists with wrong checksum)");
 
2604
                                }
 
2605
                                Q_strcat( neededpaks, len, "\n");
 
2606
                        }
2698
2607
                }
2699
2608
        }
2700
2609
 
2754
2663
 
2755
2664
void Com_AppendCDKey( const char *filename );
2756
2665
void Com_ReadCDKey( const char *filename );
2757
 
 
 
2666
 
2758
2667
/*
2759
2668
================
2760
2669
FS_ReorderPurePaks
2768
2677
        int i;
2769
2678
        searchpath_t **p_insert_index, // for linked list reordering
2770
2679
                **p_previous; // when doing the scan
2771
 
        
 
2680
 
2772
2681
        // only relevant when connected to pure server
2773
2682
        if ( !fs_numServerPaks )
2774
2683
                return;
2775
 
        
 
2684
 
2776
2685
        fs_reordered = qfalse;
2777
 
        
2778
 
        p_insert_index = &fs_searchpaths; // we insert in order at the beginning of the list 
 
2686
 
 
2687
        p_insert_index = &fs_searchpaths; // we insert in order at the beginning of the list
2779
2688
        for ( i = 0 ; i < fs_numServerPaks ; i++ ) {
2780
2689
                p_previous = p_insert_index; // track the pointer-to-current-item
2781
2690
                for (s = *p_insert_index; s; s = s->next) {
2790
2699
                                p_insert_index = &s->next;
2791
2700
                                break; // iterate to next server pack
2792
2701
                        }
2793
 
                        p_previous = &s->next; 
 
2702
                        p_previous = &s->next;
2794
2703
                }
2795
2704
        }
2796
2705
}
2800
2709
FS_Startup
2801
2710
================
2802
2711
*/
2803
 
static void FS_Startup( const char *gameName ) {
2804
 
        const char *homePath;
 
2712
static void FS_Startup( const char *gameName )
 
2713
{
 
2714
        const char *homePath;
2805
2715
        cvar_t  *fs;
2806
2716
 
2807
2717
        Com_Printf( "----- FS_Startup -----\n" );
2808
2718
 
2809
2719
        fs_debug = Cvar_Get( "fs_debug", "0", 0 );
2810
 
        fs_copyfiles = Cvar_Get( "fs_copyfiles", "0", CVAR_INIT );
2811
 
        fs_cdpath = Cvar_Get ("fs_cdpath", Sys_DefaultCDPath(), CVAR_INIT );
2812
2720
        fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT );
2813
2721
        fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT );
2814
 
  homePath = Sys_DefaultHomePath();
2815
 
  if (!homePath || !homePath[0]) {
 
2722
        homePath = Sys_DefaultHomePath();
 
2723
        if (!homePath || !homePath[0]) {
2816
2724
                homePath = fs_basepath->string;
2817
2725
        }
2818
2726
        fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT );
2819
2727
        fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
2820
 
        fs_restrict = Cvar_Get ("fs_restrict", "", CVAR_INIT );
2821
2728
 
2822
2729
        // add search path elements in reverse priority order
2823
 
        if (fs_cdpath->string[0]) {
2824
 
                FS_AddGameDirectory( fs_cdpath->string, gameName );
2825
 
        }
2826
2730
        if (fs_basepath->string[0]) {
2827
2731
                FS_AddGameDirectory( fs_basepath->string, gameName );
2828
2732
        }
2829
 
  // fs_homepath is somewhat particular to *nix systems, only add if relevant
2830
 
  // NOTE: same filtering below for mods and basegame
2831
 
        if (fs_basepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
 
2733
        // fs_homepath is somewhat particular to *nix systems, only add if relevant
 
2734
        
 
2735
        #ifdef MACOS_X
 
2736
        fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT );
 
2737
        // Make MacOSX also include the base path included with the .app bundle
 
2738
        if (fs_apppath->string[0])
 
2739
                FS_AddGameDirectory(fs_apppath->string, gameName);
 
2740
        #endif
 
2741
        
 
2742
        // NOTE: same filtering below for mods and basegame
 
2743
        if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
2832
2744
                FS_AddGameDirectory ( fs_homepath->string, gameName );
2833
2745
        }
2834
 
        
 
2746
 
2835
2747
        // check for additional base game so mods can be based upon other mods
2836
2748
        if ( fs_basegame->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_basegame->string, gameName ) ) {
2837
 
                if (fs_cdpath->string[0]) {
2838
 
                        FS_AddGameDirectory(fs_cdpath->string, fs_basegame->string);
2839
 
                }
2840
2749
                if (fs_basepath->string[0]) {
2841
2750
                        FS_AddGameDirectory(fs_basepath->string, fs_basegame->string);
2842
2751
                }
2847
2756
 
2848
2757
        // check for additional game folder for mods
2849
2758
        if ( fs_gamedirvar->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_gamedirvar->string, gameName ) ) {
2850
 
                if (fs_cdpath->string[0]) {
2851
 
                        FS_AddGameDirectory(fs_cdpath->string, fs_gamedirvar->string);
2852
 
                }
2853
2759
                if (fs_basepath->string[0]) {
2854
2760
                        FS_AddGameDirectory(fs_basepath->string, fs_gamedirvar->string);
2855
2761
                }
2873
2779
        // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=506
2874
2780
        // reorder the pure pk3 files according to server order
2875
2781
        FS_ReorderPurePaks();
2876
 
        
 
2782
 
2877
2783
        // print the current search paths
2878
2784
        FS_Path_f();
2879
2785
 
2900
2806
*/
2901
2807
static void FS_CheckPak0( void )
2902
2808
{
2903
 
/*
2904
 
        searchpath_t    *path;
 
2809
        /*searchpath_t  *path;
2905
2810
        qboolean founddemo = qfalse;
2906
2811
        unsigned foundPak = 0;
2907
2812
 
2908
 
        for( path = fs_searchpaths; path; path = path->next ) {
 
2813
        for( path = fs_searchpaths; path; path = path->next )
 
2814
        {
2909
2815
                const char* pakBasename = path->pack->pakBasename;
2910
2816
 
2911
2817
                if(!path->pack)
2912
2818
                        continue;
2913
2819
 
2914
2820
                if(!Q_stricmpn( path->pack->pakGamename, "demoq3", MAX_OSPATH )
2915
 
                && !Q_stricmpn( pakBasename, "pak0", MAX_OSPATH )) {
 
2821
                   && !Q_stricmpn( pakBasename, "pak0", MAX_OSPATH ))
 
2822
                {
2916
2823
                        founddemo = qtrue;
2917
2824
 
2918
 
                        if( path->pack->checksum == DEMO_PAK0_CHECKSUM ) {
 
2825
                        if( path->pack->checksum == DEMO_PAK0_CHECKSUM )
 
2826
                        {
2919
2827
                                Com_Printf( "\n\n"
2920
2828
                                                "**************************************************\n"
2921
2829
                                                "WARNING: It looks like you're using pak0.pk3\n"
2923
2831
                                                "guaranteed or supported.\n"
2924
2832
                                                "**************************************************\n\n\n" );
2925
2833
                        }
2926
 
                } else if(!Q_stricmpn( path->pack->pakGamename, BASEGAME, MAX_OSPATH )
2927
 
                && strlen(pakBasename) == 4 && !Q_stricmpn( pakBasename, "pak", 3 )
2928
 
                && pakBasename[3] >= '0' && pakBasename[3] <= '8') {
 
2834
                }
2929
2835
 
2930
 
                        if( path->pack->checksum != pak_checksums[pakBasename[3]-'0'] ) {
2931
 
                                if(pakBasename[0] == '0') {
 
2836
                else if(!Q_stricmpn( path->pack->pakGamename, BASEGAME, MAX_OSPATH )
 
2837
                        && strlen(pakBasename) == 4 && !Q_stricmpn( pakBasename, "pak", 3 )
 
2838
                        && pakBasename[3] >= '0' && pakBasename[3] <= '8')
 
2839
                {
 
2840
                        if( path->pack->checksum != pak_checksums[pakBasename[3]-'0'] )
 
2841
                        {
 
2842
                                if(pakBasename[0] == '0')
 
2843
                                {
2932
2844
                                        Com_Printf("\n\n"
2933
2845
                                                "**************************************************\n"
2934
2846
                                                "WARNING: pak0.pk3 is present but its checksum (%u)\n"
2936
2848
                                                "legitimate Q3 CDROM.\n"
2937
2849
                                                "**************************************************\n\n\n",
2938
2850
                                                path->pack->checksum );
2939
 
                                } else {
 
2851
                                }
 
2852
                                else
 
2853
                                {
2940
2854
                                        Com_Printf("\n\n"
2941
2855
                                                "**************************************************\n"
2942
2856
                                                "WARNING: pak%d.pk3 is present but its checksum (%u)\n"
2950
2864
                }
2951
2865
        }
2952
2866
 
2953
 
        if( !founddemo && foundPak != 0x1ff ) {
2954
 
                if((foundPak&1) != 1 ) {
 
2867
        if(!founddemo && (foundPak & 0x1ff) != 0x1ff )
 
2868
        {
 
2869
                if((foundPak&1) != 1 )
 
2870
                {
2955
2871
                        Com_Printf("\n\n"
2956
2872
                        "pak0.pk3 is missing. Please copy it\n"
2957
2873
                        "from your legitimate Q3 CDROM.\n");
2958
2874
                }
2959
2875
 
2960
 
                if((foundPak&0x1fe) != 0x1fe ) {
 
2876
                if((foundPak&0x1fe) != 0x1fe )
 
2877
                {
2961
2878
                        Com_Printf("\n\n"
2962
2879
                        "Point Release files are missing. Please\n"
2963
2880
                        "re-install the 1.32 point release.\n");
2971
2888
                if(!fs_gamedirvar->string[0]
2972
2889
                || !Q_stricmp( fs_gamedirvar->string, BASEGAME )
2973
2890
                || !Q_stricmp( fs_gamedirvar->string, "missionpack" ))
2974
 
                        Com_Error(ERR_FATAL, "\n*** you need to install Quake III Arena in order to play ***");
2975
 
        }
2976
 
*/
 
2891
                        Com_Error(ERR_FATAL, "You need to install Quake III Arena in order to play");
 
2892
        }*/
2977
2893
}
2978
2894
 
2979
2895
/*
3339
3255
        // we have to specially handle this, because normal command
3340
3256
        // line variable sets don't happen until after the filesystem
3341
3257
        // has already been initialized
3342
 
        Com_StartupVariable( "fs_cdpath" );
3343
3258
        Com_StartupVariable( "fs_basepath" );
3344
3259
        Com_StartupVariable( "fs_homepath" );
3345
3260
        Com_StartupVariable( "fs_game" );
3346
 
        Com_StartupVariable( "fs_copyfiles" );
3347
 
        Com_StartupVariable( "fs_restrict" );
3348
3261
 
3349
3262
        // try to start up normally
3350
3263
        FS_Startup( BASEGAME );
3351
3264
 
3352
 
        FS_CheckPak0( );
 
3265
        //FS_CheckPak0( );
3353
3266
 
3354
3267
        // if we can't find default.cfg, assume that the paths are
3355
3268
        // busted and error out now, rather than getting an unreadable
3356
3269
        // graphics screen when the font fails to load
3357
3270
        if ( FS_ReadFile( "default.cfg", NULL ) <= 0 ) {
3358
3271
                Com_Error( ERR_FATAL, "Couldn't load default.cfg" );
3359
 
                // bk001208 - SafeMode see below, FIXME?
3360
3272
        }
3361
3273
 
3362
3274
        Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase));
3363
3275
        Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame));
3364
 
 
3365
 
  // bk001208 - SafeMode see below, FIXME?
3366
3276
}
3367
3277
 
3368
3278
 
3385
3295
        // try to start up normally
3386
3296
        FS_Startup( BASEGAME );
3387
3297
 
3388
 
        // FS_CheckPak0( );
 
3298
        FS_CheckPak0( );
3389
3299
 
3390
3300
        // if we can't find default.cfg, assume that the paths are
3391
3301
        // busted and error out now, rather than getting an unreadable
3399
3309
                        Cvar_Set("fs_gamedirvar", lastValidGame);
3400
3310
                        lastValidBase[0] = '\0';
3401
3311
                        lastValidGame[0] = '\0';
3402
 
                        Cvar_Set( "fs_restrict", "0" );
3403
3312
                        FS_Restart(checksumFeed);
3404
3313
                        Com_Error( ERR_DROP, "Invalid game folder\n" );
3405
3314
                        return;
3407
3316
                Com_Error( ERR_FATAL, "Couldn't load default.cfg" );
3408
3317
        }
3409
3318
 
3410
 
        // bk010116 - new check before safeMode
3411
3319
        if ( Q_stricmp(fs_gamedirvar->string, lastValidGame) ) {
3412
3320
                // skip the q3config.cfg if "safe" is on the command line
3413
3321
                if ( !Com_SafeMode() ) {
3414
 
                        Cbuf_AddText ("exec q3config.cfg\n");
 
3322
                        Cbuf_AddText ("exec " Q3CONFIG_CFG "\n");
3415
3323
                }
3416
3324
        }
3417
3325
 
3487
3395
                fsh[*f].streamed = qfalse;
3488
3396
 
3489
3397
                if (mode == FS_READ) {
3490
 
                        Sys_BeginStreamedFile( *f, 0x4000 );
3491
3398
                        fsh[*f].streamed = qtrue;
3492
3399
                }
3493
3400
        }