28 Mar 2010

This commit is contained in:
g-cont 2010-03-28 00:00:00 +03:00 committed by Alibek Omarov
parent 2d8beb699c
commit dfa0517d2b
36 changed files with 1470 additions and 1117 deletions

View File

@ -257,8 +257,8 @@ void CL_DeleteDemo_f( void )
}
// delete save and saveshot
FS_Delete( va( "%s/demos/%s.dem", GI->gamedir, Cmd_Argv( 1 )));
FS_Delete( va( "%s/demos/%s.%s", GI->gamedir, Cmd_Argv( 1 ), DEMOSHOT_TYPE ));
FS_Delete( va( "demos/%s.dem", Cmd_Argv( 1 )));
FS_Delete( va( "demos/%s.%s", Cmd_Argv( 1 ), DEMOSHOT_TYPE ));
}
/*

View File

@ -444,7 +444,7 @@ Begins recording a demo from the current position
void CL_Record_f( void )
{
const char *name;
string demoname, demopath;
string demoname, demopath, demoshot;
int n;
if( Cmd_Argc() == 1 )
@ -488,12 +488,11 @@ void CL_Record_f( void )
// open the demo file
com.sprintf( demopath, "demos/%s.dem", demoname );
com.sprintf( demoshot, "demos/%s.%s", demoname, SI->savshot_ext );
// make sure what old demo is removed
if( FS_FileExists( va( "demos/%s.dem", demoname )))
FS_Delete( va( "%s/demos/%s.dem", GI->gamedir, demoname ));
if( FS_FileExists( va( "demos/%s.%s", name, SI->savshot_ext )))
FS_Delete( va( "%s/demos/%s.%s", GI->gamedir, demoname, SI->savshot_ext ));
if( FS_FileExists( demopath )) FS_Delete( demopath );
if( FS_FileExists( demoshot )) FS_Delete( demoshot );
// write demoshot for preview
Cbuf_AddText( va( "demoshot \"%s\"\n", demoname ));

View File

@ -8,7 +8,6 @@
#include "byteorder.h"
#include "matrix_lib.h"
#include "const.h"
#include "com_library.h"
#include "triangle_api.h"
#include "effects_api.h"
#include "pm_defs.h"
@ -2627,10 +2626,11 @@ void CL_UnloadProgs( void )
clgame.dllFuncs.pfnShutdown();
StringTable_Delete( clgame.hStringTable );
Com_FreeLibrary( clgame.hInstance );
FS_FreeLibrary( clgame.hInstance );
Mem_FreePool( &cls.mempool );
Mem_FreePool( &clgame.mempool );
Mem_FreePool( &clgame.private );
Mem_Set( &clgame, 0, sizeof( clgame ));
}
bool CL_LoadProgs( const char *name )
@ -2638,7 +2638,6 @@ bool CL_LoadProgs( const char *name )
static CLIENTAPI GetClientAPI;
static cl_globalvars_t gpGlobals;
static playermove_t gpMove;
string libpath;
if( clgame.hInstance ) CL_UnloadProgs();
@ -2650,17 +2649,16 @@ bool CL_LoadProgs( const char *name )
// initialize TriAPI
clgame.pmove = &gpMove;
Com_BuildPath( name, libpath );
cls.mempool = Mem_AllocPool( "Client Static Pool" );
clgame.mempool = Mem_AllocPool( "Client Edicts Zone" );
clgame.private = Mem_AllocPool( "Client Private Zone" );
clgame.baselines = NULL;
clgame.edicts = NULL;
clgame.hInstance = Com_LoadLibrary( libpath );
clgame.hInstance = FS_LoadLibrary( name, false );
if( !clgame.hInstance ) return false;
GetClientAPI = (CLIENTAPI)Com_GetProcAddress( clgame.hInstance, "CreateAPI" );
GetClientAPI = (CLIENTAPI)FS_GetProcAddress( clgame.hInstance, "CreateAPI" );
if( !GetClientAPI )
{

View File

@ -1184,7 +1184,7 @@ void CL_Init( void )
Host_CheckChanges ();
if( !CL_LoadProgs( "client" ))
if( !CL_LoadProgs( "client.dll" ))
Host_Error( "CL_InitGame: can't initialize client.dll\n" );
CL_InitLocal();

View File

@ -7,6 +7,9 @@
#include "client.h"
#include "net_sound.h"
#define MSG_COUNT 32 // last 32 messages parsed
#define MSG_MASK (MSG_COUNT - 1)
char *svc_strings[256] =
{
"svc_bad",
@ -38,6 +41,131 @@ char *svc_strings[256] =
"svc_event_reliable"
};
typedef struct
{
int command;
int starting_offset;
int frame_number;
} oldcmd_t;
typedef struct
{
oldcmd_t oldcmd[MSG_COUNT];
int currentcmd;
bool parsing;
} msg_debug_t;
static msg_debug_t cls_message_debug;
static int starting_count;
const char *CL_MsgInfo( int cmd )
{
static string sz;
com.strcpy( sz, "???" );
if( cmd > 200 && cmd < 256 )
{
// get engine message name
com.strncpy( sz, svc_strings[cmd - 200], sizeof( sz ));
}
else if( cmd >= 0 && cmd < clgame.numMessages )
{
// get user message name
if( clgame.msg[cmd] && clgame.msg[cmd]->name )
com.strncpy( sz, clgame.msg[cmd]->name, sizeof( sz ));
}
return sz;
}
/*
=====================
CL_Parse_RecordCommand
record new message params into debug buffer
=====================
*/
void CL_Parse_RecordCommand( int cmd, int startoffset )
{
int slot;
if( cmd == svc_nop ) return;
slot = ( cls_message_debug.currentcmd++ & MSG_MASK );
cls_message_debug.oldcmd[slot].command = cmd;
cls_message_debug.oldcmd[slot].starting_offset = startoffset;
cls_message_debug.oldcmd[slot].frame_number = host.framecount;
}
/*
=====================
CL_WriteErrorMessage
write net_message into buffer.dat for debugging
=====================
*/
void CL_WriteErrorMessage( int current_count, sizebuf_t *msg )
{
file_t *fp;
const char *buffer_file = "buffer.dat";
fp = FS_Open( buffer_file, "wb" );
if( !fp ) return;
FS_Write( fp, &starting_count, sizeof( int ));
FS_Write( fp, &current_count, sizeof( int ));
FS_Write( fp, msg->data, msg->cursize );
FS_Close( fp );
MsgDev( D_INFO, "Wrote erroneous message to %s\n", buffer_file );
}
/*
=====================
CL_WriteMessageHistory
list last 32 messages for debugging net troubleshooting
=====================
*/
void CL_WriteMessageHistory( void )
{
int i, thecmd;
oldcmd_t *old, *failcommand;
sizebuf_t *msg = &net_message;
if( !cls.initialized || cls.state == ca_disconnected )
return;
if( !cls_message_debug.parsing )
return;
MsgDev( D_INFO, "Last %i messages parsed.\n", MSG_COUNT );
// finish here
thecmd = cls_message_debug.currentcmd - 1;
thecmd -= ( MSG_COUNT - 1 ); // back up to here
for( i = 0; i < MSG_COUNT - 1; i++ )
{
thecmd &= CMD_MASK;
old = &cls_message_debug.oldcmd[thecmd];
MsgDev( D_INFO, "%i %04i %s\n", old->frame_number, old->starting_offset, CL_MsgInfo( old->command ));
thecmd++;
}
failcommand = &cls_message_debug.oldcmd[thecmd];
MsgDev( D_INFO, "BAD: %3i:%s\n", msg->readcount - 1, CL_MsgInfo( failcommand->command ));
if( host.developer >= 3 )
{
CL_WriteErrorMessage( msg->readcount - 1, msg );
}
cls_message_debug.parsing = false;
}
/*
===============
CL_CheckOrDownloadFile
@ -146,14 +274,10 @@ void CL_ParseDownload( sizebuf_t *msg )
}
else
{
string oldn, newn;
FS_Close( cls.download );
// rename the temp file to it's final name
com.strncpy( oldn, cls.downloadtempname, MAX_STRING );
com.strncpy( newn, cls.downloadname, MAX_STRING );
r = rename( oldn, newn );
r = FS_Rename( cls.downloadtempname, cls.downloadname );
if( r ) MsgDev( D_ERROR, "failed to rename.\n" );
cls.download = NULL;
@ -570,19 +694,29 @@ void CL_ParseServerMessage( sizebuf_t *msg )
{
char *s;
int i, cmd;
int bufStart;
cls_message_debug.parsing = true; // begin parsing
starting_count = msg->readcount; // updates each frame
// parse the message
while( 1 )
{
if( msg->error )
{
Host_Error("CL_ParseServerMessage: Bad server message\n");
Host_Error( "CL_ParseServerMessage: bad server message\n" );
return;
}
// mark start position
bufStart = msg->readcount;
cmd = MSG_ReadByte( msg );
if( cmd == -1 ) break;
// record command for debugging spew on parse problem
CL_Parse_RecordCommand( cmd, bufStart );
// if( cmd > 200 ) MsgDev( D_INFO, "CL_Parse: %s received.\n", svc_strings[cmd - 200] );
// other commands
@ -685,4 +819,6 @@ void CL_ParseServerMessage( sizebuf_t *msg )
break;
}
}
cls_message_debug.parsing = false; // done
}

View File

@ -48,7 +48,7 @@ typedef struct frame_s
int parse_entities; // non-masked index into cl_parse_entities array
} frame_t;
#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems
#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems
#define CMD_MASK (CMD_BACKUP - 1)
// the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of
@ -108,7 +108,7 @@ typedef struct
char configstrings[MAX_CONFIGSTRINGS][CS_SIZE];
char physinfo[MAX_INFO_STRING]; // physics info string
entity_state_t entity_curstates[MAX_PARSE_ENTITIES];
entity_state_t entity_curstates[MAX_PARSE_ENTITIES]; // FIXME: this is must match with GI->max_edicts
// locally derived information from server state
model_t models[MAX_MODELS];

View File

@ -232,6 +232,8 @@ bool SV_GetComment( const char *savename, char *comment );
bool SV_NewGame( const char *mapName, bool loadGame );
bool SV_LoadProgs( const char *name );
void SV_ForceMod( void );
void SV_ForceError( void );
void CL_WriteMessageHistory( void );
void CL_MouseEvent( int mx, int my );
void CL_AddLoopingSounds( void );
void CL_Disconnect( void );

View File

@ -1,520 +0,0 @@
//=======================================================================
// Copyright XashXT Group 2008 ©
// com_library.c - custom dlls loader
//=======================================================================
#include "common.h"
#include "com_library.h"
// FIXME: broken code
//#define EXPORT_FROM_MEMORY
typedef struct
{
PIMAGE_NT_HEADERS headers;
byte *codeBase;
void **modules;
int numModules;
int initialized;
} MEMORYMODULE, *PMEMORYMODULE;
typedef BOOL (WINAPI *DllEntryProc)( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved );
#define GET_HEADER_DICTIONARY( module, idx ) &(module)->headers->OptionalHeader.DataDirectory[idx]
#define CALCULATE_ADDRESS( base, offset ) (((DWORD)(base)) + (offset))
static void CopySections( const byte *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
{
int i, size;
byte *dest;
byte *codeBase = module->codeBase;
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ )
{
if( section->SizeOfRawData == 0 )
{
// section doesn't contain data in the dll itself, but may define
// uninitialized data
size = old_headers->OptionalHeader.SectionAlignment;
if( size > 0 )
{
dest = (byte *)VirtualAlloc((byte *)CALCULATE_ADDRESS(codeBase, section->VirtualAddress), size, MEM_COMMIT, PAGE_READWRITE );
section->Misc.PhysicalAddress = (DWORD)dest;
Mem_Set( dest, 0, size );
}
// section is empty
continue;
}
// commit memory block and copy data from dll
dest = (byte *)VirtualAlloc((byte *)CALCULATE_ADDRESS(codeBase, section->VirtualAddress), section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE );
Mem_Copy( dest, (byte *)CALCULATE_ADDRESS(data, section->PointerToRawData), section->SizeOfRawData );
section->Misc.PhysicalAddress = (DWORD)dest;
}
}
static void FreeSections( PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
{
int i, size;
byte *codeBase = module->codeBase;
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ )
{
if( section->SizeOfRawData == 0 )
{
size = old_headers->OptionalHeader.SectionAlignment;
if( size > 0 )
{
VirtualFree( codeBase + section->VirtualAddress, size, MEM_DECOMMIT );
section->Misc.PhysicalAddress = 0;
}
continue;
}
VirtualFree( codeBase + section->VirtualAddress, section->SizeOfRawData, MEM_DECOMMIT );
section->Misc.PhysicalAddress = 0;
}
}
// Protection flags for memory pages (Executable, Readable, Writeable)
static int ProtectionFlags[2][2][2] =
{
{
{ PAGE_NOACCESS, PAGE_WRITECOPY }, // not executable
{ PAGE_READONLY, PAGE_READWRITE },
},
{
{ PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY }, // executable
{ PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE },
},
};
static void FinalizeSections( MEMORYMODULE *module )
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION( module->headers );
int i;
// loop through all sections and change access flags
for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ )
{
DWORD protect, oldProtect, size;
int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0;
int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
if( section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE )
{
// section is not needed any more and can safely be freed
VirtualFree((LPVOID)section->Misc.PhysicalAddress, section->SizeOfRawData, MEM_DECOMMIT);
continue;
}
// determine protection flags based on characteristics
protect = ProtectionFlags[executable][readable][writeable];
if( section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED )
protect |= PAGE_NOCACHE;
// determine size of region
size = section->SizeOfRawData;
if( size == 0 )
{
if( section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA )
size = module->headers->OptionalHeader.SizeOfInitializedData;
else if( section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA )
size = module->headers->OptionalHeader.SizeOfUninitializedData;
}
if( size > 0 )
{
// change memory access flags
if( !VirtualProtect((LPVOID)section->Misc.PhysicalAddress, size, protect, &oldProtect ))
Host_Error( "Com_FinalizeSections: error protecting memory page\n" );
}
}
}
static void PerformBaseRelocation( MEMORYMODULE *module, DWORD delta )
{
DWORD i;
byte *codeBase = module->codeBase;
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_BASERELOC );
if( directory->Size > 0 )
{
PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION)CALCULATE_ADDRESS( codeBase, directory->VirtualAddress );
for( ; relocation->VirtualAddress > 0; )
{
byte *dest = (byte *)CALCULATE_ADDRESS( codeBase, relocation->VirtualAddress );
word *relInfo = (word *)((byte *)relocation + IMAGE_SIZEOF_BASE_RELOCATION );
for( i = 0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++ )
{
DWORD *patchAddrHL;
int type, offset;
// the upper 4 bits define the type of relocation
type = *relInfo >> 12;
// the lower 12 bits define the offset
offset = *relInfo & 0xfff;
switch( type )
{
case IMAGE_REL_BASED_ABSOLUTE:
// skip relocation
break;
case IMAGE_REL_BASED_HIGHLOW:
// change complete 32 bit address
patchAddrHL = (DWORD *)CALCULATE_ADDRESS( dest, offset );
*patchAddrHL += delta;
break;
default:
MsgDev( D_ERROR, "PerformBaseRelocation: unknown relocation: %d\n", type );
break;
}
}
// advance to next relocation block
relocation = (PIMAGE_BASE_RELOCATION)CALCULATE_ADDRESS( relocation, relocation->SizeOfBlock );
}
}
}
static int BuildImportTable( MEMORYMODULE *module )
{
int result=1;
byte *codeBase = module->codeBase;
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_IMPORT );
if( directory->Size > 0 )
{
PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR)CALCULATE_ADDRESS( codeBase, directory->VirtualAddress );
for( ; !IsBadReadPtr( importDesc, sizeof( IMAGE_IMPORT_DESCRIPTOR )) && importDesc->Name; importDesc++ )
{
DWORD *thunkRef, *funcRef;
void *handle;
#ifdef EXPORT_FROM_MEMORY
char libpath[MAX_SYSPATH];
FS_AllowDirectPaths( true );
Com_BuildPath((LPCSTR)CALCULATE_ADDRESS(codeBase, importDesc->Name), libpath );
handle = Com_LoadLibrary( libpath );
FS_AllowDirectPaths( false );
#else
handle = LoadLibrary((LPCSTR)CALCULATE_ADDRESS(codeBase, importDesc->Name));
#endif
if( handle == NULL )
{
MsgDev( D_ERROR, "couldn't load library\n" );
result = 0;
break;
}
module->modules = (void *)Z_Realloc( module->modules, (module->numModules + 1) * (sizeof( void* )));
if( module->modules == NULL )
{
result = 0;
break;
}
module->modules[module->numModules++] = handle;
if( importDesc->OriginalFirstThunk )
{
thunkRef = (DWORD *)CALCULATE_ADDRESS( codeBase, importDesc->OriginalFirstThunk );
funcRef = (DWORD *)CALCULATE_ADDRESS( codeBase, importDesc->FirstThunk );
}
else
{
// no hint table
thunkRef = (DWORD *)CALCULATE_ADDRESS( codeBase, importDesc->FirstThunk );
funcRef = (DWORD *)CALCULATE_ADDRESS( codeBase, importDesc->FirstThunk );
}
for( ; *thunkRef; thunkRef++, funcRef++ )
{
if( IMAGE_SNAP_BY_ORDINAL( *thunkRef ))
{
#ifdef EXPORT_FROM_MEMORY
*funcRef = (DWORD)Com_GetProcAddress( handle, (LPCSTR)IMAGE_ORDINAL( *thunkRef ));
#else
*funcRef = (DWORD)GetProcAddress( handle, (LPCSTR)IMAGE_ORDINAL( *thunkRef ));
#endif
}
else
{
PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME)CALCULATE_ADDRESS( codeBase, *thunkRef );
#ifdef EXPORT_FROM_MEMORY
*funcRef = (DWORD)Com_GetProcAddress( handle, (LPCSTR)&thunkData->Name );
#else
*funcRef = (DWORD)GetProcAddress( handle, (LPCSTR)&thunkData->Name );
#endif
}
if( *funcRef == 0 )
{
result = 0;
break;
}
}
if( !result ) break;
}
}
return result;
}
void *Com_LoadLibrary( const char *name )
{
#ifdef _DEBUG
Msg( "LoadLibrary( %s )\n", name );
return LoadLibrary( name );
#else
MEMORYMODULE *result;
PIMAGE_DOS_HEADER dos_header;
PIMAGE_NT_HEADERS old_header;
byte *code, *headers;
DWORD locationDelta;
DllEntryProc DllEntry;
string errorstring;
BOOL successfull;
void *data;
MsgDev( D_NOTE, "Sys_LoadLibrary: Loading %s", name );
data = FS_LoadFile( name, NULL );
if( !data ) return NULL;
dos_header = (PIMAGE_DOS_HEADER)data;
if( dos_header->e_magic != IMAGE_DOS_SIGNATURE )
{
MsgDev( D_NOTE, " - failed\n" );
MsgDev( D_NOTE, "%s it's not a valid executable file\n", name );
Mem_Free( data );
return NULL;
}
old_header = (PIMAGE_NT_HEADERS)&((const byte *)(data))[dos_header->e_lfanew];
if( old_header->Signature != IMAGE_NT_SIGNATURE )
{
MsgDev( D_NOTE, " - failed\n" );
MsgDev( D_NOTE, "library %s: no PE header found\n", name );
Mem_Free( data );
return NULL;
}
// reserve memory for image of library
code = (byte *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), old_header->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE );
if( code == NULL )
{
// try to allocate memory at arbitrary position
code = (byte *)VirtualAlloc( NULL, old_header->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE );
}
if( code == NULL )
{
MsgDev( D_NOTE, " - failed\n" );
MsgDev( D_NOTE, "library %s: can't reserve memory\n", name );
Mem_Free( data );
return NULL;
}
result = (MEMORYMODULE *)HeapAlloc( GetProcessHeap(), 0, sizeof( MEMORYMODULE ));
result->codeBase = code;
result->numModules = 0;
result->modules = NULL;
result->initialized = 0;
// XXX: is it correct to commit the complete memory region at once?
// calling DllEntry raises an exception if we don't...
VirtualAlloc( code, old_header->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE );
// commit memory for headers
headers = (byte *)VirtualAlloc( code, old_header->OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE );
// copy PE header to code
Mem_Copy( headers, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders );
result->headers = (PIMAGE_NT_HEADERS)&((const byte *)(headers))[dos_header->e_lfanew];
// update position
result->headers->OptionalHeader.ImageBase = (DWORD)code;
// copy sections from DLL file block to new memory location
CopySections( data, old_header, result );
// adjust base address of imported data
locationDelta = (DWORD)(code - old_header->OptionalHeader.ImageBase);
if( locationDelta != 0 ) PerformBaseRelocation( result, locationDelta );
// load required dlls and adjust function table of imports
if( !BuildImportTable( result )) goto error;
// mark memory pages depending on section headers and release
// sections that are marked as "discardable"
FinalizeSections( result );
// get entry point of loaded library
if( result->headers->OptionalHeader.AddressOfEntryPoint != 0 )
{
DllEntry = (DllEntryProc)CALCULATE_ADDRESS( code, result->headers->OptionalHeader.AddressOfEntryPoint );
if( DllEntry == 0 )
{
com.sprintf( errorstring, "library %s: has no entry point\n", name );
goto error;
}
// notify library about attaching to process
successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0 );
if( !successfull )
{
com.sprintf( errorstring, "can't attach library %s\n", name );
goto error;
}
result->initialized = 1;
}
Mem_Free( data ); // release memory
MsgDev( D_NOTE, " - ok\n" );
return (void *)result;
error:
// cleanup
MsgDev( D_NOTE, " - failed\n" );
Mem_Free( data );
Com_FreeLibrary( result );
MsgDev( D_ERROR, errorstring );
return NULL;
#endif
}
FARPROC Com_GetProcAddress( void *module, const char *name )
{
#ifdef _DEBUG
return GetProcAddress( module, name );
#else
int idx = -1;
DWORD i, *nameRef;
WORD *ordinal;
PIMAGE_EXPORT_DIRECTORY exports;
byte *codeBase = ((PMEMORYMODULE)module)->codeBase;
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((MEMORYMODULE *)module, IMAGE_DIRECTORY_ENTRY_EXPORT );
if( directory->Size == 0 )
{
// no export table found
return NULL;
}
exports = (PIMAGE_EXPORT_DIRECTORY)CALCULATE_ADDRESS( codeBase, directory->VirtualAddress );
if( exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0 )
{
// DLL doesn't export anything
return NULL;
}
// search function name in list of exported names
nameRef = (DWORD *)CALCULATE_ADDRESS( codeBase, exports->AddressOfNames );
ordinal = (WORD *)CALCULATE_ADDRESS( codeBase, exports->AddressOfNameOrdinals );
for( i = 0; i < exports->NumberOfNames; i++, nameRef++, ordinal++ )
{
// GetProcAddress case insensative ?????
if( !com.stricmp( name, (const char *)CALCULATE_ADDRESS( codeBase, *nameRef )))
{
idx = *ordinal;
break;
}
}
if( idx == -1 )
{
// exported symbol not found
return NULL;
}
if((DWORD)idx > exports->NumberOfFunctions )
{
// name <-> ordinal number don't match
return NULL;
}
// addressOfFunctions contains the RVAs to the "real" functions
return (FARPROC)CALCULATE_ADDRESS( codeBase, *(DWORD *)CALCULATE_ADDRESS( codeBase, exports->AddressOfFunctions + (idx * 4)));
#endif
}
void Com_FreeLibrary( void *hInstance )
{
#ifdef _DEBUG
FreeLibrary( hInstance );
#else
MEMORYMODULE *module = (MEMORYMODULE *)hInstance;
if( module != NULL )
{
int i;
if( module->initialized != 0 )
{
// notify library about detaching from process
DllEntryProc DllEntry = (DllEntryProc)CALCULATE_ADDRESS( module->codeBase, module->headers->OptionalHeader.AddressOfEntryPoint );
(*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0 );
module->initialized = 0;
}
if( module->modules != NULL )
{
// free previously opened libraries
for( i = 0; i < module->numModules; i++ )
{
if( module->modules[i] != NULL )
{
#ifdef EXPORT_FROM_MEMORY
Com_FreeLibrary( module->modules[i] );
#else
FreeLibrary( module->modules[i] );
#endif
}
}
Mem_Free( module->modules ); // Z_Realloc end
}
FreeSections( module->headers, module );
if( module->codeBase != NULL )
{
// release memory of library
VirtualFree( module->codeBase, 0, MEM_RELEASE );
}
HeapFree( GetProcessHeap(), 0, module );
}
#endif
}
void Com_BuildPathExt( const char *dllname, char *fullpath, size_t size )
{
string name;
if( !dllname || !fullpath || size <= 0 ) return;
// only libraries with extension .dll are valid
com.strncpy( name, dllname, sizeof( string ));
FS_FileBase( name, name );
// game path (Xash3D/game/bin/)
#ifdef _DEBUG
com.snprintf( fullpath, size, "%s/bin/%s.dll", GI->gamedir, name );
if( FS_FileTime( fullpath ) != -1 ) return;
com.snprintf( fullpath, size, "%s/bin/%s.dll", GI->basedir, name );
if( FS_FileTime( fullpath ) != -1 ) return;
// absoulte path (Xash3D/bin/)
com.snprintf( fullpath, size, "bin/%s.dll", name );
if( FS_FileTime( fullpath ) != -1 ) return; // found
#else
com.snprintf( fullpath, size, "bin/%s.dll", name );
if( FS_FileExists( fullpath )) return; // found
// absoulte path (Xash3D/bin/)
com.snprintf( fullpath, size, "%s.dll", name );
if( FS_FileExists( fullpath )) return; // found
#endif
fullpath[0] = 0;
}

View File

@ -9,7 +9,6 @@
#include "const.h"
#include "client.h"
#include "cvardef.h"
#include "com_library.h"
/*
==============
@ -460,10 +459,7 @@ pfnLoadLibrary
*/
void *pfnLoadLibrary( const char *name )
{
string libpath;
Com_BuildPath( name, libpath );
return Com_LoadLibrary( libpath );
return FS_LoadLibrary( name, false );
}
/*
@ -474,8 +470,7 @@ pfnGetProcAddress
*/
void *pfnGetProcAddress( void *hInstance, const char *name )
{
if( !hInstance ) return NULL;
return Com_GetProcAddress( hInstance, name );
return FS_GetProcAddress( hInstance, name );
}
/*
@ -486,7 +481,7 @@ pfnFreeLibrary
*/
void pfnFreeLibrary( void *hInstance )
{
Com_FreeLibrary( hInstance );
FS_FreeLibrary( hInstance );
}
/*
@ -497,9 +492,6 @@ pfnRemoveFile
*/
void pfnRemoveFile( const char *szFilename )
{
string path;
if( !szFilename || !*szFilename ) return;
com.sprintf( path, "%s/%s", GI->gamedir, szFilename );
FS_Delete( path );
FS_Delete( szFilename );
}

View File

@ -182,10 +182,6 @@ SOURCE=.\common\com_keys.c
# End Source File
# Begin Source File
SOURCE=.\common\com_library.c
# End Source File
# Begin Source File
SOURCE=.\common\com_world.c
# End Source File
# Begin Source File

View File

@ -661,6 +661,8 @@ void Host_Error( const char *error, ... )
com.vsprintf( hosterror1, error, argptr );
va_end( argptr );
CL_WriteMessageHistory (); // before com.error call
if( host.framecount < 3 || host.state == HOST_SHUTDOWN )
{
Msg( "Host_InitError: " );
@ -709,6 +711,12 @@ void Sys_Error_f( void )
com.error( "%s\n", error );
}
void Net_Error_f( void )
{
com.strncpy( host.finalmsg, Cmd_Argv( 1 ), sizeof( host.finalmsg ));
SV_ForceError();
}
/*
=================
Host_Crash_f
@ -841,6 +849,7 @@ void Host_Init( const int argc, const char **argv )
Cmd_AddCommand ( "sys_error", Sys_Error_f, "just throw a fatal error to test shutdown procedures");
Cmd_AddCommand ( "host_error", Host_Error_f, "just throw a host error to test shutdown procedures");
Cmd_AddCommand ( "crash", Host_Crash_f, "a way to force a bus error for development reasons");
Cmd_AddCommand ( "net_error", Net_Error_f, "send network bad message from random place");
}
host_cheats = Cvar_Get( "sv_cheats", "1", CVAR_SYSTEMINFO, "allow cheat variables to enable" );

View File

@ -66,7 +66,7 @@ typedef struct server_s
sizebuf_t signon;
byte signon_buf[MAX_MSGLEN];
bool autosaved;
bool write_bad_message; // just for debug
bool cphys_prepped;
bool paused;
} server_t;
@ -223,13 +223,6 @@ typedef struct
byte *temppool; // for parse, save and restore edicts
byte *mempool; // server premamnent pool: edicts etc
// library exports table
word *ordinals;
dword *funcs;
char *names[4096]; // max 4096 exports supported
int num_ordinals; // actual exports count
dword funcBase; // base offset
int hStringTable; // stringtable handle
SAVERESTOREDATA SaveData; // shared struct, used for save data
} svgame_static_t;

View File

@ -1251,6 +1251,17 @@ void _MSG_Send( int dest, const vec3_t origin, const edict_t *ent, bool direct,
else MSG_WriteData( &cl->datagram, sv.multicast.data, sv.multicast.cursize );
}
MSG_Clear( &sv.multicast );
// 25% chanse for simulate random network bugs
if( sv.write_bad_message && Com_RandomLong( 0, 32 ) <= 8 )
{
// just for network debugging (send only for local client)
MSG_WriteByte( &sv.multicast, svc_bad );
MSG_WriteLong( &sv.multicast, rand( )); // send some random data
MSG_WriteString( &sv.multicast, host.finalmsg ); // send final message
MSG_Send( MSG_ALL, vec3_origin, NULL );
sv.write_bad_message = false;
}
}
/*

View File

@ -326,8 +326,8 @@ void SV_DeleteSave_f( void )
}
// delete save and saveshot
FS_Delete( va( "%s/save/%s.sav", GI->gamedir, Cmd_Argv( 1 )));
FS_Delete( va( "%s/save/%s.%s", GI->gamedir, Cmd_Argv( 1 ), SI->savshot_ext ));
FS_Delete( va( "save/%s.sav", Cmd_Argv( 1 )));
FS_Delete( va( "save/%s.%s", Cmd_Argv( 1 ), SI->savshot_ext ));
}
/*

View File

@ -8,304 +8,9 @@
#include "net_sound.h"
#include "byteorder.h"
#include "matrix_lib.h"
#include "com_library.h"
#include "pm_defs.h"
#include "const.h"
void Sys_FsGetString( file_t *f, char *str )
{
char ch;
while(( ch = FS_Getc( f )) != EOF )
{
*str++ = ch;
if( !ch ) break;
}
}
void Sys_FreeNameFuncGlobals( void )
{
int i;
if( svgame.ordinals ) Mem_Free( svgame.ordinals );
if( svgame.funcs ) Mem_Free( svgame.funcs );
for( i = 0; i < svgame.num_ordinals; i++ )
{
if( svgame.names[i] )
Mem_Free( svgame.names[i] );
}
svgame.num_ordinals = 0;
svgame.ordinals = NULL;
svgame.funcs = NULL;
}
char *Sys_GetMSVCName( const char *in_name )
{
char *pos, *out_name;
if( in_name[0] == '?' ) // is this a MSVC C++ mangled name?
{
if(( pos = com.strstr( in_name, "@@" )) != NULL )
{
int len = pos - in_name;
// strip off the leading '?'
out_name = com.stralloc( svgame.private, in_name + 1, __FILE__, __LINE__ );
out_name[len-1] = 0; // terminate string at the "@@"
return out_name;
}
}
return com.stralloc( svgame.private, in_name, __FILE__, __LINE__ );
}
bool Sys_LoadSymbols( const char *name )
{
file_t *f;
DOS_HEADER dos_header;
LONG nt_signature;
PE_HEADER pe_header;
SECTION_HEADER section_header;
bool edata_found;
OPTIONAL_HEADER optional_header;
long edata_offset;
long edata_delta;
EXPORT_DIRECTORY export_directory;
long name_offset;
long ordinal_offset;
long function_offset;
string filename, function_name;
dword *p_Names = NULL;
int i, index;
// try game path
com.sprintf( filename, "bin/%s.dll", name );
if( !FS_FileExists( filename ))
{
// try absoulte path
com.sprintf( filename, "%s.dll", name );
}
for( i = 0; i < svgame.num_ordinals; i++ )
svgame.names[i] = NULL;
f = FS_Open( filename, "rb" );
if( !f )
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s not found\n", filename );
return false;
}
if( FS_Read( f, &dos_header, sizeof( dos_header )) != sizeof( dos_header ))
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s has corrupted EXE header\n", filename );
FS_Close( f );
return false;
}
if( dos_header.e_magic != DOS_SIGNATURE )
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid dll signature\n", filename );
FS_Close( f );
return false;
}
if( FS_Seek( f, dos_header.e_lfanew, SEEK_SET ) == -1 )
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s error seeking to new exe header\n", filename );
FS_Close( f );
return false;
}
if( FS_Read( f, &nt_signature, sizeof( nt_signature )) != sizeof( nt_signature ))
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s has corrupted NT header\n", filename );
FS_Close( f );
return false;
}
if( nt_signature != NT_SIGNATURE )
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid NT signature\n", filename );
FS_Close( f );
return false;
}
if( FS_Read( f, &pe_header, sizeof( pe_header )) != sizeof( pe_header ))
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid PE header\n", filename );
FS_Close( f );
return false;
}
if( !pe_header.SizeOfOptionalHeader )
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have an optional header\n", filename );
FS_Close( f );
return false;
}
if( FS_Read( f, &optional_header, sizeof( optional_header )) != sizeof( optional_header ))
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s optional header probably corrupted\n", filename );
FS_Close( f );
return false;
}
edata_found = false;
for( i = 0; i < pe_header.NumberOfSections; i++ )
{
if( FS_Read( f, &section_header, sizeof( section_header )) != sizeof( section_header ))
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s error during reading section header\n", filename );
FS_Close( f );
return false;
}
if( !com.strcmp((char *)section_header.Name, ".edata" ))
{
edata_found = true;
break;
}
}
if( edata_found )
{
edata_offset = section_header.PointerToRawData;
edata_delta = section_header.VirtualAddress - section_header.PointerToRawData;
}
else
{
edata_offset = optional_header.DataDirectory[0].VirtualAddress;
edata_delta = 0;
}
if( FS_Seek( f, edata_offset, SEEK_SET ) == -1 )
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid exports section\n", filename );
FS_Close( f );
return false;
}
if( FS_Read( f, &export_directory, sizeof( export_directory )) != sizeof( export_directory ))
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid optional header\n", filename );
FS_Close( f );
return false;
}
svgame.num_ordinals = export_directory.NumberOfNames; // also number of ordinals
if( svgame.num_ordinals > 4096 )
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s too many exports\n", filename );
FS_Close( f );
return false;
}
ordinal_offset = export_directory.AddressOfNameOrdinals - edata_delta;
if( FS_Seek( f, ordinal_offset, SEEK_SET ) == -1 )
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid ordinals section\n", filename );
FS_Close( f );
return false;
}
svgame.ordinals = Mem_Alloc( svgame.private, svgame.num_ordinals * sizeof( word ));
if( FS_Read( f, svgame.ordinals, svgame.num_ordinals * sizeof( word )) != (svgame.num_ordinals * sizeof( word )))
{
Sys_FreeNameFuncGlobals();
MsgDev( D_ERROR, "Sys_LoadSymbols: %s error during reading ordinals table\n", filename );
FS_Close( f );
return false;
}
function_offset = export_directory.AddressOfFunctions - edata_delta;
if( FS_Seek( f, function_offset, SEEK_SET ) == -1 )
{
MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid export address section\n", filename );
FS_Close( f );
return false;
}
svgame.funcs = Mem_Alloc( svgame.private, svgame.num_ordinals * sizeof( dword ));
if( FS_Read( f, svgame.funcs, svgame.num_ordinals * sizeof( dword )) != (svgame.num_ordinals * sizeof( dword )))
{
Sys_FreeNameFuncGlobals();
MsgDev( D_ERROR, "Sys_LoadSymbols: %s error during reading export address section\n", filename );
FS_Close( f );
return false;
}
name_offset = export_directory.AddressOfNames - edata_delta;
if( FS_Seek( f, name_offset, SEEK_SET ) == -1 )
{
Sys_FreeNameFuncGlobals();
MsgDev( D_ERROR, "Sys_LoadSymbols: %s file does not have a valid names section\n", filename );
FS_Close( f );
return false;
}
p_Names = Mem_Alloc( svgame.private, svgame.num_ordinals * sizeof( dword ));
if( FS_Read( f, p_Names, svgame.num_ordinals * sizeof( dword )) != (svgame.num_ordinals * sizeof( dword )))
{
Sys_FreeNameFuncGlobals();
if( p_Names ) Mem_Free( p_Names );
MsgDev( D_ERROR, "Sys_LoadSymbols: %s error during reading names table\n", filename );
FS_Close( f );
return false;
}
for( i = 0; i < svgame.num_ordinals; i++ )
{
name_offset = p_Names[i] - edata_delta;
if( name_offset != 0 )
{
if( FS_Seek( f, name_offset, SEEK_SET ) != -1 )
{
Sys_FsGetString( f, function_name );
svgame.names[i] = Sys_GetMSVCName( function_name );
}
else break;
}
}
if( i != svgame.num_ordinals )
{
Sys_FreeNameFuncGlobals();
if( p_Names ) Mem_Free( p_Names );
MsgDev( D_ERROR, "Sys_LoadSymbols: %s error during loading names section\n", filename );
FS_Close( f );
return false;
}
FS_Close( f );
for( i = 0; i < svgame.num_ordinals; i++ )
{
if( !com.strcmp( "CreateAPI", svgame.names[i] ))
{
void *fn_offset;
index = svgame.ordinals[i];
fn_offset = (void *)Com_GetProcAddress( svgame.hInstance, "CreateAPI" );
svgame.funcBase = (dword)(fn_offset) - svgame.funcs[index];
break;
}
}
if( p_Names ) Mem_Free( p_Names );
return true;
}
void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max )
{
int i;
@ -645,7 +350,7 @@ edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
VectorSet( ent->v.rendercolor, 255, 255, 255 ); // assume default color
// allocate edict private memory (passed by dlls)
SpawnEdict = (LINK_ENTITY_FUNC)Com_GetProcAddress( svgame.hInstance, pszClassName );
SpawnEdict = (LINK_ENTITY_FUNC)FS_GetProcAddress( svgame.hInstance, pszClassName );
if( !SpawnEdict )
{
// attempt to create custom entity
@ -2505,19 +2210,7 @@ pfnFunctionFromName
*/
dword pfnFunctionFromName( const char *pName )
{
int i, index;
for( i = 0; i < svgame.num_ordinals; i++ )
{
if( !com.strcmp( pName, svgame.names[i] ))
{
index = svgame.ordinals[i];
return svgame.funcs[index] + svgame.funcBase;
}
}
// couldn't find the function name to return address
return 0;
return FS_FunctionFromName( svgame.hInstance, pName );
}
/*
@ -2528,18 +2221,7 @@ pfnNameForFunction
*/
const char *pfnNameForFunction( dword function )
{
int i, index;
for( i = 0; i < svgame.num_ordinals; i++ )
{
index = svgame.ordinals[i];
if((function - svgame.funcBase) == svgame.funcs[index] )
return svgame.names[i];
}
// couldn't find the function address to return name
return NULL;
return FS_NameForFunction( svgame.hInstance, function );
}
/*
@ -2743,9 +2425,8 @@ int pfnCompareFileTime( const char *filename1, const char *filename2, int *iComp
if( filename1 && filename2 )
{
// FIXME: rewrite FS_FileTime
long ft1 = FS_FileTime( va( "%s/%s", GI->gamedir, filename1 ));
long ft2 = FS_FileTime( va( "%s/%s", GI->gamedir, filename2 ));
long ft1 = FS_FileTime( filename1 );
long ft2 = FS_FileTime( filename2 );
*iCompare = Host_CompareFileTime( ft1, ft2 );
bRet = 1;
@ -3816,13 +3497,10 @@ void SV_UnloadProgs( void )
svgame.dllFuncs.pfnGameShutdown ();
StringTable_Delete( svgame.hStringTable );
Sys_FreeNameFuncGlobals ();
Com_FreeLibrary( svgame.hInstance );
FS_FreeLibrary( svgame.hInstance );
Mem_FreePool( &svgame.mempool );
Mem_FreePool( &svgame.private );
Mem_FreePool( &svgame.temppool );
svgame.hInstance = NULL;
Mem_Set( &svgame, 0, sizeof( svgame ));
}
@ -3831,7 +3509,6 @@ bool SV_LoadProgs( const char *name )
static SERVERAPI GetEntityAPI;
static globalvars_t gpGlobals;
static playermove_t gpMove;
string libpath;
edict_t *e;
int i;
@ -3840,11 +3517,10 @@ bool SV_LoadProgs( const char *name )
// fill it in
svgame.pmove = &gpMove;
svgame.globals = &gpGlobals;
Com_BuildPath( name, libpath );
svgame.mempool = Mem_AllocPool( "Server Edicts Zone" );
svgame.private = Mem_AllocPool( "Server Private Zone" );
svgame.temppool = Mem_AllocPool( "Server Temp Strings" );
svgame.hInstance = Com_LoadLibrary( libpath );
svgame.hInstance = FS_LoadLibrary( name, true );
if( !svgame.hInstance )
{
@ -3852,19 +3528,14 @@ bool SV_LoadProgs( const char *name )
return false;
}
GetEntityAPI = (SERVERAPI)Com_GetProcAddress( svgame.hInstance, "CreateAPI" );
GetEntityAPI = (SERVERAPI)FS_GetProcAddress( svgame.hInstance, "CreateAPI" );
if( !GetEntityAPI )
{
MsgDev( D_ERROR, "SV_LoadProgs: failed to get address of CreateAPI proc\n" );
return false;
}
if( !Sys_LoadSymbols( name ))
{
MsgDev( D_ERROR, "SV_LoadProgs: can't loading export symbols\n" );
return false;
}
if( !GetEntityAPI( &svgame.dllFuncs, &gEngfuncs, svgame.globals ))
{
MsgDev( D_ERROR, "SV_LoadProgs: couldn't get entity API\n" );

View File

@ -393,7 +393,7 @@ void SV_InitGame( void )
// init game after host error
if( !svgame.hInstance )
{
if( !SV_LoadProgs( "server" ))
if( !SV_LoadProgs( "server.dll" ))
return; // can't loading
}
@ -484,6 +484,13 @@ void SV_ForceMod( void )
sv.cphys_prepped = false;
}
void SV_ForceError( void )
{
// this only for singleplayer testing
if( sv_maxclients->integer != 1 ) return;
sv.write_bad_message = true;
}
bool SV_NewGame( const char *mapName, bool loadGame )
{
if( !loadGame )

View File

@ -358,7 +358,7 @@ void SV_ReadComment( wfile_t *l )
game_header_t ghdr;
// init the game to get acess for read funcs
if( !svgame.hInstance ) SV_LoadProgs( "server" );
if( !svgame.hInstance ) SV_LoadProgs( "server.dll" );
// initialize SAVERESTOREDATA
Mem_Set( &svgame.SaveData, 0, sizeof( SAVERESTOREDATA ));

View File

@ -361,7 +361,6 @@ int EntityInSolid( edict_t *ent )
void SV_ClearSaveDir( void )
{
string path;
search_t *t;
int i;
@ -371,8 +370,7 @@ void SV_ClearSaveDir( void )
for( i = 0; i < t->numfilenames; i++ )
{
com.sprintf( path, "%s/%s", GI->gamedir, t->filenames[i] );
FS_Delete( path );
FS_Delete( t->filenames[i] );
}
Mem_Free( t );
}
@ -426,8 +424,8 @@ void SV_AgeSaveList( const char *pName, int count )
string newName, oldName, newImage, oldImage;
// delete last quick/autosave (e.g. quick05.sav)
com.snprintf( newName, sizeof( newName ), "%s/save/%s%02d.sav", GI->gamedir, pName, count );
com.snprintf( newImage, sizeof( newImage ), "%s/save/%s%02d.%s", GI->gamedir, pName, count, SI->savshot_ext );
com.snprintf( newName, sizeof( newName ), "save/%s%02d.sav", pName, count );
com.snprintf( newImage, sizeof( newImage ), "save/%s%02d.%s", pName, count, SI->savshot_ext );
// only delete from game directory, basedir is read-only
FS_Delete( newName );
@ -438,23 +436,22 @@ void SV_AgeSaveList( const char *pName, int count )
if( count == 1 )
{
// quick.sav
com.snprintf( oldName, sizeof( oldName ), "%s/save/%s.sav", GI->gamedir, pName );
com.snprintf( oldImage, sizeof( oldImage ), "%s/save/%s.%s", GI->gamedir, pName, SI->savshot_ext );
com.snprintf( oldName, sizeof( oldName ), "save/%s.sav", pName );
com.snprintf( oldImage, sizeof( oldImage ), "save/%s.%s", pName, SI->savshot_ext );
}
else
{
// quick04.sav, etc.
com.snprintf( oldName, sizeof( oldName ), "%s/save/%s%02d.sav", GI->gamedir, pName, count - 1 );
com.snprintf( oldImage, sizeof( oldImage ), "%s/save/%s%02d.%s", GI->gamedir, pName, count - 1, SI->savshot_ext );
com.snprintf( oldName, sizeof( oldName ), "save/%s%02d.sav", pName, count - 1 );
com.snprintf( oldImage, sizeof( oldImage ), "save/%s%02d.%s", pName, count - 1, SI->savshot_ext );
}
com.snprintf( newName, sizeof( newName ), "%s/save/%s%02d.sav", GI->gamedir, pName, count );
com.snprintf( newImage, sizeof( newImage ), "%s/save/%s%02d.%s", GI->gamedir, pName, count, SI->savshot_ext );
// Scroll the name list down (rename quick04.sav to quick05.sav)
com.snprintf( newName, sizeof( newName ), "save/%s%02d.sav", pName, count );
com.snprintf( newImage, sizeof( newImage ), "save/%s%02d.%s", pName, count, SI->savshot_ext );
// FIXME: create FS_Rename
rename( oldName, newName );
rename( oldImage, newImage );
// Scroll the name list down (rename quick04.sav to quick05.sav)
FS_Rename( oldName, newName );
FS_Rename( oldImage, newImage );
count--;
}
}
@ -1524,9 +1521,9 @@ void SV_SaveGame( const char *pName )
// make sure what oldsave is removed
if( FS_FileExists( va( "save/%s.sav", savename )))
FS_Delete( va( "%s/save/%s.sav", GI->gamedir, savename ));
FS_Delete( va( "save/%s.sav", savename ));
if( FS_FileExists( va( "save/%s.%s", savename, SI->savshot_ext )))
FS_Delete( va( "%s/save/%s.%s", GI->gamedir, savename, SI->savshot_ext ));
FS_Delete( va( "save/%s.%s", savename, SI->savshot_ext ));
SV_BuildSaveComment( comment, sizeof( comment ));
SV_SaveGameSlot( savename, comment );
@ -1555,7 +1552,7 @@ const char *SV_GetLatestSave( void )
for( i = 0; i < f->numfilenames; i++ )
{
ft = FS_FileTime( va( "%s/%s", GI->gamedir, f->filenames[i] ));
ft = FS_FileTime( f->filenames[i] );
// found a match?
if( ft > 0 )
@ -1714,7 +1711,7 @@ bool SV_GetComment( const char *savename, char *comment )
const struct tm *file_tm;
string timestring;
fileTime = FS_FileTime( va( "%s/%s", GI->gamedir, savename ));
fileTime = FS_FileTime( savename );
file_tm = localtime( &fileTime );
// split comment to sections

View File

@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "common.h"
#include "com_library.h"
#include "ui_local.h"
#include "client.h"
@ -278,7 +277,7 @@ static void UI_LanGame_Init( void )
uiLanGame.gameList.itemNames = uiLanGame.gameDescriptionPtr;
// server.dll needs for reading savefiles or startup newgame
Com_BuildPath( "server", libpath );
UI_BuildPath( "server", libpath );
if( !FS_FileExists( libpath ))
uiLanGame.createGame.generic.flags |= QMF_GRAYED; // server.dll is missed - remote servers only

View File

@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "common.h"
#include "com_library.h"
#include "ui_local.h"
#include "input.h"
#include "client.h"
@ -439,7 +438,7 @@ void UI_LoadGame_Menu( void )
return;
}
Com_BuildPath( "server", libpath );
UI_BuildPath( "server", libpath );
if( !FS_FileExists( libpath )) return;
UI_LoadGame_Precache();

View File

@ -350,6 +350,8 @@ void UI_FillRect( int x, int y, int w, int h, const rgba_t color );
void UI_DrawRectangleExt( int in_x, int in_y, int in_w, int in_h, const rgba_t color, int outlineWidth );
#define UI_DrawString( x, y, w, h, str, col, fcol, cw, ch, j, s ) UI_DrawStringExt( x, y, w, h, str, col, fcol, cw, ch, j, s, uiStatic.menuFont )
void UI_DrawStringExt( int x, int y, int w, int h, const char *str, const rgba_t col, bool forceCol, int charW, int charH, int justify, bool shadow, shader_t font );
#define UI_BuildPath( a, b ) UI_BuildPathExt( a, b, sizeof( b ))
void UI_BuildPathExt( const char *dllname, char *fullpath, size_t size );
void UI_StartSound( const char *sound );
void UI_AddItem ( menuFramework_s *menu, void *item );

View File

@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "common.h"
#include "com_library.h"
#include "ui_local.h"
#include "input.h"
#include "client.h"
@ -347,7 +346,7 @@ static void UI_Main_Init( void )
uiMain.saveRestore.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
// server.dll needs for reading savefiles or startup newgame
Com_BuildPath( "server", libpath );
UI_BuildPath( "server", libpath );
if( !FS_FileExists( libpath ))
{
uiMain.saveRestore.generic.flags |= QMF_GRAYED;

View File

@ -309,6 +309,33 @@ void UI_StartSound( const char *sound )
S_StartLocalSound( sound, 1.0f, 100.0f, vec3_origin );
}
/*
=================
UI_BuildPathExt
helper to search dlls
=================
*/
void UI_BuildPathExt( const char *dllname, char *fullpath, size_t size )
{
string name;
if( !dllname || !fullpath || size <= 0 ) return;
// only libraries with extension .dll are valid
com.strncpy( name, dllname, sizeof( string ));
FS_FileBase( name, name );
// game path (Xash3D/game/bin/)
com.snprintf( fullpath, size, "bin/%s.dll", name );
if( FS_FileExists( fullpath )) return; // found
// absoulte path (Xash3D/bin/)
com.snprintf( fullpath, size, "%s.dll", name );
if( FS_FileExists( fullpath )) return; // found
fullpath[0] = 0;
}
// =====================================================================

View File

@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "common.h"
#include "com_library.h"
#include "ui_local.h"
#include "input.h"
#include "client.h"

View File

@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "common.h"
#include "com_library.h"
#include "ui_local.h"
#include "input.h"
#include "client.h"
@ -468,7 +467,7 @@ void UI_RecDemo_Menu( void )
{
string libpath;
Com_BuildPath( "server", libpath );
UI_BuildPath( "server", libpath );
if( !FS_FileExists( libpath )) return;
UI_RecDemo_Precache();

View File

@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "common.h"
#include "com_library.h"
#include "ui_local.h"
#include "input.h"
#include "client.h"
@ -460,7 +459,7 @@ void UI_SaveGame_Menu( void )
return;
}
Com_BuildPath( "server", libpath );
UI_BuildPath( "server", libpath );
if( !FS_FileExists( libpath )) return;
UI_SaveGame_Precache();

View File

@ -7,6 +7,7 @@
#include "qfiles_ref.h"
#include "filesystem.h"
#include "byteorder.h"
#include "library.h"
#include "mathlib.h"
#define ZIP_END_CDIR_SIZE 22
@ -43,7 +44,7 @@ typedef struct wadtype_s
char type;
} wadtype_t;
struct file_s
typedef struct file_s
{
int flags;
int handle; // file descriptor
@ -51,6 +52,7 @@ struct file_s
fs_offset_t position; // current position in the file
fs_offset_t offset; // offset into the package (0 if external file)
int ungetc; // single stored character from ungetc, cleared to EOF when read
time_t filetime; // pak, wad or real filetime
// Contents buffer
fs_offset_t buff_ind, buff_len; // buffer current index and length
byte buff [FILE_BUFF_SIZE];
@ -78,6 +80,7 @@ typedef struct wfile_s
int mode;
file_t *file;
dlumpinfo_t *lumps;
time_t filetime;
};
typedef struct packfile_s
@ -95,6 +98,7 @@ typedef struct pack_s
int handle;
int numfiles;
packfile_t *files;
time_t filetime; // common for all packed files
} pack_t;
typedef struct searchpath_s
@ -111,12 +115,13 @@ searchpath_t *fs_searchpaths = NULL;
searchpath_t fs_directpath; // static direct path
static void FS_InitMemory( void );
const char *FS_FileExtension (const char *in);
const char *FS_FileExtension( const char *in );
static searchpath_t *FS_FindFile (const char *name, int *index, bool quiet );
static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char matchtype );
static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, fs_offset_t offset, fs_offset_t packsize, fs_offset_t realsize, int flags);
static byte *W_LoadFile( const char *path, fs_offset_t *filesizeptr );
static bool FS_SysFileExists (const char *path);
static bool FS_SysFileExists( const char *path );
static long FS_SysFileTime( const char *filename );
static char W_TypeFromExt( const char *lumpname );
static const char *W_ExtFromType( char lumptype );
@ -304,44 +309,45 @@ FS_LoadPackPK3
Create a package entry associated with a PK3 file
====================
*/
pack_t *FS_LoadPackPK3 (const char *packfile)
pack_t *FS_LoadPackPK3( const char *packfile )
{
int packhandle;
dpak3file_t eocd;
pack_t *pack;
int real_nb_files;
int packhandle;
int real_nb_files;
dpak3file_t eocd;
pack_t *pack;
packhandle = open(packfile, O_RDONLY | O_BINARY);
if (packhandle < 0) return NULL;
packhandle = open( packfile, O_RDONLY|O_BINARY );
if( packhandle < 0 ) return NULL;
if (!PK3_GetEndOfCentralDir (packfile, packhandle, &eocd))
if( !PK3_GetEndOfCentralDir( packfile, packhandle, &eocd ))
{
Msg("%s is not a PK3 file\n", packfile);
close(packhandle);
MsgDev( D_NOTE, "%s is not a PK3 file\n", packfile );
close( packhandle );
return NULL;
}
// Multi-volume ZIP archives are NOT allowed
if (eocd.disknum != 0 || eocd.cdir_disknum != 0)
// multi-volume ZIP archives are NOT allowed
if( eocd.disknum != 0 || eocd.cdir_disknum != 0 )
{
Msg("%s is a multi-volume ZIP archive\n", packfile);
close(packhandle);
MsgDev( D_NOTE, "%s is a multi-volume ZIP archive. Ignored.\n", packfile );
close( packhandle );
return NULL;
}
// Create a package structure in memory
pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof( pack_t ));
pack = (pack_t *)Mem_Alloc( fs_mempool, sizeof( pack_t ));
com.strncpy( pack->filename, packfile, sizeof( pack->filename ));
pack->handle = packhandle;
pack->numfiles = eocd.nbentries;
pack->files = (packfile_t *)Mem_Alloc( fs_mempool, eocd.nbentries * sizeof( packfile_t ));
pack->filetime = FS_SysFileTime( packfile );
real_nb_files = PK3_BuildFileList (pack, &eocd);
if (real_nb_files < 0)
real_nb_files = PK3_BuildFileList( pack, &eocd );
if( real_nb_files < 0 )
{
Msg("%s is not a valid PK3 file\n", packfile);
close(pack->handle);
Mem_Free(pack);
MsgDev( D_ERROR, "%s is not a valid PK3 file\n", packfile );
close( pack->handle );
Mem_Free( pack );
return NULL;
}
@ -714,64 +720,67 @@ Loads the header and directory, adding the files at the beginning
of the list so they override previous pack files.
=================
*/
pack_t *FS_LoadPackPAK(const char *packfile)
pack_t *FS_LoadPackPAK( const char *packfile )
{
dpackheader_t header;
int i, numpackfiles;
int packhandle;
pack_t *pack;
dpackfile_t *info;
dpackheader_t header;
int i, numpackfiles;
int packhandle;
pack_t *pack;
dpackfile_t *info;
packhandle = open (packfile, O_RDONLY | O_BINARY);
if (packhandle < 0) return NULL;
read (packhandle, (void *)&header, sizeof(header));
if(header.ident != IDPACKV1HEADER)
packhandle = open( packfile, O_RDONLY|O_BINARY );
if( packhandle < 0 ) return NULL;
read( packhandle, (void *)&header, sizeof( header ));
if( header.ident != IDPACKV1HEADER )
{
Msg("%s is not a packfile\n", packfile);
close(packhandle);
MsgDev( D_NOTE, "%s is not a packfile. Ignored.\n", packfile );
close( packhandle );
return NULL;
}
header.dirofs = LittleLong (header.dirofs);
header.dirlen = LittleLong (header.dirlen);
header.dirofs = LittleLong( header.dirofs );
header.dirlen = LittleLong( header.dirlen );
if (header.dirlen % sizeof(dpackfile_t))
if( header.dirlen % sizeof( dpackfile_t ))
{
Msg("%s has an invalid directory size\n", packfile);
close(packhandle);
MsgDev( D_ERROR, "%s has an invalid directory size. Ignored.\n", packfile );
close( packhandle );
return NULL;
}
numpackfiles = header.dirlen / sizeof(dpackfile_t);
numpackfiles = header.dirlen / sizeof( dpackfile_t );
if (numpackfiles > MAX_FILES_IN_PACK)
if( numpackfiles > MAX_FILES_IN_PACK )
{
Msg("%s has %i files\n", packfile, numpackfiles);
close(packhandle);
MsgDev( D_ERROR, "%s has too many files ( %i ). Ignored.\n", packfile, numpackfiles );
close( packhandle );
return NULL;
}
info = (dpackfile_t *)Mem_Alloc( fs_mempool, sizeof(*info) * numpackfiles);
lseek (packhandle, header.dirofs, SEEK_SET);
if(header.dirlen != read (packhandle, (void *)info, header.dirlen))
info = (dpackfile_t *)Mem_Alloc( fs_mempool, sizeof( *info ) * numpackfiles );
lseek( packhandle, header.dirofs, SEEK_SET );
if( header.dirlen != read( packhandle, (void *)info, header.dirlen ))
{
Msg("%s is an incomplete PAK, not loading\n", packfile);
Mem_Free(info);
close(packhandle);
MsgDev( D_NOTE, "%s is an incomplete PAK, not loading\n", packfile );
Mem_Free( info );
close( packhandle );
return NULL;
}
pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof( pack_t ));
pack = (pack_t *)Mem_Alloc( fs_mempool, sizeof( pack_t ));
com.strncpy( pack->filename, packfile, sizeof( pack->filename ));
pack->handle = packhandle;
pack->numfiles = 0;
pack->files = (packfile_t *)Mem_Alloc( fs_mempool, numpackfiles * sizeof( packfile_t ));
pack->filetime = FS_SysFileTime( packfile );
// parse the directory
for (i = 0;i < numpackfiles;i++)
for( i = 0; i < numpackfiles; i++ )
{
fs_offset_t offset = LittleLong (info[i].filepos);
fs_offset_t size = LittleLong (info[i].filelen);
FS_AddFileToPack (info[i].name, pack, offset, size, size, PACKFILE_FLAG_TRUEOFFS);
fs_offset_t offset = LittleLong( info[i].filepos );
fs_offset_t size = LittleLong( info[i].filelen );
FS_AddFileToPack( info[i].name, pack, offset, size, size, PACKFILE_FLAG_TRUEOFFS );
}
Mem_Free( info );
@ -885,40 +894,41 @@ static bool FS_AddPack_Fullpath( const char *pakfile, bool *already_loaded, bool
if( already_loaded ) *already_loaded = false;
if( !com.stricmp( ext, "pak" )) pak = FS_LoadPackPAK (pakfile);
else if( !com.stricmp( ext, "pk2" )) pak = FS_LoadPackPK3(pakfile);
else if( !com.stricmp( ext, "pk3" )) pak = FS_LoadPackPK3(pakfile);
if( !com.stricmp( ext, "pak" )) pak = FS_LoadPackPAK( pakfile );
else if( !com.stricmp( ext, "pk2" )) pak = FS_LoadPackPK3( pakfile );
else if( !com.stricmp( ext, "pk3" )) pak = FS_LoadPackPK3( pakfile );
else MsgDev( D_ERROR, "\"%s\" does not have a pack extension\n", pakfile );
if( pak )
{
if(keep_plain_dirs)
if( keep_plain_dirs )
{
// find the first item whose next one is a pack or NULL
searchpath_t *insertion_point = 0;
if(fs_searchpaths && !fs_searchpaths->pack)
if( fs_searchpaths && !fs_searchpaths->pack )
{
insertion_point = fs_searchpaths;
for(;;)
while( 1 )
{
if(!insertion_point->next) break;
if(insertion_point->next->pack) break;
if( !insertion_point->next ) break;
if( insertion_point->next->pack ) break;
insertion_point = insertion_point->next;
}
}
// If insertion_point is NULL, this means that either there is no
// if insertion_point is NULL, this means that either there is no
// item in the list yet, or that the very first item is a pack. In
// that case, we want to insert at the beginning...
if(!insertion_point)
if( !insertion_point )
{
search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t));
search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t ));
search->pack = pak;
search->next = fs_searchpaths;
fs_searchpaths = search;
}
else // otherwise we want to append directly after insertion_point.
{
search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t));
search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t ));
search->pack = pak;
search->next = insertion_point->next;
insertion_point->next = search;
@ -926,7 +936,7 @@ static bool FS_AddPack_Fullpath( const char *pakfile, bool *already_loaded, bool
}
else
{
search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t));
search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t ));
search->pack = pak;
search->next = fs_searchpaths;
fs_searchpaths = search;
@ -935,7 +945,7 @@ static bool FS_AddPack_Fullpath( const char *pakfile, bool *already_loaded, bool
}
else
{
MsgDev( D_ERROR, "FS_AddPack_Fullpath: unable to load pak \"%s\"\n", pakfile);
MsgDev( D_ERROR, "FS_AddPack_Fullpath: unable to load pak \"%s\"\n", pakfile );
return false;
}
}
@ -947,9 +957,9 @@ FS_AddWad_Fullpath
*/
static bool FS_AddWad_Fullpath( const char *wadfile, bool *already_loaded, bool keep_plain_dirs )
{
searchpath_t *search;
wfile_t *wad = NULL;
const char *ext = FS_FileExtension( wadfile );
searchpath_t *search;
wfile_t *wad = NULL;
const char *ext = FS_FileExtension( wadfile );
for( search = fs_searchpaths; search; search = search->next )
{
@ -1075,7 +1085,7 @@ void FS_AddGameDirectory( const char *dir, int flags )
// add any PAK package in the directory
for( i = 0; i < list.numstrings; i++ )
{
if( !com.stricmp( FS_FileExtension(list.strings[i]), "pak" ))
if( !com.stricmp( FS_FileExtension( list.strings[i] ), "pak" ))
{
com.sprintf( pakfile, "%s%s", dir, list.strings[i] );
FS_AddPack_Fullpath( pakfile, NULL, false );
@ -1112,7 +1122,7 @@ void FS_AddGameDirectory( const char *dir, int flags )
stringlistfreecontents( &list );
// use normal method because we want take access to wad files in pak or pk3 archives
// use normal method because we want take access to wad files through pak or pk3 archives
wads = FS_Search( "*.wad", true );
for( i = 0; wads && i < wads->numfilenames; i++ )
FS_AddWad_Fullpath( wads->filenames[i], NULL, false );
@ -1127,10 +1137,7 @@ FS_AddGameHierarchy
void FS_AddGameHierarchy( const char *dir, int flags )
{
// Add the common game directory
if( dir || *dir )
{
FS_AddGameDirectory( va( "%s%s/", fs_basedir, dir ), flags );
}
if( dir && *dir ) FS_AddGameDirectory( va( "%s%s/", fs_basedir, dir ), flags );
}
@ -1840,6 +1847,23 @@ void FS_Shutdown( void )
Mem_FreePool( &fs_mempool );
}
/*
====================
FS_SysFileTime
Internal function used to determine filetime
====================
*/
static long FS_SysFileTime( const char *filename )
{
struct stat buf;
if( stat( filename, &buf ) == -1 )
return -1;
return buf.st_mtime;
}
/*
====================
FS_SysOpen
@ -1889,19 +1913,20 @@ static file_t* FS_SysOpen( const char* filepath, const char* mode )
}
file = (file_t *)Mem_Alloc( fs_mempool, sizeof( *file ));
file->filetime = FS_SysFileTime( filepath );
file->ungetc = EOF;
file->handle = open (filepath, mod | opt, 0666);
if (file->handle < 0)
file->handle = open( filepath, mod|opt, 0666 );
if( file->handle < 0 )
{
Mem_Free (file);
Mem_Free( file );
return NULL;
}
file->real_length = lseek (file->handle, 0, SEEK_END);
file->real_length = lseek( file->handle, 0, SEEK_END );
// For files opened in append mode, we start at the end of the file
if (mod & O_APPEND) file->position = file->real_length;
else lseek (file->handle, 0, SEEK_SET);
if( mod & O_APPEND ) file->position = file->real_length;
else lseek( file->handle, 0, SEEK_SET );
return file;
}
@ -2078,7 +2103,7 @@ static searchpath_t *FS_FindFile( const char *name, int* index, bool quiet )
}
}
if( fs_ext_path && (pEnvPath = getenv( "Path" )))
if( fs_ext_path && ( pEnvPath = getenv( "Path" )))
{
char netpath[MAX_SYSPATH];
@ -2778,6 +2803,67 @@ bool FS_FileExists( const char *filename )
return false;
}
/*
==================
FS_FindLibrary
search for library, assume index is valid
only for internal use
==================
*/
dll_user_t *FS_FindLibrary( const char *dllname, bool directpath )
{
string dllpath;
searchpath_t *search;
dll_user_t *hInst;
int index;
// check for bad exports
if( !dllname || !*dllname )
return NULL;
fs_ext_path = directpath;
if( !directpath )
com.snprintf( dllpath, sizeof( dllpath ), "bin/%s", dllname );
else com.strncpy( dllpath, dllname, sizeof( dllpath ));
FS_DefaultExtension( dllpath, ".dll" ); // trying to apply if forget
search = FS_FindFile( dllpath, &index, true );
if( !search )
{
fs_ext_path = false;
if( directpath ) return NULL; // direct paths fails here
// trying check also 'bin' folder for indirect paths
com.strncpy( dllpath, dllname, sizeof( dllpath ));
search = FS_FindFile( dllpath, &index, true );
if( !search ) return NULL; // unable to find
}
// all done, create dll_user_t struct
hInst = Mem_Alloc( Sys.basepool, sizeof( dll_user_t ));
// save dllname for debug purposes
com.strncpy( hInst->dllName, dllname, sizeof( hInst->dllName ));
// shortPath is used for LibraryLoadSymbols only
com.strncpy( hInst->shortPath, dllpath, sizeof( hInst->shortPath ));
if( index < 0 )
{
com.snprintf( hInst->fullPath, sizeof( hInst->fullPath ), "%s%s", search->filename, dllpath );
hInst->custom_loader = false; // we can loading from disk and use normal debugging
}
else
{
com.strncpy( hInst->fullPath, dllpath, sizeof( hInst->fullPath ));
hInst->custom_loader = true; // loading from pack or wad - for release, debug don't working
}
fs_ext_path = false; // always reset direct paths
return hInst;
}
/*
==================
@ -2793,14 +2879,13 @@ fs_offset_t FS_FileSize (const char *filename)
fp = _FS_Open( filename, "rb", true );
if (fp)
if( fp )
{
// it exists
FS_Seek(fp, 0, SEEK_END);
length = FS_Tell(fp);
FS_Close(fp);
FS_Seek( fp, 0, SEEK_END );
length = FS_Tell( fp );
FS_Close( fp );
}
return length;
}
@ -2813,30 +2898,69 @@ return time of creation file in seconds
*/
fs_offset_t FS_FileTime( const char *filename )
{
struct stat buf;
searchpath_t *search;
int pack_ind;
if( stat( filename, &buf ) == -1 )
return -1;
return buf.st_mtime;
}
search = FS_FindFile( filename, &pack_ind, true );
if( !search ) return -1; // doesn't exist
bool FS_Remove( const char *path )
{
remove( path );
return true;
if( search->pack ) // grab pack filetime
return search->pack->filetime;
else if( search->wad ) // grab wad filetime
return search->wad->filetime;
else if( pack_ind < 0 )
{
// found in the filesystem?
char path [MAX_SYSPATH];
com.sprintf( path, "%s%s", search->filename, filename );
return FS_SysFileTime( path );
}
return -1; // doesn't exist
}
/*
==================
FS_DeleteFile
FS_Rename
internal use only
rename specified file from gamefolder
==================
*/
void FS_DeleteFile( const char *path )
bool FS_Rename( const char *oldname, const char *newname )
{
remove( va( "%s/%s", fs_gamedir, path ));
char oldpath[MAX_SYSPATH], newpath[MAX_SYSPATH];
bool iRet;
if( !oldname || !newname || !*oldname || !*newname )
return false;
com_snprintf( oldpath, sizeof( oldpath ), "%s/%s", fs_gamedir, oldname );
com_snprintf( newpath, sizeof( newpath ), "%s/%s", fs_gamedir, newname );
iRet = rename( oldpath, newpath );
return iRet;
}
/*
==================
FS_Delete
delete specified file from gamefolder
==================
*/
bool FS_Delete( const char *path )
{
char real_path[MAX_SYSPATH];
bool iRet;
if( !path || !*path )
return false;
com_snprintf( real_path, sizeof( real_path ), "%s/%s", fs_gamedir, path );
iRet = remove( real_path );
return iRet;
}
/*
@ -3879,6 +4003,7 @@ wfile_t *W_Open( const char *filename, const char *mode )
// copy wad name
com.strncpy( wad->filename, filename, sizeof( wad->filename ));
wad->mempool = Mem_AllocPool( filename );
wad->filetime = wad->file->filetime;
// if the file is opened in "write", "append", or "read/write" mode
if( mode[0] == 'w' )
@ -3942,6 +4067,7 @@ wfile_t *W_Open( const char *filename, const char *mode )
W_Close( wad );
return NULL;
}
// NOTE: lumps table can be reallocated for O_APPEND mode
wad->lumps = Mem_Alloc( wad->mempool, wad->numlumps * sizeof( dlumpinfo_t ));

View File

@ -651,6 +651,6 @@ bool Image_SaveJPG( const char *name, rgbdata_t *pix )
error_caught:
jpeg_destroy_compress( &cinfo );
FS_Close( file );
FS_DeleteFile( name ); // kill invalid file
FS_Delete( name ); // kill invalid file
return false;
}

View File

@ -180,6 +180,10 @@ SOURCE=.\imagelib\img_wad.c
# End Source File
# Begin Source File
SOURCE=.\library.c
# End Source File
# Begin Source File
SOURCE=.\memlib.c
# End Source File
# Begin Source File
@ -218,6 +222,10 @@ SOURCE=.\filesystem.h
SOURCE=.\launch.h
# End Source File
# Begin Source File
SOURCE=.\library.h
# End Source File
# End Group
# Begin Group "Resource Files"

View File

@ -336,7 +336,6 @@ bool FS_GetParmFromCmdLine( char *parm, char *out, size_t size );
void FS_ExtractFilePath( const char* const path, char* dest );
void FS_UpdateEnvironmentVariables( void );
const char *FS_FileWithoutPath( const char *in );
void FS_DeleteFile( const char *path );
extern char sys_rootdir[];
extern char *fs_argv[];
extern int fs_argc;
@ -362,47 +361,48 @@ search_t *FS_Search(const char *pattern, int caseinsensitive );
search_t *FS_SearchDirs(const char *pattern, int caseinsensitive );
// files managment (like fopen, fread etc)
file_t *FS_Open( const char* filepath, const char* mode );
file_t* _FS_Open( const char* filepath, const char* mode, bool quiet );
fs_offset_t FS_Write (file_t* file, const void* data, size_t datasize);
fs_offset_t FS_Read (file_t* file, void* buffer, size_t buffersize);
int FS_VPrintf(file_t* file, const char* format, va_list ap);
int FS_Seek (file_t* file, fs_offset_t offset, int whence);
int FS_Gets (file_t* file, byte *string, size_t bufsize );
int FS_Printf(file_t* file, const char* format, ...);
fs_offset_t FS_FileSize (const char *filename);
fs_offset_t FS_FileTime (const char *filename);
int FS_Print(file_t* file, const char *msg);
bool FS_FileExists (const char *filename);
bool FS_Remove( const char *path );
int FS_UnGetc (file_t* file, byte c);
void FS_StripExtension (char *path);
fs_offset_t FS_Tell( file_t* file );
bool FS_Eof( file_t* file );
void FS_Purge (file_t* file);
int FS_Close (file_t* file);
int FS_Getc (file_t* file);
bool FS_Eof( file_t* file);
file_t *FS_Open( const char *filepath, const char *mode );
file_t* _FS_Open( const char *filepath, const char *mode, bool quiet );
fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize );
fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize );
int FS_VPrintf( file_t *file, const char *format, va_list ap );
int FS_Seek( file_t *file, fs_offset_t offset, int whence );
int FS_Gets( file_t *file, byte *string, size_t bufsize );
int FS_Printf( file_t *file, const char *format, ... );
fs_offset_t FS_FileSize( const char *filename );
fs_offset_t FS_FileTime( const char *filename );
int FS_Print( file_t *file, const char *msg );
bool FS_Rename( const char *oldname, const char *newname );
bool FS_FileExists( const char *filename );
bool FS_Delete( const char *path );
int FS_UnGetc( file_t *file, byte c );
void FS_StripExtension( char *path );
fs_offset_t FS_Tell( file_t *file );
bool FS_Eof( file_t *file );
void FS_Purge( file_t *file );
int FS_Close( file_t *file );
int FS_Getc( file_t *file );
bool FS_Eof( file_t *file );
//
// cvar.c
//
cvar_t *Cvar_FindVar (const char *var_name);
cvar_t *Cvar_Get (const char *var_name, const char *value, int flags, const char *description);
void Cvar_Set( const char *var_name, const char *value);
cvar_t *Cvar_FindVar( const char *var_name );
cvar_t *Cvar_Get( const char *var_name, const char *value, int flags, const char *description );
void Cvar_Set( const char *var_name, const char *value );
cvar_t *Cvar_Set2( const char *var_name, const char *value, bool force );
void Cvar_LookupVars( int checkbit, void *buffer, void *ptr, setpair_t callback );
void Cvar_FullSet (char *var_name, char *value, int flags);
void Cvar_SetLatched( const char *var_name, const char *value);
void Cvar_SetValue( const char *var_name, float value);
float Cvar_VariableValue(const char *var_name);
int Cvar_VariableInteger(const char *var_name);
char *Cvar_VariableString(const char *var_name);
bool Cvar_Command (void);
void Cvar_FullSet (char *var_name, char *value, int flags );
void Cvar_SetLatched( const char *var_name, const char *value );
void Cvar_SetValue( const char *var_name, float value );
float Cvar_VariableValue( const char *var_name );
int Cvar_VariableInteger( const char *var_name );
char *Cvar_VariableString( const char *var_name );
bool Cvar_Command( void );
void Cvar_WriteVariables( file_t *f );
void Cvar_Init (void);
char *Cvar_Userinfo (void);
char *Cvar_Serverinfo (void);
void Cvar_Init( void );
char *Cvar_Userinfo( void );
char *Cvar_Serverinfo( void );
extern bool userinfo_modified;
char *Info_ValueForKey( char *s, char *key );
void Info_RemoveKey( char *s, char *key );
@ -415,39 +415,39 @@ extern cvar_t *cvar_vars;
// cmd.c
//
void Cbuf_Init( void );
void Cbuf_AddText (const char *text);
void Cbuf_InsertText (const char *text);
void Cbuf_ExecuteText (int exec_when, const char *text);
void Cbuf_AddText( const char *text );
void Cbuf_InsertText( const char *text );
void Cbuf_ExecuteText( int exec_when, const char *text );
void Cbuf_Execute (void);
uint Cmd_Argc( void );
char *Cmd_Args( void );
char *Cmd_Argv( uint arg );
void Cmd_Init( void );
void Cmd_AddCommand(const char *cmd_name, xcommand_t function, const char *cmd_desc);
void Cmd_RemoveCommand(const char *cmd_name);
bool Cmd_Exists (const char *cmd_name);
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
void Cmd_RemoveCommand( const char *cmd_name );
bool Cmd_Exists( const char *cmd_name );
void Cmd_LookupCmds( char *buffer, void *ptr, setpair_t callback );
bool Cmd_GetMapList( const char *s, char *completedname, int length );
bool Cmd_GetDemoList( const char *s, char *completedname, int length );
bool Cmd_GetMovieList (const char *s, char *completedname, int length );
void Cmd_TokenizeString (const char *text);
void Cmd_ExecuteString (const char *text);
void Cmd_ForwardToServer (void);
bool Cmd_GetMovieList( const char *s, char *completedname, int length );
void Cmd_TokenizeString( const char *text );
void Cmd_ExecuteString( const char *text );
void Cmd_ForwardToServer( void );
// virtual files managment
vfile_t *VFS_Create( const byte *buffer, size_t buffsize );
vfile_t *VFS_Open(file_t *handle, const char* mode);
vfile_t *VFS_Open( file_t *handle, const char* mode );
fs_offset_t VFS_Write( vfile_t *file, const void *buf, size_t size );
fs_offset_t VFS_Read( vfile_t* file, void* buffer, size_t buffersize);
int VFS_Print(vfile_t* file, const char *msg);
int VFS_Printf(vfile_t* file, const char* format, ...);
fs_offset_t VFS_Read( vfile_t* file, void* buffer, size_t buffersize );
int VFS_Print( vfile_t* file, const char *msg );
int VFS_Printf( vfile_t* file, const char* format, ... );
int VFS_Seek( vfile_t *file, fs_offset_t offset, int whence );
int VFS_Gets(vfile_t* file, byte *string, size_t bufsize );
bool VFS_Unpack( void* compbuf, size_t compsize, void **buf, size_t size );
int VFS_Gets( vfile_t *file, byte *string, size_t bufsize );
bool VFS_Unpack( void *compbuf, size_t compsize, void **buf, size_t size );
byte *VFS_GetBuffer( vfile_t *file );
fs_offset_t VFS_Tell (vfile_t* file);
fs_offset_t VFS_Tell (vfile_t *file );
file_t *VFS_Close( vfile_t *file );
bool VFS_Eof( vfile_t* file);
bool VFS_Eof( vfile_t *file );
//
// crclib.c

862
launch/library.c Normal file
View File

@ -0,0 +1,862 @@
//=======================================================================
// Copyright XashXT Group 2008 ©
// library.c - custom dlls loader
//=======================================================================
#include "launch.h"
#include "library.h"
/*
---------------------------------------------------------------
Custom dlls loader
---------------------------------------------------------------
*/
typedef struct
{
PIMAGE_NT_HEADERS headers;
byte *codeBase;
void **modules;
int numModules;
int initialized;
} MEMORYMODULE, *PMEMORYMODULE;
// Protection flags for memory pages (Executable, Readable, Writeable)
static int ProtectionFlags[2][2][2] =
{
{
{ PAGE_NOACCESS, PAGE_WRITECOPY }, // not executable
{ PAGE_READONLY, PAGE_READWRITE },
},
{
{ PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY }, // executable
{ PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE },
},
};
typedef BOOL (WINAPI *DllEntryProc)( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved );
#define GET_HEADER_DICTIONARY( module, idx ) &(module)->headers->OptionalHeader.DataDirectory[idx]
#define CALCULATE_ADDRESS( base, offset ) (((DWORD)(base)) + (offset))
static void CopySections( const byte *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
{
int i, size;
byte *dest;
byte *codeBase = module->codeBase;
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION( module->headers );
for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ )
{
if( section->SizeOfRawData == 0 )
{
// section doesn't contain data in the dll itself, but may define
// uninitialized data
size = old_headers->OptionalHeader.SectionAlignment;
if( size > 0 )
{
dest = (byte *)VirtualAlloc((byte *)CALCULATE_ADDRESS(codeBase, section->VirtualAddress), size, MEM_COMMIT, PAGE_READWRITE );
section->Misc.PhysicalAddress = (DWORD)dest;
Mem_Set( dest, 0, size );
}
// section is empty
continue;
}
// commit memory block and copy data from dll
dest = (byte *)VirtualAlloc((byte *)CALCULATE_ADDRESS(codeBase, section->VirtualAddress), section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE );
Mem_Copy( dest, (byte *)CALCULATE_ADDRESS(data, section->PointerToRawData), section->SizeOfRawData );
section->Misc.PhysicalAddress = (DWORD)dest;
}
}
static void FreeSections( PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
{
int i, size;
byte *codeBase = module->codeBase;
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ )
{
if( section->SizeOfRawData == 0 )
{
size = old_headers->OptionalHeader.SectionAlignment;
if( size > 0 )
{
VirtualFree( codeBase + section->VirtualAddress, size, MEM_DECOMMIT );
section->Misc.PhysicalAddress = 0;
}
continue;
}
VirtualFree( codeBase + section->VirtualAddress, section->SizeOfRawData, MEM_DECOMMIT );
section->Misc.PhysicalAddress = 0;
}
}
static void FinalizeSections( MEMORYMODULE *module )
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION( module->headers );
int i;
// loop through all sections and change access flags
for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ )
{
DWORD protect, oldProtect, size;
int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0;
int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
if( section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE )
{
// section is not needed any more and can safely be freed
VirtualFree((LPVOID)section->Misc.PhysicalAddress, section->SizeOfRawData, MEM_DECOMMIT);
continue;
}
// determine protection flags based on characteristics
protect = ProtectionFlags[executable][readable][writeable];
if( section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED )
protect |= PAGE_NOCACHE;
// determine size of region
size = section->SizeOfRawData;
if( size == 0 )
{
if( section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA )
size = module->headers->OptionalHeader.SizeOfInitializedData;
else if( section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA )
size = module->headers->OptionalHeader.SizeOfUninitializedData;
}
if( size > 0 )
{
// change memory access flags
if( !VirtualProtect((LPVOID)section->Misc.PhysicalAddress, size, protect, &oldProtect ))
Sys_Error( "Com_FinalizeSections: error protecting memory page\n" );
}
}
}
static void PerformBaseRelocation( MEMORYMODULE *module, DWORD delta )
{
DWORD i;
byte *codeBase = module->codeBase;
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_BASERELOC );
if( directory->Size > 0 )
{
PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION)CALCULATE_ADDRESS( codeBase, directory->VirtualAddress );
for( ; relocation->VirtualAddress > 0; )
{
byte *dest = (byte *)CALCULATE_ADDRESS( codeBase, relocation->VirtualAddress );
word *relInfo = (word *)((byte *)relocation + IMAGE_SIZEOF_BASE_RELOCATION );
for( i = 0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++ )
{
DWORD *patchAddrHL;
int type, offset;
// the upper 4 bits define the type of relocation
type = *relInfo >> 12;
// the lower 12 bits define the offset
offset = *relInfo & 0xfff;
switch( type )
{
case IMAGE_REL_BASED_ABSOLUTE:
// skip relocation
break;
case IMAGE_REL_BASED_HIGHLOW:
// change complete 32 bit address
patchAddrHL = (DWORD *)CALCULATE_ADDRESS( dest, offset );
*patchAddrHL += delta;
break;
default:
MsgDev( D_ERROR, "PerformBaseRelocation: unknown relocation: %d\n", type );
break;
}
}
// advance to next relocation block
relocation = (PIMAGE_BASE_RELOCATION)CALCULATE_ADDRESS( relocation, relocation->SizeOfBlock );
}
}
}
static FARPROC MemoryGetProcAddress( void *module, const char *name )
{
int idx = -1;
DWORD i, *nameRef;
WORD *ordinal;
PIMAGE_EXPORT_DIRECTORY exports;
byte *codeBase = ((PMEMORYMODULE)module)->codeBase;
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((MEMORYMODULE *)module, IMAGE_DIRECTORY_ENTRY_EXPORT );
if( directory->Size == 0 )
{
// no export table found
return NULL;
}
exports = (PIMAGE_EXPORT_DIRECTORY)CALCULATE_ADDRESS( codeBase, directory->VirtualAddress );
if( exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0 )
{
// DLL doesn't export anything
return NULL;
}
// search function name in list of exported names
nameRef = (DWORD *)CALCULATE_ADDRESS( codeBase, exports->AddressOfNames );
ordinal = (WORD *)CALCULATE_ADDRESS( codeBase, exports->AddressOfNameOrdinals );
for( i = 0; i < exports->NumberOfNames; i++, nameRef++, ordinal++ )
{
// GetProcAddress case insensative ?????
if( !com.stricmp( name, (const char *)CALCULATE_ADDRESS( codeBase, *nameRef )))
{
idx = *ordinal;
break;
}
}
if( idx == -1 )
{
// exported symbol not found
return NULL;
}
if((DWORD)idx > exports->NumberOfFunctions )
{
// name <-> ordinal number don't match
return NULL;
}
// addressOfFunctions contains the RVAs to the "real" functions
return (FARPROC)CALCULATE_ADDRESS( codeBase, *(DWORD *)CALCULATE_ADDRESS( codeBase, exports->AddressOfFunctions + (idx * 4)));
}
static int BuildImportTable( MEMORYMODULE *module )
{
int result=1;
byte *codeBase = module->codeBase;
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_IMPORT );
if( directory->Size > 0 )
{
PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR)CALCULATE_ADDRESS( codeBase, directory->VirtualAddress );
for( ; !IsBadReadPtr( importDesc, sizeof( IMAGE_IMPORT_DESCRIPTOR )) && importDesc->Name; importDesc++ )
{
DWORD *thunkRef, *funcRef;
LPCSTR libname;
void *handle;
libname = (LPCSTR)CALCULATE_ADDRESS( codeBase, importDesc->Name );
handle = Com_LoadLibraryExt( libname, false, true );
if( handle == NULL )
{
MsgDev( D_ERROR, "couldn't load library %s\n", libname );
result = 0;
break;
}
module->modules = (void *)Mem_Realloc( Sys.basepool, module->modules, (module->numModules + 1) * (sizeof( void* )));
module->modules[module->numModules++] = handle;
if( importDesc->OriginalFirstThunk )
{
thunkRef = (DWORD *)CALCULATE_ADDRESS( codeBase, importDesc->OriginalFirstThunk );
funcRef = (DWORD *)CALCULATE_ADDRESS( codeBase, importDesc->FirstThunk );
}
else
{
// no hint table
thunkRef = (DWORD *)CALCULATE_ADDRESS( codeBase, importDesc->FirstThunk );
funcRef = (DWORD *)CALCULATE_ADDRESS( codeBase, importDesc->FirstThunk );
}
for( ; *thunkRef; thunkRef++, funcRef++ )
{
if( IMAGE_SNAP_BY_ORDINAL( *thunkRef ))
{
LPCSTR funcName = (LPCSTR)IMAGE_ORDINAL( *thunkRef );
*funcRef = (DWORD)Com_GetProcAddress( handle, funcName );
}
else
{
PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME)CALCULATE_ADDRESS( codeBase, *thunkRef );
LPCSTR funcName = (LPCSTR)&thunkData->Name;
*funcRef = (DWORD)Com_GetProcAddress( handle, funcName );
}
if( *funcRef == 0 )
{
result = 0;
break;
}
}
if( !result ) break;
}
}
return result;
}
static void MemoryFreeLibrary( void *hInstance )
{
MEMORYMODULE *module = (MEMORYMODULE *)hInstance;
if( module != NULL )
{
int i;
if( module->initialized != 0 )
{
// notify library about detaching from process
DllEntryProc DllEntry = (DllEntryProc)CALCULATE_ADDRESS( module->codeBase, module->headers->OptionalHeader.AddressOfEntryPoint );
(*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0 );
module->initialized = 0;
}
if( module->modules != NULL )
{
// free previously opened libraries
for( i = 0; i < module->numModules; i++ )
{
if( module->modules[i] != NULL )
{
Com_FreeLibrary( module->modules[i] );
}
}
Mem_Free( module->modules ); // Mem_Realloc end
}
FreeSections( module->headers, module );
if( module->codeBase != NULL )
{
// release memory of library
VirtualFree( module->codeBase, 0, MEM_RELEASE );
}
HeapFree( GetProcessHeap(), 0, module );
}
}
void *MemoryLoadLibrary( const char *name )
{
MEMORYMODULE *result;
PIMAGE_DOS_HEADER dos_header;
PIMAGE_NT_HEADERS old_header;
byte *code, *headers;
DWORD locationDelta;
DllEntryProc DllEntry;
string errorstring;
BOOL successfull;
void *data = NULL;
data = FS_LoadFile( name, NULL );
if( !data )
{
com.sprintf( errorstring, "couldn't load %s", name );
goto library_error;
}
dos_header = (PIMAGE_DOS_HEADER)data;
if( dos_header->e_magic != IMAGE_DOS_SIGNATURE )
{
com.sprintf( errorstring, "%s it's not a valid executable file", name );
goto library_error;
}
old_header = (PIMAGE_NT_HEADERS)&((const byte *)(data))[dos_header->e_lfanew];
if( old_header->Signature != IMAGE_NT_SIGNATURE )
{
com.sprintf( errorstring, "%s missing PE header", name );
goto library_error;
}
// reserve memory for image of library
code = (byte *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), old_header->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE );
if( code == NULL )
{
// try to allocate memory at arbitrary position
code = (byte *)VirtualAlloc( NULL, old_header->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE );
}
if( code == NULL )
{
com.sprintf( errorstring, "%s can't reserve memory", name );
goto library_error;
}
result = (MEMORYMODULE *)HeapAlloc( GetProcessHeap(), 0, sizeof( MEMORYMODULE ));
result->codeBase = code;
result->numModules = 0;
result->modules = NULL;
result->initialized = 0;
// XXX: is it correct to commit the complete memory region at once?
// calling DllEntry raises an exception if we don't...
VirtualAlloc( code, old_header->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE );
// commit memory for headers
headers = (byte *)VirtualAlloc( code, old_header->OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE );
// copy PE header to code
Mem_Copy( headers, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders );
result->headers = (PIMAGE_NT_HEADERS)&((const byte *)(headers))[dos_header->e_lfanew];
// update position
result->headers->OptionalHeader.ImageBase = (DWORD)code;
// copy sections from DLL file block to new memory location
CopySections( data, old_header, result );
// adjust base address of imported data
locationDelta = (DWORD)(code - old_header->OptionalHeader.ImageBase);
if( locationDelta != 0 ) PerformBaseRelocation( result, locationDelta );
// load required dlls and adjust function table of imports
if( !BuildImportTable( result ))
{
com.sprintf( errorstring, "%s failed to build import table", name );
goto library_error;
}
// mark memory pages depending on section headers and release
// sections that are marked as "discardable"
FinalizeSections( result );
// get entry point of loaded library
if( result->headers->OptionalHeader.AddressOfEntryPoint != 0 )
{
DllEntry = (DllEntryProc)CALCULATE_ADDRESS( code, result->headers->OptionalHeader.AddressOfEntryPoint );
if( DllEntry == 0 )
{
com.sprintf( errorstring, "%s has no entry point", name );
goto library_error;
}
// notify library about attaching to process
successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0 );
if( !successfull )
{
com.sprintf( errorstring, "can't attach library %s", name );
goto library_error;
}
result->initialized = 1;
}
Mem_Free( data ); // release memory
return (void *)result;
library_error:
// cleanup
if( data ) Mem_Free( data );
MemoryFreeLibrary( result );
MsgDev( D_ERROR, "LoadLibrary: %s\n", errorstring );
return NULL;
}
/*
---------------------------------------------------------------
Name for function stuff
---------------------------------------------------------------
*/
static void FsGetString( file_t *f, char *str )
{
char ch;
while(( ch = FS_Getc( f )) != EOF )
{
*str++ = ch;
if( !ch ) break;
}
}
static void FreeNameFuncGlobals( dll_user_t *hInst )
{
int i;
if( !hInst ) return;
if( hInst->ordinals ) Mem_Free( hInst->ordinals );
if( hInst->funcs ) Mem_Free( hInst->funcs );
for( i = 0; i < hInst->num_ordinals; i++ )
{
if( hInst->names[i] )
Mem_Free( hInst->names[i] );
}
hInst->num_ordinals = 0;
hInst->ordinals = NULL;
hInst->funcs = NULL;
}
char *GetMSVCName( const char *in_name )
{
char *pos, *out_name;
if( in_name[0] == '?' ) // is this a MSVC C++ mangled name?
{
if(( pos = com.strstr( in_name, "@@" )) != NULL )
{
int len = pos - in_name;
// strip off the leading '?'
out_name = com.stralloc( Sys.stringpool, in_name + 1, __FILE__, __LINE__ );
out_name[len-1] = 0; // terminate string at the "@@"
return out_name;
}
}
return com.stralloc( Sys.stringpool, in_name, __FILE__, __LINE__ );
}
bool LibraryLoadSymbols( dll_user_t *hInst )
{
file_t *f;
string errorstring;
DOS_HEADER dos_header;
LONG nt_signature;
PE_HEADER pe_header;
SECTION_HEADER section_header;
bool edata_found;
OPTIONAL_HEADER optional_header;
long edata_offset;
long edata_delta;
EXPORT_DIRECTORY export_directory;
long name_offset;
long ordinal_offset;
long function_offset;
string function_name;
dword *p_Names = NULL;
int i, index;
// can only be done for loaded libraries
if( !hInst ) return false;
for( i = 0; i < hInst->num_ordinals; i++ )
hInst->names[i] = NULL;
f = FS_Open( hInst->shortPath, "rb" );
if( !f )
{
com.sprintf( errorstring, "couldn't load %s", hInst->shortPath );
goto table_error;
}
if( FS_Read( f, &dos_header, sizeof( dos_header )) != sizeof( dos_header ))
{
com.sprintf( errorstring, "%s has corrupted EXE header", hInst->shortPath );
goto table_error;
}
if( dos_header.e_magic != DOS_SIGNATURE )
{
com.sprintf( errorstring, "%s does not have a valid dll signature", hInst->shortPath );
goto table_error;
}
if( FS_Seek( f, dos_header.e_lfanew, SEEK_SET ) == -1 )
{
com.sprintf( errorstring, "%s error seeking for new exe header", hInst->shortPath );
goto table_error;
}
if( FS_Read( f, &nt_signature, sizeof( nt_signature )) != sizeof( nt_signature ))
{
com.sprintf( errorstring, "%s has corrupted NT header", hInst->shortPath );
goto table_error;
}
if( nt_signature != NT_SIGNATURE )
{
com.sprintf( errorstring, "%s does not have a valid NT signature", hInst->shortPath );
goto table_error;
}
if( FS_Read( f, &pe_header, sizeof( pe_header )) != sizeof( pe_header ))
{
com.sprintf( errorstring, "%s does not have a valid PE header", hInst->shortPath );
goto table_error;
}
if( !pe_header.SizeOfOptionalHeader )
{
com.sprintf( errorstring, "%s does not have an optional header", hInst->shortPath );
goto table_error;
}
if( FS_Read( f, &optional_header, sizeof( optional_header )) != sizeof( optional_header ))
{
com.sprintf( errorstring, "%s optional header probably corrupted", hInst->shortPath );
goto table_error;
}
edata_found = false;
for( i = 0; i < pe_header.NumberOfSections; i++ )
{
if( FS_Read( f, &section_header, sizeof( section_header )) != sizeof( section_header ))
{
com.sprintf( errorstring, "%s error during reading section header", hInst->shortPath );
goto table_error;
}
if( !com.strcmp((char *)section_header.Name, ".edata" ))
{
edata_found = true;
break;
}
}
if( edata_found )
{
edata_offset = section_header.PointerToRawData;
edata_delta = section_header.VirtualAddress - section_header.PointerToRawData;
}
else
{
edata_offset = optional_header.DataDirectory[0].VirtualAddress;
edata_delta = 0;
}
if( FS_Seek( f, edata_offset, SEEK_SET ) == -1 )
{
com.sprintf( errorstring, "%s does not have a valid exports section", hInst->shortPath );
goto table_error;
}
if( FS_Read( f, &export_directory, sizeof( export_directory )) != sizeof( export_directory ))
{
com.sprintf( errorstring, "%s does not have a valid optional header", hInst->shortPath );
goto table_error;
}
hInst->num_ordinals = export_directory.NumberOfNames; // also number of ordinals
if( hInst->num_ordinals > MAX_LIBRARY_EXPORTS )
{
com.sprintf( errorstring, "%s too many exports", hInst->shortPath );
goto table_error;
}
ordinal_offset = export_directory.AddressOfNameOrdinals - edata_delta;
if( FS_Seek( f, ordinal_offset, SEEK_SET ) == -1 )
{
com.sprintf( errorstring, "%s does not have a valid ordinals section", hInst->shortPath );
goto table_error;
}
hInst->ordinals = Mem_Alloc( Sys.basepool, hInst->num_ordinals * sizeof( word ));
if( FS_Read( f, hInst->ordinals, hInst->num_ordinals * sizeof( word )) != (hInst->num_ordinals * sizeof( word )))
{
com.sprintf( errorstring, "%s error during reading ordinals table", hInst->shortPath );
goto table_error;
}
function_offset = export_directory.AddressOfFunctions - edata_delta;
if( FS_Seek( f, function_offset, SEEK_SET ) == -1 )
{
com.sprintf( errorstring, "%s does not have a valid export address section", hInst->shortPath );
goto table_error;
}
hInst->funcs = Mem_Alloc( Sys.basepool, hInst->num_ordinals * sizeof( dword ));
if( FS_Read( f, hInst->funcs, hInst->num_ordinals * sizeof( dword )) != (hInst->num_ordinals * sizeof( dword )))
{
com.sprintf( errorstring, "%s error during reading export address section", hInst->shortPath );
goto table_error;
}
name_offset = export_directory.AddressOfNames - edata_delta;
if( FS_Seek( f, name_offset, SEEK_SET ) == -1 )
{
com.sprintf( errorstring, "%s file does not have a valid names section", hInst->shortPath );
goto table_error;
}
p_Names = Mem_Alloc( Sys.basepool, hInst->num_ordinals * sizeof( dword ));
if( FS_Read( f, p_Names, hInst->num_ordinals * sizeof( dword )) != (hInst->num_ordinals * sizeof( dword )))
{
com.sprintf( errorstring, "%s error during reading names table", hInst->shortPath );
goto table_error;
}
for( i = 0; i < hInst->num_ordinals; i++ )
{
name_offset = p_Names[i] - edata_delta;
if( name_offset != 0 )
{
if( FS_Seek( f, name_offset, SEEK_SET ) != -1 )
{
FsGetString( f, function_name );
hInst->names[i] = GetMSVCName( function_name );
}
else break;
}
}
if( i != hInst->num_ordinals )
{
com.sprintf( errorstring, "%s error during loading names section", hInst->shortPath );
goto table_error;
}
FS_Close( f );
for( i = 0; i < hInst->num_ordinals; i++ )
{
if( !com.strcmp( "CreateAPI", hInst->names[i] )) // main entry point for Xash3D dlls
{
void *fn_offset;
index = hInst->ordinals[i];
fn_offset = (void *)Com_GetProcAddress( hInst, "CreateAPI" );
hInst->funcBase = (dword)(fn_offset) - hInst->funcs[index];
break;
}
}
if( p_Names ) Mem_Free( p_Names );
return true;
table_error:
// cleanup
if( f ) FS_Close( f );
if( p_Names ) Mem_Free( p_Names );
FreeNameFuncGlobals( hInst );
MsgDev( D_ERROR, "LoadLibrary: %s\n", errorstring );
return false;
}
/*
================
Com_LoadLibrary
smart dll loader - can loading dlls from pack or wad files
================
*/
void *Com_LoadLibraryExt( const char *dllname, int build_ordinals_table, bool directpath )
{
dll_user_t *hInst;
hInst = FS_FindLibrary( dllname, directpath );
if( !hInst ) return NULL; // nothing to load
if( hInst->custom_loader )
hInst->hInstance = MemoryLoadLibrary( hInst->fullPath );
else hInst->hInstance = LoadLibrary( hInst->fullPath );
if( !hInst->hInstance )
{
MsgDev( D_NOTE, "Sys_LoadLibrary: Loading %s - failed\n", dllname );
Com_FreeLibrary( hInst );
return NULL;
}
// if not set - FunctionFromName and NameForFunction will not working
if( build_ordinals_table )
{
if( !LibraryLoadSymbols( hInst ))
{
MsgDev( D_NOTE, "Sys_LoadLibrary: Loading %s - failed\n", dllname );
Com_FreeLibrary( hInst );
return NULL;
}
}
MsgDev( D_NOTE, "Sys_LoadLibrary: Loading %s - ok\n", dllname );
return hInst;
}
void *Com_LoadLibrary( const char *dllname, int build_ordinals_table )
{
return Com_LoadLibraryExt( dllname, build_ordinals_table, false );
}
void *Com_GetProcAddress( void *hInstance, const char *name )
{
dll_user_t *hInst = (dll_user_t *)hInstance;
if( !hInst || !hInst->hInstance )
return NULL;
if( hInst->custom_loader )
return MemoryGetProcAddress( hInst->hInstance, name );
return GetProcAddress( hInst->hInstance, name );
}
void Com_FreeLibrary( void *hInstance )
{
dll_user_t *hInst = (dll_user_t *)hInstance;
if( !hInst || !hInst->hInstance )
return; // already freed
if( Sys.app_state == SYS_CRASH )
{
// we need to hold down all modules, while MSVC can find error
MsgDev( D_NOTE, "Sys_FreeLibrary: hold %s for debugging\n", hInst->dllName );
return;
}
else MsgDev( D_NOTE, "Sys_FreeLibrary: Unloading %s\n", hInst->dllName );
if( hInst->custom_loader )
MemoryFreeLibrary( hInst->hInstance );
else FreeLibrary( hInst->hInstance );
hInst->hInstance = NULL;
if( hInst->num_ordinals )
FreeNameFuncGlobals( hInst );
Mem_Free( hInst ); // done
}
dword Com_FunctionFromName( void *hInstance, const char *pName )
{
dll_user_t *hInst = (dll_user_t *)hInstance;
int i, index;
if( !hInst || !hInst->hInstance )
return 0;
for( i = 0; i < hInst->num_ordinals; i++ )
{
if( !com.strcmp( pName, hInst->names[i] ))
{
index = hInst->ordinals[i];
return hInst->funcs[index] + hInst->funcBase;
}
}
// couldn't find the function name to return address
return 0;
}
const char *Com_NameForFunction( void *hInstance, dword function )
{
dll_user_t *hInst = (dll_user_t *)hInstance;
int i, index;
if( !hInst || !hInst->hInstance )
return NULL;
for( i = 0; i < hInst->num_ordinals; i++ )
{
index = hInst->ordinals[i];
if(( function - hInst->funcBase ) == hInst->funcs[index] )
return hInst->names[i];
}
// couldn't find the function address to return name
return NULL;
}

View File

@ -1,13 +1,14 @@
//=======================================================================
// Copyright XashXT Group 2008 ©
// com_library.h - custom dlls loader
// library.h - custom dlls loader
//=======================================================================
#ifndef COM_LIBRARY
#define COM_LIBRARY
#ifndef LIBRARY_H
#define LIBRARY_H
#define DOS_SIGNATURE 0x5A4D // MZ
#define NT_SIGNATURE 0x00004550 // PE00
#define NUMBEROF_DIRECTORY_ENTRIES 16
#define NUMBER_OF_DIRECTORY_ENTRIES 16
#define MAX_LIBRARY_EXPORTS 4096
typedef struct
{
@ -104,7 +105,7 @@ typedef struct
dword LoaderFlags;
dword NumberOfRvaAndSizes;
DATA_DIRECTORY DataDirectory[NUMBEROF_DIRECTORY_ENTRIES];
DATA_DIRECTORY DataDirectory[NUMBER_OF_DIRECTORY_ENTRIES];
} OPTIONAL_HEADER;
typedef struct
@ -122,10 +123,27 @@ typedef struct
dword AddressOfNameOrdinals; // RVA from base of image
} EXPORT_DIRECTORY;
void *Com_LoadLibrary( const char *name );
FARPROC Com_GetProcAddress( void *hInstance, const char *name );
void Com_FreeLibrary( void *hInstance );
void Com_BuildPathExt( const char *dllname, char *fullpath, size_t size );
#define Com_BuildPath( a, b ) Com_BuildPathExt( a, b, sizeof( b ))
typedef struct dll_user_s
{
void *hInstance; // to avoid possible hacks
bool custom_loader; // a bit who indicated loader type
char dllName[32]; // for debug messages
string fullPath, shortPath; // actual dll paths
#endif//COM_LIBRARY
// ordinals stuff
word *ordinals;
dword *funcs;
char *names[MAX_LIBRARY_EXPORTS]; // max 4096 exports supported
int num_ordinals; // actual exports count
dword funcBase; // base offset
} dll_user_t;
dll_user_t *FS_FindLibrary( const char *dllname, bool directpath );
void *Com_LoadLibrary( const char *dllname, int build_ordinals_table );
void *Com_LoadLibraryExt( const char *dllname, int build_ordinals_table, bool directpath );
void *Com_GetProcAddress( void *hInstance, const char *name );
const char *Com_NameForFunction( void *hInstance, dword function );
dword Com_FunctionFromName( void *hInstance, const char *pName );
void Com_FreeLibrary( void *hInstance );
#endif//LIBRARY_H

View File

@ -4,6 +4,7 @@
//=======================================================================
#include "launch.h"
#include "library.h"
#include "baserc_api.h"
#include "engine_api.h"
#include "mathlib.h"
@ -120,6 +121,12 @@ void Sys_GetStdAPI( void )
com.Com_ThreadUnlock = Sys_ThreadUnlock; // unlock numthreads
com.Com_NumThreads = Sys_GetNumThreads; // returns count of active threads
com.LoadLibrary = Com_LoadLibrary;
com.GetProcAddress = Com_GetProcAddress;
com.NameForFunction = Com_NameForFunction;
com.FunctionFromName = Com_FunctionFromName;
com.FreeLibrary = Com_FreeLibrary;
com.Com_OpenScript = PS_LoadScript; // loading script into buffer
com.Com_CloseScript = PS_FreeScript; // release current script
com.Com_ResetScript = PS_ResetScript; // jump to start of scriptfile
@ -174,9 +181,10 @@ void Sys_GetStdAPI( void )
com.fgetc = FS_Getc; // same as fgetc
com.fgets = FS_Gets; // like a fgets, but can return EOF
com.fseek = FS_Seek; // fseek, can seek in packfiles too
com.fremove = FS_Remove; // like remove
com.ftell = FS_Tell; // like a ftell
com.feof = FS_Eof; // like a feof
com.fremove = FS_Delete; // like remove
com.frename = FS_Rename; // like rename
// virtual filesystem
com.vfcreate = VFS_Create; // create virtual stream

View File

@ -510,6 +510,13 @@ typedef struct stdilib_api_s
void (*Com_ThreadUnlock)( void ); // unlock numthreads
int (*Com_NumThreads)( void ); // returns count of active threads
// user dlls interface
void *(*LoadLibrary)( const char *dllname, int build_ordinals_table );
void *(*GetProcAddress)( void *hInstance, const char *name );
const char *(*NameForFunction)( void *hInstance, dword function );
dword (*FunctionFromName)( void *hInstance, const char *pName );
void (*FreeLibrary)( void *hInstance );
// script machine base functions
script_t *(*Com_OpenScript)( const char *filename, const char *buf, size_t size );
void (*Com_CloseScript)( script_t *script ); // release current script
@ -560,15 +567,16 @@ typedef struct stdilib_api_s
file_t *(*fopen)(const char* path, const char* mode); // same as fopen
int (*fclose)(file_t* file); // same as fclose
long (*fwrite)(file_t* file, const void* data, size_t datasize); // same as fwrite
long (*fread)(file_t* file, void* buffer, size_t buffersize); // same as fread, can see trough pakfile
long (*fread)(file_t* file, void* buffer, size_t buffersize); // same as fread, can see through pakfile
int (*fprint)(file_t* file, const char *msg); // printed message into file
int (*fprintf)(file_t* file, const char* format, ...); // same as fprintf
int (*fgetc)( file_t* file ); // same as fgetc
int (*fgets)(file_t* file, byte *string, size_t bufsize ); // like a fgets, but can return EOF
int (*fseek)(file_t* file, fs_offset_t offset, int whence); // fseek, can seek in packfiles too
bool (*fremove)( const char *path ); // remove sepcified file
long (*ftell)( file_t *file ); // like a ftell
bool (*feof)( file_t *file ); // like a feof
bool (*fremove)( const char *path ); // remove specified file
bool (*frename)( const char *oldname, const char *newname ); // rename specified file
// virtual filesystem
vfile_t *(*vfcreate)( const byte *buffer, size_t buffsize ); // create virtual stream
@ -780,6 +788,7 @@ filesystem manager
#define FS_Getc (*com.fgetc)
#define FS_Gets (*com.fgets)
#define FS_Delete (*com.fremove)
#define FS_Rename (*com.frename)
#define FS_Gamedir() com.SysInfo->GameInfo->gamedir
#define FS_Title() com.SysInfo->GameInfo->title
#define g_Instance() com.SysInfo->instance
@ -945,6 +954,12 @@ misc utils
#define StringTable_Load com.st_load
#define StringTable_Save com.st_save
#define FS_LoadLibrary com.LoadLibrary
#define FS_GetProcAddress com.GetProcAddress
#define FS_NameForFunction com.NameForFunction
#define FS_FunctionFromName com.FunctionFromName
#define FS_FreeLibrary com.FreeLibrary
/*
===========================================
stdlib function names that not across with windows stdlib

View File

@ -31,7 +31,9 @@ Xash 0.71 Beta 05.05.10
7. reborn Xash 0.4 Source Code
8. completely finalize Save\restore & Changelevel OK
9. creates an imagelib user profile OK
10. test saves and changelevel, fix errors
11. implement FS_Rename
12. rewrite FS_Delete
13. rewrite FS_FileTime
10. test saves and changelevel, fix errors OK
11. implement FS_Rename OK
12. rewrite FS_Delete OK
13. rewrite FS_FileTime OK
14. rewrite user dlls loading OK
15. disable plaque between levels

View File

@ -784,11 +784,11 @@ int BSPMain( int argc, char **argv )
SetDefaultSampleSize( sampleSize );
/* delete portal, line and surface files */
com.sprintf( path, "%s/maps/%s.prt", GI->gamedir, source );
com.sprintf( path, "maps/%s.prt", source );
FS_Delete( path );
com.sprintf( path, "%s/maps/%s.lin", GI->gamedir, source );
com.sprintf( path, "maps/%s.lin", source );
FS_Delete( path );
com.sprintf( path, "%s/maps/%s.log", GI->gamedir, source );
com.sprintf( path, "maps/%s.log", source );
FS_Delete( path );
com.snprintf( name, sizeof( name ), "maps/%s.map", gs_filename );
enable_log = true;