📄 files.c
字号:
directory_t *dir;
long hash;
unz_s *zfi;
FILE *temp;
int l;
char demoExt[16];
hash = 0;
if ( !fs_searchpaths ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
}
if ( file == NULL ) {
// just wants to see if file is there
for ( search = fs_searchpaths ; search ; search = search->next ) {
//
if ( search->pack ) {
hash = FS_HashFileName(filename, search->pack->hashSize);
}
// is the element a pak file?
if ( search->pack && search->pack->hashTable[hash] ) {
// look through all the pak file elements
pak = search->pack;
pakFile = pak->hashTable[hash];
do {
// case and separator insensitive comparisons
if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
// found it!
return qtrue;
}
pakFile = pakFile->next;
} while(pakFile != NULL);
} else if ( search->dir ) {
dir = search->dir;
netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
temp = fopen (netpath, "rb");
if ( !temp ) {
continue;
}
fclose(temp);
return qtrue;
}
}
return qfalse;
}
if ( !filename ) {
Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" );
}
Com_sprintf (demoExt, sizeof(demoExt), ".dm_%d",PROTOCOL_VERSION );
// qpaths are not supposed to have a leading slash
if ( filename[0] == '/' || filename[0] == '\\' ) {
filename++;
}
// make absolutely sure that it can't back up the path.
// The searchpaths do guarantee that something will always
// be prepended, so we don't need to worry about "c:" or "//limbo"
if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) {
*file = 0;
return -1;
}
// make sure the q3key file is only readable by the quake3.exe at initialization
// any other time the key should only be accessed in memory using the provided functions
if( com_fullyInitialized && strstr( filename, "q3key" ) ) {
*file = 0;
return -1;
}
//
// search through the path, one element at a time
//
*file = FS_HandleForFile();
fsh[*file].handleFiles.unique = uniqueFILE;
for ( search = fs_searchpaths ; search ; search = search->next ) {
//
if ( search->pack ) {
hash = FS_HashFileName(filename, search->pack->hashSize);
}
// is the element a pak file?
if ( search->pack && search->pack->hashTable[hash] ) {
// disregard if it doesn't match one of the allowed pure pak files
if ( !FS_PakIsPure(search->pack) ) {
continue;
}
// look through all the pak file elements
pak = search->pack;
pakFile = pak->hashTable[hash];
do {
// case and separator insensitive comparisons
if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
// found it!
// mark the pak as having been referenced and mark specifics on cgame and ui
// shaders, txt, arena files by themselves do not count as a reference as
// these are loaded from all pk3s
// from every pk3 file..
l = strlen( filename );
if ( !(pak->referenced & FS_GENERAL_REF)) {
if ( Q_stricmp(filename + l - 7, ".shader") != 0 &&
Q_stricmp(filename + l - 4, ".txt") != 0 &&
Q_stricmp(filename + l - 4, ".cfg") != 0 &&
Q_stricmp(filename + l - 7, ".config") != 0 &&
strstr(filename, "levelshots") == NULL &&
Q_stricmp(filename + l - 4, ".bot") != 0 &&
Q_stricmp(filename + l - 6, ".arena") != 0 &&
Q_stricmp(filename + l - 5, ".menu") != 0) {
pak->referenced |= FS_GENERAL_REF;
}
}
// qagame.qvm - 13
// dTZT`X!di`
if (!(pak->referenced & FS_QAGAME_REF) && FS_ShiftedStrStr(filename, "dTZT`X!di`", 13)) {
pak->referenced |= FS_QAGAME_REF;
}
// cgame.qvm - 7
// \`Zf^'jof
if (!(pak->referenced & FS_CGAME_REF) && FS_ShiftedStrStr(filename , "\\`Zf^'jof", 7)) {
pak->referenced |= FS_CGAME_REF;
}
// ui.qvm - 5
// pd)lqh
if (!(pak->referenced & FS_UI_REF) && FS_ShiftedStrStr(filename , "pd)lqh", 5)) {
pak->referenced |= FS_UI_REF;
}
if ( uniqueFILE ) {
// open a new file on the pakfile
fsh[*file].handleFiles.file.z = unzReOpen (pak->pakFilename, pak->handle);
if (fsh[*file].handleFiles.file.z == NULL) {
Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->pakFilename);
}
} else {
fsh[*file].handleFiles.file.z = pak->handle;
}
Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
fsh[*file].zipFile = qtrue;
zfi = (unz_s *)fsh[*file].handleFiles.file.z;
// in case the file was new
temp = zfi->file;
// set the file position in the zip file (also sets the current file info)
unzSetCurrentFileInfoPosition(pak->handle, pakFile->pos);
// copy the file info into the unzip structure
Com_Memcpy( zfi, pak->handle, sizeof(unz_s) );
// we copy this back into the structure
zfi->file = temp;
// open the file in the zip
unzOpenCurrentFile( fsh[*file].handleFiles.file.z );
fsh[*file].zipFilePos = pakFile->pos;
if ( fs_debug->integer ) {
Com_Printf( "FS_FOpenFileRead: %s (found in '%s')\n",
filename, pak->pakFilename );
}
return zfi->cur_file_info.uncompressed_size;
}
pakFile = pakFile->next;
} while(pakFile != NULL);
} else if ( search->dir ) {
// check a file in the directory tree
// if we are running restricted, the only files we
// will allow to come from the directory are .cfg files
l = strlen( filename );
// FIXME TTimo I'm not sure about the fs_numServerPaks test
// if you are using FS_ReadFile to find out if a file exists,
// this test can make the search fail although the file is in the directory
// I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
// turned out I used FS_FileExists instead
if ( fs_restrict->integer || fs_numServerPaks ) {
if ( Q_stricmp( filename + l - 4, ".cfg" ) // for config files
&& Q_stricmp( filename + l - 5, ".menu" ) // menu files
&& Q_stricmp( filename + l - 5, ".game" ) // menu files
&& Q_stricmp( filename + l - strlen(demoExt), demoExt ) // menu files
&& Q_stricmp( filename + l - 4, ".dat" ) ) { // for journal files
continue;
}
}
dir = search->dir;
netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
fsh[*file].handleFiles.file.o = fopen (netpath, "rb");
if ( !fsh[*file].handleFiles.file.o ) {
continue;
}
if ( Q_stricmp( filename + l - 4, ".cfg" ) // for config files
&& Q_stricmp( filename + l - 5, ".menu" ) // menu files
&& Q_stricmp( filename + l - 5, ".game" ) // menu files
&& Q_stricmp( filename + l - strlen(demoExt), demoExt ) // menu files
&& Q_stricmp( filename + l - 4, ".dat" ) ) { // for journal files
fs_fakeChkSum = random();
}
Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
fsh[*file].zipFile = qfalse;
if ( fs_debug->integer ) {
Com_Printf( "FS_FOpenFileRead: %s (found in '%s/%s')\n", filename,
dir->path, dir->gamedir );
}
// if we are getting it from the cdpath, optionally copy it
// to the basepath
if ( fs_copyfiles->integer && !Q_stricmp( dir->path, fs_cdpath->string ) ) {
char *copypath;
copypath = FS_BuildOSPath( fs_basepath->string, dir->gamedir, filename );
FS_CopyFile( netpath, copypath );
}
return FS_filelength (*file);
}
}
Com_DPrintf ("Can't find %s\n", filename);
#ifdef FS_MISSING
if (missingFiles) {
fprintf(missingFiles, "%s\n", filename);
}
#endif
*file = 0;
return -1;
}
/*
=================
FS_Read
Properly handles partial reads
=================
*/
int FS_Read2( void *buffer, int len, fileHandle_t f ) {
if ( !fs_searchpaths ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
}
if ( !f ) {
return 0;
}
if (fsh[f].streamed) {
int r;
fsh[f].streamed = qfalse;
r = Sys_StreamedRead( buffer, len, 1, f);
fsh[f].streamed = qtrue;
return r;
} else {
return FS_Read( buffer, len, f);
}
}
int FS_Read( void *buffer, int len, fileHandle_t f ) {
int block, remaining;
int read;
byte *buf;
int tries;
if ( !fs_searchpaths ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
}
if ( !f ) {
return 0;
}
buf = (byte *)buffer;
fs_readCount += len;
if (fsh[f].zipFile == qfalse) {
remaining = len;
tries = 0;
while (remaining) {
block = remaining;
read = fread (buf, 1, block, fsh[f].handleFiles.file.o);
if (read == 0) {
// we might have been trying to read from a CD, which
// sometimes returns a 0 read on windows
if (!tries) {
tries = 1;
} else {
return len-remaining; //Com_Error (ERR_FATAL, "FS_Read: 0 bytes read");
}
}
if (read == -1) {
Com_Error (ERR_FATAL, "FS_Read: -1 bytes read");
}
remaining -= read;
buf += read;
}
return len;
} else {
return unzReadCurrentFile(fsh[f].handleFiles.file.z, buffer, len);
}
}
/*
=================
FS_Write
Properly handles partial writes
=================
*/
int FS_Write( const void *buffer, int len, fileHandle_t h ) {
int block, remaining;
int written;
byte *buf;
int tries;
FILE *f;
if ( !fs_searchpaths ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
}
if ( !h ) {
return 0;
}
f = FS_FileForHandle(h);
buf = (byte *)buffer;
remaining = len;
tries = 0;
while (remaining) {
block = remaining;
written = fwrite (buf, 1, block, f);
if (written == 0) {
if (!tries) {
tries = 1;
} else {
Com_Printf( "FS_Write: 0 bytes written\n" );
return 0;
}
}
if (written == -1) {
Com_Printf( "FS_Write: -1 bytes written\n" );
return 0;
}
remaining -= written;
buf += written;
}
if ( fsh[h].handleSync ) {
fflush( f );
}
return len;
}
void QDECL FS_Printf( fileHandle_t h, const char *fmt, ... ) {
va_list argptr;
char msg[MAXPRINTMSG];
va_start (argptr,fmt);
Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
va_end (argptr);
FS_Write(msg, strlen(msg), h);
}
/*
=================
FS_Seek
=================
*/
int FS_Seek( fileHandle_t f, long offset, int origin ) {
int _origin;
char foo[65536];
if ( !fs_searchpaths ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
return -1;
}
if (fsh[f].streamed) {
fsh[f].streamed = qfalse;
Sys_StreamSeek( f, offset, origin );
fsh[f].streamed = qtrue;
}
if (fsh[f].zipFile == qtrue) {
if (offset == 0 && origin == FS_SEEK_SET) {
// set the file position in the zip file (also sets the current file info)
unzSetCurrentFileInfoPosition(fsh[f].handleFiles.file.z, fsh[f].zipFilePos);
return unzOpenCurrentFile(fsh[f].handleFiles.file.z);
} else if (offset<65536) {
// set the file position in the zip file (also sets the current file info)
unzSetCurrentFileInfoPosition(fsh[f].handleFiles.file.z, fsh[f].zipFilePos);
unzOpenCurrentFile(fsh[f].handleFiles.file.z);
return FS_Read(foo, offset, f);
} else {
Com_Error( ERR_FATAL, "ZIP FILE FSEEK NOT YET IMPLEMENTED\n" );
return -1;
}
} else {
FILE *file;
file = FS_FileForHandle(f);
switch( origin ) {
case FS_SEEK_CUR:
_origin = SEEK_CUR;
break;
case FS_SEEK_END:
_origin = SEEK_END;
break;
case FS_SEEK_SET:
_origin = SEEK_SET;
break;
default:
_origin = SEEK_CUR;
Com_Error( ERR_FATAL, "Bad origin in FS_Seek\n" );
break;
}
return fseek( file, offset, _origin );
}
}
/*
======================================================================================
CONVENIENCE FUNCTIONS FOR ENTIRE FILES
======================================================================================
*/
int FS_FileIsInPAK(const char *filename, int *pChecksum ) {
searchpath_t *search;
pack_t *pak;
fileInPack_t *pakFile;
long hash = 0;
if ( !fs_searchpaths ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
}
if ( !filename ) {
Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" );
}
// qpaths are not supposed to have a leading slash
if ( filename[0] == '/' || filename[0] == '\\' ) {
filename++;
}
// make absolutely sure that it can't back up the path.
// The searchpaths do guarantee that something will always
// be prepended, so we don't need to worry about "c:" or "//limbo"
if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) {
return -1;
}
//
// search through the path, one element at a time
//
for ( search = fs_searchpaths ; search ; search = search->next ) {
//
if (search->pack) {
hash = FS_HashFileName(filename, search->pack->hashSize);
}
// is the element a pak file?
if ( search->pack && search->pack->hashTable[hash] ) {
// disregard if it doesn't match one of the allowed pure pak files
if ( !FS_PakIsPure(search->pack) ) {
continue;
}
// look through all the pak file elements
pak = search->pack;
pakFile = pak->hashTable[hash];
do {
// case and separator insensitive comparisons
if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
if (pChecksum) {
*pChecksum = pak->pure_checksum;
}
return 1;
}
pakFile = pakFile->next;
} while(pakFile != NULL);
}
}
return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -