// GTA:ViceCity debug logger
// This file written by Stanislav "listener" Golovin and donated to the public domain.

#include <windows.h>
#include <stdio.h>

//=============================================================================
// 
static FILE * logfile = NULL;
char linebuf[1024];

CRITICAL_SECTION loglock;

void debug (char * message, ...) {
	if (!logfile)
		return;
	EnterCriticalSection (&loglock);


	SYSTEMTIME	t;
	GetLocalTime (&t);	
	fprintf (logfile, "%02d/%02d/%04d %02d:%02d:%02d.%03d ", t.wDay, t.wMonth, t.wYear, t.wHour, t.wMinute, t.wSecond, t.wMilliseconds);
	va_list	arg;	
	va_start (arg, message);
	vsprintf (linebuf, message, arg);
	char * p = strrchr (linebuf, '\n');
	if (p)
		*p = '\0';
	fprintf (logfile, "%s\r\n", linebuf);
	//fflush (logfile);

	va_end (arg); 

	LeaveCriticalSection (&loglock);
}

void logMessage (char * str1, char* str2) {
	if (!str1) str1 = "";
	if (!str2) str2 = "";
	debug("%s: %s\n", str1, str2);
}
int dsprintf (char * buf, char * message, ...) {	
	if (!buf) return 0;
	if (!message) message = "";
	va_list	arg;	
	va_start (arg, message);
	int r = vsprintf (buf, message, arg);
	va_end (arg);
	debug ("SPRINTF: %s", buf);
	return r;
}


void injectFunction (DWORD address, DWORD function) {
	BYTE * patch = (BYTE *)address;
	*patch = 0xE9;	// JMP
	*(DWORD *)(patch+1) = (function-(address+5));	
}



BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 ) {
	switch (ul_reason_for_call) {
	case DLL_PROCESS_ATTACH:
		logfile = fopen ("sa_log.log", "ab");
		if (!logfile)
			return false;
		InitializeCriticalSection (&loglock);
		debug ("Log started\n");

		DWORD oldProtect;
		if (!VirtualProtect ((LPVOID)0x401000, 0x456000, PAGE_EXECUTE_READWRITE, &oldProtect)) {
			debug ("Virtual protect failed, exiting...\n");
			return false;
		}

		injectFunction (0x821982, (DWORD)debug); // printf
		injectFunction (0x821BB5, (DWORD)dsprintf); // sprintf
		injectFunction (0x590240, (DWORD)logMessage); // logMessage
		

		if (!logfile)	// floating point hack - do not remove!
			debug ("test: %f %f %f\n", 1.2f, 2.3f, 3.4f);
		break;
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:		
		if (logfile) {
			debug ("Log closed\n");
			fclose (logfile);			
			logfile = NULL;
			DeleteCriticalSection (&loglock);
		}		
		break;
	}
    return TRUE;
}

