28 Mar 2010
This commit is contained in:
parent
2d8beb699c
commit
dfa0517d2b
|
@ -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 ));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 ));
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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, ¤t_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
|
||||
}
|
|
@ -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];
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 );
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 ));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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, §ion_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" );
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 ));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 ));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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"
|
||||
|
||||
|
|
106
launch/launch.h
106
launch/launch.h
|
@ -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
|
||||
|
|
|
@ -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, §ion_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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
10
todo.log
10
todo.log
|
@ -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
|
|
@ -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;
|
||||
|
|
Reference in New Issue