4 #if defined (_WIN32) && !defined (__CYGWIN__)
10 #endif //tells VCC not to generate min/max macros
20 #include <sys/types.h>
29 #include "common/common.h"
63 int offset = (
SERVER ? 2 : 1);
64 size_t maxserial=(1<<(
sizeof(ObjSerial)*8));
66 static bool firstBadness=
true;
68 fprintf(stderr,
"Error recycling used serial since serial map is completely full at size %d\n",(
int)
usedSerials.size());
71 return ((rand()%(maxserial/3-1))+1)*3;
73 std::map< ObjSerial, bool >::const_iterator iter;
88 #if defined (__APPLE__)
94 if (
string( entry->d_name ) ==
"." &&
string( entry->d_name ) ==
"..")
100 if (stat( tmp.c_str(), &s ) < 0)
102 if ( (s.st_mode&S_IFDIR) )
107 #if defined (__FreeBSD__) || defined (__APPLE__)
114 if ( (
string( entry->d_name ).find(
".pk3" ) ) != std::string::npos && (
string( entry->d_name ).find(
"data" ) )
115 == std::string::npos )
120 #if defined (__FreeBSD__) || defined (__APPLE__)
127 if ( (
string( entry->d_name ).find(
"data.pk3" ) ) != std::string::npos )
132 namespace VSFileSystem
141 if (NULL != getcwd( pwd, 8191 )) {
149 char *program = argv0;
160 sprintf( linkname,
"/proc/%d/exe", pid );
161 ret = readlink( linkname, buf, 65535 );
163 sprintf( linkname,
"/proc/%d/file", pid );
164 ret = readlink( linkname, buf, 65535 );
167 ret = readlink( program, buf, 65535 );
177 int pathlen = strlen( program );
178 parentdir =
new char[pathlen+1];
180 strncpy( parentdir, program, pathlen+1 );
181 c = (
char*) parentdir;
184 while ( (*c !=
'/') && (*c !=
'\\') && c > parentdir )
187 if (strlen( parentdir ) > 0) {
188 if (chdir( parentdir ))
197 FileLookupCache::iterator it = cache.find( hashName );
198 if ( it != cache.end() )
202 return cache[hashName] =
LookForFile( file, type );
237 ostr<<
"VSFileSystem::<undefined VSFileType>";
247 cerr<<
"STARTING ARGLIST"<<endl;
260 ret = va_arg( ap,
int );
261 cerr<<
"\tFound 'n' : "<<ret<<endl;
264 cerr<<
"\tOther arg"<<endl;
267 cerr<<
"ENDING ARGLIST"<<endl;
330 std::string result(
"" );
336 std::string result(
"" );
349 return string(
"#stex#" )+name;
353 return string(
"#ssnd#" )+name;
359 return newpath+string(
"/" );
373 autogenerated =
false;
374 if (name.length() == 0)
376 string newname( name );
378 std::string::size_type dot = name.find(
"." );
379 if (dot != std::string::npos)
380 newname = name.substr( 0, dot );
381 newname +=
".net.system";
385 autogenerated =
false;
387 autogenerated = (err ==
Shared);
397 FILE *
vs_open(
const char *filename,
const char *mode )
400 cerr<<
"-= VS_OPEN in mode "<<mode<<
" =- ";
402 string fullpath =
homedir+
"/"+string( filename );
403 if ( !
use_volumes && (
string( mode ) ==
"rb" ||
string( mode ) ==
"r") ) {
405 fp = fopen( fullpath.c_str(), mode );
407 fullpath = string( filename );
408 output += fullpath+
"... NOT FOUND\n\tTry loading : "+fullpath;
409 fp = fopen( fullpath.c_str(), mode );
412 fullpath =
datadir+
"/"+string( filename );
413 output +=
"... NOT FOUND\n\tTry loading : "+fullpath;
414 fp = fopen( fullpath.c_str(), mode );
419 cerr<<fullpath<<
" SUCCESS !!!"<<endl;
421 cerr<<output<<
" NOT FOUND !!!"<<endl;
425 fp = fopen( fullpath.c_str(), mode );
428 cerr<<fullpath<<
" opened for writing SUCCESS !!!"<<endl;
430 cerr<<fullpath<<
" FAILED !!!"<<endl;
438 size_t vs_read(
void *ptr,
size_t size,
size_t nmemb, FILE *fp )
441 return fread( ptr, size, nmemb, fp );
446 size_t vs_write(
const void *ptr,
size_t size,
size_t nmemb, FILE *fp )
449 return fwrite( ptr, size, nmemb, fp );
465 va_start( ap, format );
467 return vfprintf( fp, format, ap );
476 va_start( ap, format );
477 vfprintf( stderr, format, ap );
482 int vs_fscanf( FILE *fp,
const char *format, ... )
486 va_start( arglist, format );
488 return vfscanf( fp, format, arglist );
496 return fseek( fp, offset, whence );
518 if (fstat( fileno( fp ), &st ) == 0)
534 char *chome_path = NULL;
536 struct passwd *pwent;
537 pwent = getpwuid( getuid() );
538 chome_path = pwent->pw_dir;
540 cerr<<
"!!! ERROR : home directory not found"<<endl;
543 string user_home_path( chome_path );
548 cerr<<
"USING HOMEDIR : "<<
homedir<<
" As the home directory "<<endl;
554 vector< string >data_paths;
558 data_paths.push_back(
datadir );
563 data_paths.push_back( DATA_DIR );
576 data_paths.push_back(
"." );
577 data_paths.push_back(
".." );
580 data_paths.push_back(
"../data" );
581 data_paths.push_back(
"../../data" );
582 data_paths.push_back(
"../Resources" );
583 data_paths.push_back(
"../Resources/data" );
588 for (vector< string >::iterator vsit = data_paths.begin(); vsit != data_paths.end(); vsit++)
591 cerr<<
"Found data in "<<(*vsit)<<endl;
592 if (NULL != getcwd( tmppath, 16384 )) {
593 if ( (*vsit).substr( 0, 1 ) ==
"." )
594 datadir =
string( tmppath )+
"/"+(*vsit);
601 if (chdir(
datadir.c_str() ) < 0) {
602 cerr<<
"Error changing to datadir"<<endl;
605 if (NULL != getcwd( tmppath, 16384 )) {
611 cerr<<
"Using "<<
datadir<<
" as data directory"<<endl;
615 string versionloc =
datadir+
"/Version.txt";
616 FILE *version = fopen( versionloc.c_str(),
"r" );
618 versionloc =
datadir+
"Version.txt";
619 version = fopen( versionloc.c_str(),
"r" );
622 version = fopen(
"Version.txt",
"r" );
626 while ( ( c = fgetc( version ) ) != EOF ) {
632 if ( hsd.length() ) {
634 printf(
"Using %s as the home directory\n", hsd.c_str() );
639 cout<<
"Found MODDIR = "<<
moddir<<endl;
647 bool foundweapons =
false;
654 cout<<
"CONFIGFILE - Found a config file in home mod directory, using : "
665 cout<<
"WARNING : coudn't find a mod named '"<<subdir<<
"' in homedir/mods"<<endl;
669 cout<<
"CONFIGFILE - Found a config file in mods directory, using : "
671 if ( (!foundweapons) &&
FileExists(
moddir+
"/"+subdir,
"weapon_list.xml" ) >= 0 ) {
679 cout<<
"ERROR : coudn't find a mod named '"<<subdir<<
"' in datadir/mods"<<endl;
686 cerr<<
"CONFIGFILE - Found a config file in home directory, using : "<<(
homedir+
"/"+
config_file)<<endl;
691 cerr<<
"CONFIGFILE - No home config file found, using datadir config file : "<<(
datadir+
"/"+
config_file)<<endl;
696 cerr<<
"CONFIG FILE NOT FOUND !!!"<<endl;
700 }
else if (subdir !=
"") {
701 printf(
"Using Mod Directory %s\n",
moddir.c_str() );
708 fprintf( stderr,
"reallocating vs_config \n" );
716 if (data_path !=
"") {
718 cout<<
"DATADIR - Found a datadir in config, using : "<<data_path<<endl;
721 cout<<
"DATADIR - No datadir specified in config file, using ; "<<
datadir<<endl;
728 struct dirent **dirlist;
738 string dname( dirlist[ret]->d_name );
741 cout<<
"\n\nAdding HQ Textures Pack\n\n";
754 string dname( dirlist[ret]->d_name );
756 curpath =
moddir+
"/"+dname;
757 cout<<
"Adding mod path : "<<curpath<<endl;
771 string dname( dirlist[ret]->d_name );
774 cout<<
"Adding mod path : "<<curpath<<endl;
940 cout<<
"Using volume file "<<(
datadir+
"/animations")<<
".pk3"<<endl;
944 cout<<
"Using volume file "<<(
datadir+
"/movies")<<
".pk3"<<endl;
948 cout<<
"Using volume file "<<(
datadir+
"/communications")<<
".pk3"<<endl;
952 cout<<
"Using volume file "<<(
datadir+
"/mission")<<
".pk3"<<endl;
956 cout<<
"Using volume file "<<(
datadir+
"/ai")<<
".pk3"<<endl;
966 err = mkdir( filename
967 #
if !defined (_WIN32) || defined (__CYGWIN__)
971 if (err < 0 && errno != EEXIST) {
972 cerr<<
"Errno="<<errno<<
" - FAILED TO CREATE : "<<filename<<endl;
1004 if (stat( filename, &s ) < 0)
1006 if (s.st_mode&S_IFDIR)
1023 if (filename[0] ==
'/')
1027 const char *rootsep = (root ==
"" || root ==
"/") ?
"" :
"/";
1030 fullpath = root+rootsep+file;
1032 fullpath = root+rootsep+
Directories[type]+
"/"+file;
1034 if (stat( fullpath.c_str(), &s ) >= 0) {
1035 if (s.st_mode&S_IFDIR) {
1036 cerr<<
" File is a directory ! ";
1052 vsUMap< string, CPK3* >::iterator it;
1054 failed +=
"Looking for file in VOLUME : "+fullpath+
"... ";
1058 if ( ( volok = vol->
Open( fullpath.c_str() ) ) ) {
1059 failed +=
" VOLUME OPENED\n";
1061 std::pair< std::string, CPK3* >pk3_pair( fullpath, vol );
1064 failed +=
" COULD NOT OPEN VOLUME\n";
1067 failed +=
" VOLUME FOUND\n";
1081 filestr = string( file );
1084 failed +=
"Looking for file in VOLUME : "+fullpath+
"... ";
1088 if ( ( volok = vol->
Open( fullpath.c_str() ) ) ) {
1089 failed +=
" VOLUME OPENED\n";
1091 std::pair< std::string, CPK3* >pk3_pair( fullpath, vol );
1094 failed +=
" COULD NOT OPEN VOLUME\n";
1097 failed +=
" VOLUME FOUND\n";
1114 failed +=
"\tTRY LOADING : "+
nameof( type )+
" "+fullpath+
"... NOT FOUND\n";
1116 failed +=
"\tTRY LOADING in "+
nameof( type )+
" "+fullpath+
" : "+file+
"... NOT FOUND\n";
1119 failed =
"\tTRY LOADING : "+
nameof( type )+
" "+fullpath+
"... SUCCESS";
1121 failed =
"\tTRY LOADING in "+
nameof( type )+
" "+fullpath+
" : "+file+
"... SUCCESS";
1129 return FileExists( root, filename.c_str(), type, lookinvolume );
1152 cerr<<
"!!! ERROR/WARNING VSFile : ";
1154 cerr<<
"on "<<str<<
" : ";
1156 cerr<<
"File not found"<<endl;
1158 }
else if (errno == EPERM) {
1159 cerr<<
"Permission denied"<<endl;
1161 }
else if (errno == EACCES) {
1162 cerr<<
"Access denied"<<endl;
1165 cerr<<
"Unspecified error (maybe to document in VSFile ?)"<<endl;
1180 int found = -1, shared =
false;
1181 string filepath, curpath, dir, extra(
"" ), subdir;
1219 unsigned int i = 0,
j = 0;
1220 for (
int LC = 0; LC < 2 && found < 0; ( LC += (extra ==
"" ? 2 : 1) ), extra =
"") {
1223 for (i = 0; found < 0 && i <
Rootdir.size(); i++) {
1257 for (i = 0; found < 0 && i <
Rootdir.size(); i++) {
1267 if ( subdir.length() ) subdir +=
"/";
1276 for (i = 0; found < 0 && i <
Rootdir.size(); i++) {
1292 cerr<<
failed<<
" - INDEX="<<found<<endl<<endl;
1325 void VSFile::private_init()
1330 pk3_extracted_file = NULL;
1346 this->size = bufsize;
1347 this->pk3_extracted_file =
new char[bufsize+1];
1348 memcpy( this->pk3_extracted_file, buffer, bufsize );
1349 pk3_extracted_file[bufsize] = 0;
1350 this->file_type = this->alt_type =
ZoneBuffer;
1351 this->file_mode = mode;
1373 if (pk3_extracted_file)
1374 delete[] pk3_extracted_file;
1377 void VSFile::checkExtracted()
1380 if (!pk3_extracted_file) {
1381 string full_vol_path;
1382 if (this->volume_type ==
VSFSBig)
1386 vsUMap< string, CPK3* >::iterator it;
1391 if ( !pk3newfile->
Open( full_vol_path.c_str() ) ) {
1392 cerr<<
"!!! ERROR : opening volume : "<<full_vol_path<<endl;
1395 std::pair< std::string, CPK3* >pk3_pair( full_vol_path, pk3newfile );
1398 this->pk3_file = pk3newfile;
1400 this->pk3_file = it->second;
1403 if (this->file_index != -1)
1404 pk3_extracted_file = (
char*) pk3_file->
ExtractFile( this->file_index, &pk3size );
1406 pk3_extracted_file = (
char*) pk3_file->
ExtractFile(
1407 (this->subdirectoryname+
"/"+this->filename).c_str(), &pk3size );
1408 this->size = pk3size;
1410 <<(this->subdirectoryname+
"/"+this->filename)<<
" WITH INDEX="<<this->file_index<<
" SIZE="<<pk3size<<endl;
1420 this->file_type = this->alt_type = type;
1422 this->filename = string( file );
1427 cerr<<
"Loading a "<<type<<
" : "<<file<<endl;
1438 failed +=
"\t"+filestr+
" NOT FOUND !\n";
1441 for (
unsigned int ij = 0; ij <
Rootdir.size() && found < 0; ij++) {
1442 filestr =
Rootdir[ij]+
"/"+file;
1445 failed +=
"\tRootdir : "+filestr+
" NOT FOUND !\n";
1450 if ( ( found =
FileExists(
"", filestr ) ) < 0 )
1451 failed +=
"\tAbs or rel : "+filestr+
" NOT FOUND !\n";
1457 this->valid =
false;
1460 if ( ( this->fp = fopen( filestr.c_str(),
"rb" ) ) == NULL ) {
1461 cerr<<
"!!! SERIOUS ERROR : failed to open Unknown file "<<filestr<<
" - this should not happen"<<endl;
1466 cerr<<filestr<<
" SUCCESS !!!"<<endl;
1471 this->valid =
false;
1475 this->fp = fopen( filestr.c_str(),
"rb" );
1477 cerr<<
"!!! SERIOUS ERROR : failed to open "<<filestr<<
" - this should not happen"<<endl;
1478 this->valid =
false;
1488 this->valid =
false;
1493 if ( this->volume_type ==
VSFSNone || (this->alt_type != this->file_type && !
UseVolumes[this->alt_type]) ) {
1495 this->fp = fopen( filestr.c_str(),
"rb" );
1497 cerr<<
"!!! SERIOUS ERROR : failed to open "<<filestr<<
" - this should not happen"<<endl;
1498 this->valid =
false;
1512 cerr<<endl<<
"BEGINNING OF ";
1520 if (!this->pk3_extracted_file)
1534 this->file_type = this->alt_type = type;
1546 this->file_type = this->alt_type = type;
1547 this->filename = string( filenam );
1553 string fpath(
homedir+
"/"+dirpath+
"/"+this->filename );
1554 this->fp = fopen( fpath.c_str(),
"wb" );
1559 this->fp = fopen( fpath.c_str(),
"wb" );
1566 this->fp = fopen( fpath.c_str(),
"wb" );
1570 string fpath(
homedir+
"/save/"+this->filename );
1571 this->fp = fopen( fpath.c_str(),
"wb" );
1575 string fpath(
datadir+
"/accounts/"+this->filename );
1576 this->fp = fopen( fpath.c_str(),
"wb" );
1580 string fpath(
homedir+
"/"+this->filename );
1582 this->directoryname =
"";
1583 this->fp = fopen( fpath.c_str(),
"wb" );
1594 assert( fp != NULL );
1595 nbread = fread( ptr, 1, length, this->fp );
1599 if (length > this->size-this->offset)
1600 length = this->size-this->offset;
1601 memcpy( ptr, (pk3_extracted_file+offset), length );
1613 ret = fgets( (
char*) ptr, length, this->fp );
1621 bool nl_found =
false;
1624 cerr<<
"READLINE STARTING OFFSET="<<offset;
1625 for (i = 0; !nl_found && i < length && offset < size; offset++, i++) {
1626 if (pk3_extracted_file[offset] ==
'\n' || pk3_extracted_file[offset] ==
'\r') {
1629 if (pk3_extracted_file[offset] ==
'\n')
1631 if (pk3_extracted_file[offset] ==
'\r')
1635 ret[i] = pk3_extracted_file[offset];
1637 cerr<<std::hex<<ret[i]<<
" ";
1643 cerr<<std::dec<<
" - read "<<i<<
" char - "<<ret<<endl;
1653 if (this->
Size() < 0) {
1654 cerr<<
"Attempt to call ReadFull on a bad file "<<this->filename<<
" "<<this->
Size()<<
" "<<this->
GetFullPath().c_str()<<endl;
1658 char *content =
new char[this->
Size()+1];
1659 content[this->
Size()] = 0;
1660 int readsize = fread( content, 1, this->
Size(), this->fp );
1661 if (this->
Size() != readsize) {
1662 cerr<<
"Only read "<<readsize<<
" out of "<<this->
Size()<<
" bytes of "<<this->filename<<endl;
1667 content[readsize] =
'\0';
1669 string res( content );
1675 offset = this->
Size();
1676 return string( pk3_extracted_file );
1679 return string(
"" );
1685 size_t nbwritten = fwrite( ptr, 1, length, this->fp );
1688 cerr<<
"!!! ERROR : Writing is not supported within resource/volume files"<<endl;
1696 std::string::size_type length = content.length();
1697 return this->
Write( content.c_str(), length );
1703 fputs( (
const char*) ptr, this->fp );
1705 cerr<<
"!!! ERROR : Writing is not supported within resource/volume files"<<endl;
1718 va_start( ap, format );
1720 return vfprintf( this->fp, format, ap );
1722 cerr<<
"!!! ERROR : Writing is not supported within resource/volume files"<<endl;
1735 int format_length = strlen( format );
1736 char *newformat =
new char[format_length+3];
1737 memset( newformat, 0, format_length+3 );
1738 memcpy( newformat, format, format_length );
1739 strcat( newformat,
"%n" );
1741 va_start( arglist, format );
1744 ret = vfscanf( this->fp, newformat, arglist );
1750 ret = vsscanf( pk3_extracted_file+offset, newformat, arglist );
1753 cerr<<
" SSCANF : Read "<<readbytes<<
" bytes"<<endl;
1754 this->offset += readbytes;
1766 fseek( this->fp, 0, SEEK_SET );
1778 fseek( this->fp, 0, SEEK_END );
1790 fseek( this->fp, foffset, SEEK_SET );
1804 if ( (fp != NULL) && fstat( fileno( fp ), &st ) == 0 )
1805 return this->size = st.st_size;
1822 this->fp = fopen( this->
GetFullPath().c_str(),
"w+b" );
1829 cerr<<
"!!! ERROR : Writing is not supported within resource/volume files"<<endl;
1838 ret = ftell( this->fp );
1854 eof = (this->
Size() < 0) || ( offset == (
unsigned long)this->
Size() );
1868 delete this->pk3_extracted_file;
1869 this->pk3_extracted_file = NULL;
1872 if ( this->valid && this->file_mode ==
ReadOnly
1889 if (pk3_extracted_file)
1890 delete[] pk3_extracted_file;
1891 pk3_extracted_file = NULL;
1895 this->valid =
false;
1896 this->filename =
"";
1897 this->directoryname =
"";
1898 this->subdirectoryname =
"";
1899 this->rootname =
"";
1901 this->file_index = -1;
1904 static void pathAppend(
string &dest,
string &suffix )
1906 if ( suffix.empty() )
1908 if (suffix[0] !=
'/' && !dest.empty() && dest[dest.length()-1] !=
'/')
1915 string tmp = this->rootname;
1916 pathAppend( tmp, this->directoryname );
1917 pathAppend( tmp, this->subdirectoryname );
1918 pathAppend( tmp, this->filename );
1924 string tmp = this->directoryname;
1925 pathAppend( tmp, this->subdirectoryname );
1926 pathAppend( tmp, this->filename );
1932 this->file_type = type;
1936 this->alt_type = type;
1940 this->file_index = index;
1945 this->volume_type = big;
1954 while ( this->offset < length && this->offset < this->size
1955 && (this->pk3_extracted_file[offset] ==
'\r' || this->pk3_extracted_file[offset] ==
'\n') )
1960 while ( this->offset < this->size && (this->pk3_extracted_file[offset] ==
'\r' || this->pk3_extracted_file[offset] ==
'\n') )
1986 ostr<<
"VSFileSystem::<undefined VSError>";
2025 return "VSFileSystem::<undefined VSFileType>";
2032 #if defined (_WIN32) && !defined (__CYGWIN__)
2034 int scandir(
const char *dirname,
struct dirent ***namelist,
int (*select)(
const struct dirent* ),
int (*compar)(
2035 const struct dirent**,
2036 const struct dirent** ) )
2040 WIN32_FIND_DATA find;
2042 int nDir = 0, NDir = 0;
2043 struct dirent **dir = 0, *selectDir;
2046 len = strlen( dirname );
2047 findIn = (
char*) malloc( len+5 );
2048 strcpy( findIn, dirname );
2049 for (d = findIn; *d; d++)
2050 if (*d ==
'/') *d =
'\\';
2051 if ( (len == 0) ) strcpy( findIn,
".\\*" );
2052 if ( (len == 1) && (d[-1] ==
'.') ) strcpy( findIn,
".\\*" );
2053 if ( (len > 0) && (d[-1] ==
'\\') ) {
2057 if ( (len > 1) && (d[-1] ==
'.') && (d[-2] ==
'\\') ) d[-1] =
'*';
2058 if ( ( h = FindFirstFile( findIn, &find ) ) == INVALID_HANDLE_VALUE ) {
2059 ret = GetLastError();
2060 if (ret != ERROR_NO_MORE_FILES) {
2067 selectDir = (
struct dirent*) malloc(
sizeof (
struct dirent)+strlen( find.cFileName ) );
2068 strcpy( selectDir->d_name, find.cFileName );
2069 if ( !select || (*select)(selectDir) ) {
2071 struct dirent **tempDir = (dirent**) calloc(
sizeof (
struct dirent*), NDir+33 );
2072 if (NDir) memcpy( tempDir, dir,
sizeof (
struct dirent*) *NDir );
2073 if (dir) free( dir );
2077 dir[nDir] = selectDir;
2083 }
while ( FindNextFile( h, &find ) );
2084 ret = GetLastError();
2085 if (ret != ERROR_NO_MORE_FILES) {
2092 qsort( dir, nDir,
sizeof (*dir),
2093 (
int (*)(
const void*,
const void* ) )compar );
2098 int alphasort(
struct dirent **a,
struct dirent **b )
2100 return strcmp( (*a)->d_name, (*b)->d_name );