/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2009 Miranda ICQ/IM project, 
all portions of this codebase are copyrighted to the people 
listed in contributors.txt.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "commonheaders.h"

#define BLOCK_ALLOCED 0xABBABABA
#define BLOCK_FREED   0xDEADBEEF

static int CheckBlock( void* blk )
{
	int result = FALSE;
	char* p = ( char* )blk - sizeof(DWORD)*2;
	DWORD size, *b, *e;

	__try
	{
		size = *( DWORD* )p;
		b = ( DWORD* )&p[ sizeof( DWORD ) ];
		e = ( DWORD* )&p[ sizeof( DWORD )*2 + size ];

		if ( *b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED )
		{
			if ( *b == BLOCK_FREED && *e == BLOCK_FREED )
				OutputDebugStringA( "memory block is already deleted\n" );
			else
				OutputDebugStringA( "memory block is corrupted\n" );
			#if defined( _DEBUG )
				DebugBreak();
			#endif
		}
 		else result = TRUE;
	}
	__except( EXCEPTION_EXECUTE_HANDLER )
	{
		OutputDebugStringA( "access violation during checking memory block\n" );
		#if defined( _DEBUG )
			DebugBreak();
		#endif
	}

	return result;
}

/******************************************************************************/

void* mir_alloc( size_t size )
{
	if ( size == 0 )
		return NULL;
	{
		char* p = (char*)malloc( size + sizeof(DWORD)*3 );
		if ( p == NULL ) {
			OutputDebugStringA( "memory overflow\n" );
			#if defined( _DEBUG )
				DebugBreak();
			#endif
			return NULL;
		}

		*( DWORD* )p = ( DWORD )size;
		*( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
		*( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
		return p + sizeof( DWORD )*2;
}	}

/******************************************************************************/

void* mir_calloc( size_t size )
{
	void* p = mir_alloc( size );
	if ( p != NULL )
		memset( p, 0, size );
	return p;
}

/******************************************************************************/

void* mir_realloc( void* ptr, size_t size )
{
	char* p;

	if ( ptr != NULL ) {
		if ( !CheckBlock( ptr ))
			return NULL;
		p = ( char* )ptr - sizeof(DWORD)*2;
	}
	else p = NULL;

	p = ( char* )realloc( p, size + sizeof(DWORD)*3 );
	if ( p == NULL ) {
		OutputDebugStringA( "memory overflow\n" );
		#if defined( _DEBUG )
			DebugBreak();
		#endif
		return NULL;
	}

	*( DWORD* )p = ( DWORD )size;
	*( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
	*( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
	return p + sizeof( DWORD )*2;
}

/******************************************************************************/

void mir_free( void* ptr )
{
	char* p;
	DWORD size;

	if ( ptr == NULL )
		return;
	if ( !CheckBlock( ptr ))
		return;

	p = ( char* )ptr - sizeof(DWORD)*2;
	size = *( DWORD* )p;
	*( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_FREED;
	*( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_FREED;
	free( p );
}

/******************************************************************************/

char* mir_strdup( const char* str )
{
	if ( str != NULL ) {
		char* p = ( char* )mir_alloc( strlen( str )+1 );
		if ( p )
			strcpy( p, str );
		return p;
	}
	return NULL;
}

/******************************************************************************/

char* mir_strndup( const char* str, size_t len )
{
	if ( str != NULL && len != 0 ) {
		char* p = ( char* )mir_alloc( len + 1 );
		if ( !p ) {
			memcpy( p, str, len );
			p[ len ] = 0;
		}
		return p;
	}
	return NULL;
}

/******************************************************************************/

WCHAR* mir_wstrdup( const WCHAR* str )
{
	if ( str != NULL ) {
		WCHAR* p = ( WCHAR* )mir_alloc( sizeof( WCHAR )*( wcslen( str )+1 ));
		if ( p )
			wcscpy( p, str );
		return p;
	}
	return NULL;
}

/******************************************************************************/

int mir_snprintf(char *buffer, size_t count, const char* fmt, ...)
{
	va_list va;
	int len;

	va_start(va, fmt);
	len = _vsnprintf(buffer, count-1, fmt, va);
	va_end(va);
	buffer[count-1] = 0;
	return len;
}

/******************************************************************************/

int mir_sntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, ...)
{
	va_list va;
	int len;

	va_start(va, fmt);
	len = _vsntprintf(buffer, count-1, fmt, va);
	va_end(va);
	buffer[count-1] = 0;
	return len;
}

/******************************************************************************/

int mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va)
{
	int len;

	len = _vsnprintf(buffer, count-1, fmt, va);
	buffer[count-1] = 0;
	return len;
}

/******************************************************************************/

int mir_vsntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, va_list va)
{
	int len;

	len = _vsntprintf(buffer, count-1, fmt, va);
	buffer[count-1] = 0;
	return len;
}

/******************************************************************************/

wchar_t* mir_a2u_cp( const char* src, int codepage )
{
	if ( src == NULL )
		return NULL;

	int cbLen = MultiByteToWideChar( codepage, 0, src, -1, NULL, 0 );
	wchar_t* result = ( wchar_t* )mir_alloc( sizeof( wchar_t )*(cbLen+1));
	if ( result == NULL )
		return NULL;

	MultiByteToWideChar( codepage, 0, src, -1, result, cbLen );
	result[ cbLen ] = 0;
	return result;
}

/******************************************************************************/

wchar_t* mir_a2u( const char* src )
{
	return mir_a2u_cp( src, LangPackGetDefaultCodePage());
}

/******************************************************************************/

char* mir_u2a_cp( const wchar_t* src, int codepage )
{
	if ( src == NULL )
		return NULL;

	int cbLen = WideCharToMultiByte( codepage, 0, src, -1, NULL, 0, NULL, NULL );
	char* result = ( char* )mir_alloc( cbLen+1 );
	if ( result == NULL )
		return NULL;

	WideCharToMultiByte( codepage, 0, src, -1, result, cbLen, NULL, NULL );
	result[ cbLen ] = 0;
	return result;
}

/******************************************************************************/

char* mir_u2a( const wchar_t* src )
{
	return mir_u2a_cp( src, LangPackGetDefaultCodePage());
}
